/ckeditor4/src/ckeditor-dev/tests/plugins/widget/_helpers/tools.js
JavaScript | 404 lines | 355 code | 29 blank | 20 comment | 12 complexity | ec83d8d86e43c66106bf37b25f0f72e1 MD5 | raw file
- /* exported widgetTestsTools */
- var widgetTestsTools = ( function() {
- 'use strict';
- //
- // @param config
- // @param config.name
- // @param config.widgetName
- // @param [config.editorConfig]
- // @param [config.extraPlugins]
- // @param [config.extraAllowedContent]
- // @param [config.onWidgetDefinition]
- //
- // @param config.initialInstancesNumber
- // @param [config.checkData]
- // @param [config.assertWidgets]
- //
- // @param config.newData
- // @param config.newWidgetPattern
- // @param {Boolean/Function} [config.ignoreStyle=false]
- function addTests( tcs, config ) {
- var editor,
- editorBot,
- tcName = config.name,
- checkData = config.checkData !== false,
- initialData,
- editorConfig = {
- extraPlugins: config.extraPlugins + ',sourcearea,undo,clipboard,toolbar',
- removePlugins: config.removePlugins,
- extraAllowedContent: config.extraAllowedContent,
- on: {
- loaded: function( evt ) {
- editor = evt.editor;
- initialData = fixHtml( editor.getData(), config.ignoreStyle, editor );
- editor.dataProcessor.writer.sortAttributes = true;
- },
- widgetDefinition: function( evt ) {
- if ( evt.data.name == config.widgetName && config.onWidgetDefinition )
- config.onWidgetDefinition( evt.data );
- }
- }
- };
- if ( config.editorConfig )
- CKEDITOR.tools.extend( editorConfig, config.editorConfig, true );
- tcs[ 'test ' + tcName + ' - init' ] = function() {
- bender.editorBot.create( {
- name: 'editor_' + tcName,
- creator: config.creator,
- config: editorConfig
- }, function( bot ) {
- editorBot = bot;
- editor.focus();
- assert.isNotUndefined( editor.widgets.registered[ config.widgetName ], 'widget definition is registered' );
- assertWidgets( 'on init' );
- } );
- };
- if ( config.creator != 'inline' ) {
- tcs[ 'test ' + tcName + ' - switch modes' ] = function() {
- var sourceModeData;
- // Wait & ensure async.
- wait( function() {
- editor.setMode( 'source', function() {
- sourceModeData = fixHtml( editor.getData(), config.ignoreStyle, editor );
- editor.setMode( 'wysiwyg', function() {
- resume( function() {
- checkData && assert.areSame( initialData, sourceModeData, 'source mode data' );
- assertWidgets( 'after switching modes' );
- } );
- } );
- } );
- } );
- };
- }
- tcs[ 'test ' + tcName + ' - paste' ] = function() {
- var html = editor.editable().getHtml();
- editorBot.setData( '', function() {
- editor.once( 'afterPaste', function() {
- resume( function() {
- assertWidgets( 'after paste' );
- } );
- } );
- wait( function() {
- editor.execCommand( 'paste', html );
- } );
- } );
- };
- tcs[ 'test ' + tcName + ' - create' ] = function() {
- editorBot.setData( '', function() {
- var widgetDef = editor.widgets.registered[ config.widgetName ];
- editor.once( 'dialogShow', function( evt ) {
- var dialog = evt.data;
- setTimeout( function() {
- for ( var i = 0; i < config.newData.length; ++i )
- dialog.setValueOf.apply( dialog, config.newData[ i ] );
- dialog.getButton( 'ok' ).click();
- }, 50 );
- } );
- editor.once( 'dialogHide', function() {
- resume( function() {
- var instances = bender.tools.objToArray( editor.widgets.instances );
- assert.areSame( 1, instances.length, 'one instance was created' );
- assert.isMatching( config.newWidgetPattern, editor.getData(), 'data' );
- } );
- } );
- // We lose focus somewhere in the previous tests. Regain it, so command's state is refreshed.
- editor.focus();
- editor.execCommand( widgetDef.name );
- wait();
- } );
- };
- function assertWidgets( msg ) {
- var instances = bender.tools.objToArray( editor.widgets.instances );
- assert.areSame( config.initialInstancesNumber, instances.length, 'instances number ' + msg );
- checkData && assert.areSame( initialData, fixHtml( editor.getData(), config.ignoreStyle, editor ), 'data ' + msg );
- var editable = editor.editable();
- for ( var i = 0; i < instances.length; ++i )
- assert.isTrue( editable.contains( instances[ i ].wrapper ), 'editable contains wrapper ' + msg );
- config.assertWidgets && config.assertWidgets( editor, msg );
- }
- }
- function classes2Array( classesObj ) {
- return CKEDITOR.tools.object.keys( classesObj ).sort();
- }
- function fixHtml( html, ignoreStyle, editor ) {
- // Because IE modify style attribute we should fix it or totally ignore style attribute.
- html = html.replace( /style="([^"]*)"/g, function( styleStr ) {
- ignoreStyle = typeof ignoreStyle === 'function' ? ignoreStyle( editor ) : ignoreStyle;
- // If there are too many problems with styles just ignore them.
- if ( ignoreStyle ) {
- return '';
- }
- // If it is only the matter of spacers and semicolons fix attributes.
- var style = styleStr.substr( 7, styleStr.length - 8 );
- return 'style="' + CKEDITOR.tools.htmlEncodeAttr( CKEDITOR.tools.writeCssText( CKEDITOR.tools.parseCssText( style ) ) ) + '"';
- } );
- // And some additional cleanup.
- html = bender.tools.compatHtml( html, true, true, true, true );
- return html;
- }
- function data2Attr( data ) {
- return encodeURIComponent( JSON.stringify( data ) );
- }
- function getAttrData( widget ) {
- return JSON.parse( decodeURIComponent( widget.element.data( 'cke-widget-data' ) ) );
- }
- // @param {Boolean} [byElement] If true, the passed id has to be widget element's id.
- // Important for nested widgets, so parent widget is not mistakenly found.
- function getWidgetById( editor, id, byElement ) {
- var widget = editor.widgets.getByElement( editor.document.getById( id ) );
- if ( widget && byElement )
- return widget.element.$.id == id ? widget : null;
- return widget;
- }
- // Retrives widget by its offset among parsed widgets.
- //
- // @param {CKEDITOR.editor} editor
- // @param {Number} offset 0-based widget offset.
- // @returns {CKEDITOR.plugins.widget/null} Returns null if widget was not found.
- function getWidgetByDOMOffset( editor, offset ) {
- var wrapper = editor.editable().find( '.cke_widget_wrapper' ).getItem( offset ),
- ret = null;
- if ( wrapper )
- ret = editor.widgets.getByElement( wrapper );
- return ret;
- }
- // Sets editor content to given element and tests if its downcasted to expected widget.
- //
- // @param {bender.editorBot} editorBot
- // @param {String} id Id of element in document which.
- // @param {Number} [expectedInstancesCount=1] Expected widget instances count.
- // @param {String} [expectedWidgetName] Expected widget definiton name. In this case
- // should have same definition name.
- function assertDowncast( editorBot, id, expectedInstancesCount, expectedWidgetName ) {
- var data = CKEDITOR.document.getById( id ).getHtml();
- if ( typeof expectedInstancesCount == 'undefined' )
- expectedInstancesCount = 1;
- editorBot.setData( data, function() {
- var instancesArray = bender.tools.objToArray( editorBot.editor.widgets.instances );
- assert.areEqual( expectedInstancesCount, instancesArray.length, 'Invalid count of created widget instances.' );
- assert.areEqual( fixHtml( data ), fixHtml( editorBot.getData() ), 'Editor html after performing downcast is not matching.' );
- if ( expectedWidgetName ) {
- for ( var i = instancesArray.length - 1; i >= 0; i-- )
- assert.areEqual( expectedWidgetName, instancesArray[ i ].name, 'Widget at index ' + i + ' has widget invalid definition name.' );
- }
- } );
- }
- // Asserts that dialog appears after executing given command, and that dialog
- // fields contains given values.
- //
- // Uses global functions: wait, resume.
- //
- // For sample use see: dt/plugins/image2/editing.html
- //
- // @param {bender.editorBot} editorBot
- // @param {String} commandName Name of command which should create dialog.
- // @param {String} editorHtml Initial HTML code for editor, should contain code transformable into the widget.
- // @param {Number/String} focusedWidgetIndex If String: id of widget which should be focused
- // if Number: index of widget which should be focused (0-based), otherwise: no widget will be focused (default)
- // @param {Object} expectedValues Expected dialog values object. If null - checking will be skipped.
- // @param {String} htmlWithSelectionSource If passed it will use htmlWithSelection() method and
- // override content set with editorHtml variable.
- // @param {Function} onResume Callback called after checking dialog values, passes
- // dialog object as its first argument.
- function assertWidgetDialog( editorBot, commandName, editorHtml, focusedWidgetIndex, expectedValues, htmlWithSelectionSource, onResume ) {
- var editor = editorBot.editor,
- dialogCheckedTab = 'info'; // Tab name in dialog.
- // Registering dialogShow listener, which will invoke resume().
- editor.once( 'dialogShow', function( evt ) {
- var dialog = evt.data;
- resume( function() {
- // Lets check dialog contents.
- try {
- expectedValues = expectedValues || {};
- for ( var i in expectedValues )
- assert.areSame( expectedValues[ i ], dialog.getValueOf( dialogCheckedTab, i ), 'Dialog field "' + i + '" in tab "' + dialogCheckedTab + '" has invalid value.' );
- } catch ( e ) {
- // Propagate error.
- dialog.hide();
- throw e;
- }
- onResume && onResume( dialog );
- dialog.hide();
- } );
- } );
- editorBot.setData( editorHtml, function() {
- var widget = null;
- // If html with seleciton was requested - override.
- if ( typeof htmlWithSelectionSource == 'string' )
- editorBot.htmlWithSelection( htmlWithSelectionSource );
- if ( typeof focusedWidgetIndex == 'number' ) {
- // If index of widget to be focused is number.
- widget = getWidgetByDOMOffset( editor, focusedWidgetIndex );
- assert.isNotNull( widget, 'Could not find widget with index ' + focusedWidgetIndex );
- } else if ( typeof focusedWidgetIndex == 'string' ) {
- // In this case id was given.
- widget = getWidgetById( editor, focusedWidgetIndex );
- assert.isNotNull( widget, 'Could not find widget with id ' + focusedWidgetIndex );
- }
- if ( widget )
- widget.focus();
- assert.isTrue( true );
- editor.execCommand( commandName );
- wait();
- } );
- }
- function assertWidget( config ) {
- var editor = config.bot.editor,
- // Widget instances as array.
- instancesArray = null;
- config.bot.setData( config.html, function() {
- var widget = null,
- pickWidget = function() {
- var ret = null;
- if ( config.widgetId )
- ret = widgetTestsTools.getWidgetById( editor, config.widgetId );
- else if ( typeof config.widgetOffset !== 'undefined' )
- ret = widgetTestsTools.getWidgetByDOMOffset( editor, config.widgetOffset );
- return ret;
- };
- instancesArray = bender.tools.objToArray( editor.widgets.instances );
- // If expected widgets count was specified, check if it's the same.
- typeof config.count !== 'undefined' && assert.areSame( Number( config.count ), instancesArray.length, 'Invalid count of widgets found.' );
- // There is a case that config.count will be 0, so we dont want to have any widgets found.
- if ( typeof config.count !== 'number' || config.count > 0 ) {
- widget = pickWidget();
- // Assert widget once it's created.
- config.assertCreated && config.assertCreated( widget );
- // Assert widget name.
- assert.areSame( config.nameCreated, widget.name, 'Initial widget name must match.' );
- // Set new widget data. This may destroy the widget.
- config.data && widget.setData( config.data );
- // Retrieve the widget once again as it may have been destroyed.
- widget = pickWidget();
- // Assert widget as new data is set.
- config.assertNewData && config.assertNewData( widget );
- // Assert widget name as new data is set.
- config.nameNewData && assert.areSame( config.nameNewData, widget.name, 'Widget name must match after data is set.' );
- // Finally destroy the widget.
- editor.widgets.destroy( widget );
- }
- config.callback && config.callback( config );
- } );
- }
- return {
- addTests: addTests,
- data2Attribute: data2Attr,
- getAttributeData: getAttrData,
- fixHtml: fixHtml,
- getWidgetById: getWidgetById,
- getWidgetByDOMOffset: getWidgetByDOMOffset,
- classes2Array: classes2Array,
- assertDowncast: assertDowncast,
- assertWidgetDialog: assertWidgetDialog,
- assertWidget: assertWidget,
- widgetInitedWrapperAttributes:
- 'aria-label="[a-z]+ widget" ' +
- 'class="cke_widget_wrapper cke_widget_(?:inline|block) cke_widget_test(?:_upcasted_pasting|inline|block)" ' +
- 'contenteditable="false" ' +
- '(?:data-cke-display-name="[a-z0-9]+" )?' +
- '(?:data-cke-expando="[0-9]+" )?' +
- 'data-cke-filter="off" ' +
- 'data-cke-widget-id="[0-9]+" ' +
- 'data-cke-widget-wrapper="1" ' +
- 'role="region" ' +
- 'tabindex="-1"',
- widgetWrapperAttributes:
- 'class="cke_widget_wrapper cke_widget_new cke_widget_(?:inline|block) cke_widget_test(?:1|2|inline|block)?" ' +
- 'contenteditable="false" ' +
- '(?:data-cke-display-name="[a-z0-9]+" )?' +
- '(?:data-cke-expando="[0-9]+" )?' +
- 'data-cke-filter="off" ' +
- 'data-cke-widget-wrapper="1" ' +
- 'tabindex="-1"',
- widgetDragHanlder:
- '<span class="cke_reset cke_widget_drag_handler_container" style="[^"]+">' +
- '<img class="cke_reset cke_widget_drag_handler" ' +
- '(?:data-cke-expando="[0-9]+" )?' +
- 'data-cke-widget-drag-handler="1" ' +
- '(?:draggable="true" )?' +
- 'height="\\d+" ' +
- 'role="presentation" ' +
- 'src="[^"]+" ' +
- 'title="[^"]+" ' +
- 'width="\\d+" ' +
- '/>' +
- '</span>'
- };
- } )();