Saturday, July 27, 2013

jQuery Window After Resize Event

afterResize.js

If you have ever used jQuery's .resize() method to detect a window resize you may be aware that most browsers don't wait for the resize event to finish before it triggers a callback. Instead the event and it's callback is fired rapidly until the resize is complete.
This very simple jQuery plugin is designed to emulate an 'after resize' event. It works by adding the callback to a queue to be executed after a duration. If the event is triggered again before the end of this duration, it is restarted and the callback will not execute until the duration can finish.

Example

$(document).ready( function() {
    $(window).afterResize( function() {
        alert('Resize event has finished');
    }, true, 100 );
});
Download after resize jquery plugin
Original content area on github

Thursday, July 25, 2013

CKEditor 4.2 jQuery installation

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>

<textarea id="text_area_id">Hello</textarea>
<script type="text/javascript">
    for (var i in CKEDITOR.instances) {
        if(CKEDITOR.instances[i]) {
            CKEDITOR.remove(CKEDITOR.instances[i]); /* REMOVE ALL CKEDITOR INSTANCE IF NEED */
        }
    }
    CKEDITOR.replace( 'text_area_id',
        {
            pasteFromWordRemoveFontStyles : false,
            fullPage : true,
            removePlugins : 'elementspath',
            height : 300,
            toolbar :
                [
                    { name: 'document',    items : [ 'Source','-','Save','NewPage','DocProps','Preview','Print','-','Templates' ] },
                    { name: 'clipboard',   items : [ 'Cut','Copy','Paste','PasteText','PasteFromWord','-','Undo','Redo' ] },
                    { name: 'editing',     items : [ 'Find','Replace','-','SelectAll','-','SpellChecker', 'Scayt' ] },
                    { name: 'forms',       items : [ 'Form', 'Checkbox', 'Radio', 'TextField', 'Textarea', 'Select', 'Button', 'ImageButton', 'HiddenField' ] },
                    '/',
                    { name: 'basicstyles', items : [ 'Bold','Italic','Underline','Strike','Subscript','Superscript','-','RemoveFormat' ] },
                    { name: 'paragraph',   items : [ 'NumberedList','BulletedList','-','Outdent','Indent','-','Blockquote','CreateDiv','-','JustifyLeft','JustifyCenter','JustifyRight','JustifyBlock','-','BidiLtr','BidiRtl' ] },
                    { name: 'links',       items : [ 'Link','Unlink','Anchor' ] },
                    { name: 'insert',      items : [ 'Image','Flash','Table','HorizontalRule','Smiley','SpecialChar','PageBreak' ] },
                    '/',
                    { name: 'styles',      items : [ 'Styles','Format','Font','FontSize' ] },
                    { name: 'colors',      items : [ 'TextColor','BGColor' ] },
                    { name: 'tools',       items : [ 'Maximize', 'ShowBlocks','-','About' ] }
                ]
        });
</script>

CKEditor basic table operations plugin

Download full plugin.

Make a entry in config.js file like this:
config.extraPlugins = "tableoperations";

You must have 'table' plugin included with your CKEDITOR.

Add name 'tableoperations' when you initialize your ckeditor.
CKEDITOR.replace('text_area_id', {
 toolbar: [
  {
   name: 'tableoperations',
   items : [ '-', 'Table', 'TableInsertRowBefore',  'TableInsertRowAfter', 'TableRowDelete', '-',
                            'TableInsertColumnBefore', 'TableInsertColumnAfter', 'TableColumnDelete', '-', 'TableCellMerge',
                            'TableCellSplitVertical', 'TableCellSplitHorizontal', 'TableDeleteTable' ]

  }
 ]
});

plugin.js file:
CKEDITOR.plugins.add('tableoperations', {
    requires : [ 'table' ],
    init : function( editor ){
        editor.addCommand('tblOpInsertRowBefore', {
            exec : function( editor ){
                if(!editor.getSelection().getStartElement().getAscendant( 'table', 1 ))
                    return;
                editor.execCommand('rowInsertBefore',editor);
            }
        });
      
        editor.addCommand('tblOpInsertRowAfter', {
            exec : function( editor ){
                if(!editor.getSelection().getStartElement().getAscendant( 'table', 1 ))
                    return;
                editor.execCommand('rowInsertAfter',editor);
            }
        });
      
        editor.addCommand('tblOpRowDelete', {
            exec : function( editor ){
                if(!editor.getSelection().getStartElement().getAscendant( 'table', 1 ))
                    return;
                editor.execCommand('rowDelete',editor);
            }
        });
      
        editor.addCommand('tblOpInsertColumnBefore', {
            exec : function( editor ){
                if(!editor.getSelection().getStartElement().getAscendant( 'table', 1 ))
                    return;
                editor.execCommand('columnInsertBefore',editor);
            }
        });
      
        editor.addCommand('tblOpInsertColumnAfter', {
            exec : function( editor ){
                if(!editor.getSelection().getStartElement().getAscendant( 'table', 1 ))
                    return;
                editor.execCommand('columnInsertAfter',editor);
            }
        });
      
        editor.addCommand('tblOpColumnDelete', {
            exec : function( editor ){
                if(!editor.getSelection().getStartElement().getAscendant( 'table', 1 ))
                    return;
                editor.execCommand('columnDelete',editor);
            }
        });
      
        editor.addCommand('tblOpCellMerge', {
            exec : function( editor ){
                if(!editor.getSelection().getStartElement().getAscendant( 'table', 1 ))
                    return;
                try{
                    editor.execCommand('cellMerge',editor);
                }
                catch(err){
                    console.log(err.message);
                }
            }
        });
      
        editor.addCommand('tblOpCellSplitVertical', {
            exec : function( editor ){
                if(!editor.getSelection().getStartElement().getAscendant( 'table', 1 ))
                    return;
                editor.execCommand('cellVerticalSplit',editor);
            }
        });
      
        editor.addCommand('tblOpCellSplitHorizontal', {
            exec : function( editor ){
                if(!editor.getSelection().getStartElement().getAscendant( 'table', 1 ))
                    return;
                editor.execCommand('cellHorizontalSplit',editor);
            }
        });
      
        editor.addCommand('tblOpDeleteTable', {
            exec : function( editor ){
                if(!editor.getSelection().getStartElement().getAscendant( 'table', 1 ))
                    return;
                editor.execCommand('tableDelete',editor);
            }
        });
      
        editor.ui.addButton('TableInsertRowBefore', {
            label : 'Insert Row Before',
            command : 'tblOpInsertRowBefore',
            icon : this.path + '../../skins/' + editor.skinName + '/icons.png',
            iconOffset : 69
        });
      
        editor.ui.addButton('TableInsertRowAfter', {
            label : 'Insert Row After',
            command : 'tblOpInsertRowAfter',
            icon : this.path + '../../skins/' + editor.skinName + '/icons.png',
            iconOffset : 61
        });
      
        editor.ui.addButton('TableRowDelete', {
            label : 'Delete Row',
            command : 'tblOpRowDelete',
            icon : this.path + '../../skins/' + editor.skinName + '/icons.png',
            iconOffset : 62
        });
      
        editor.ui.addButton('TableInsertColumnBefore', {
            label : 'Insert Column Before',
            command : 'tblOpInsertColumnBefore',
            icon : this.path + '../../skins/' + editor.skinName + '/icons.png',
            iconOffset : 70
        });
      
        editor.ui.addButton('TableInsertColumnAfter', {
            label : 'Insert Column After',
            command : 'tblOpInsertColumnAfter',
            icon : this.path + '../../skins/' + editor.skinName + '/icons.png',
            iconOffset : 63
        });
      
        editor.ui.addButton('TableColumnDelete', {
            label : 'Delete Column',
            command : 'tblOpColumnDelete',
            icon : this.path + '../../skins/' + editor.skinName + '/icons.png',
            iconOffset : 64
        });
      
        editor.ui.addButton('TableCellMerge', {
            label : 'Merge Cells',
            command : 'tblOpCellMerge',
            icon : this.path + '../../skins/' + editor.skinName + '/icons.png',
            iconOffset : 59
        });
      
        editor.ui.addButton('TableCellSplitVertical', {
            label : 'Split Cell Vertically',
            command : 'tblOpCellSplitVertical',
            icon : this.path + '/split_cell_vertically.png'
        });
      
        editor.ui.addButton('TableCellSplitHorizontal', {
            label : 'Split Cell Horizontally',
            command : 'tblOpCellSplitHorizontal',
            icon : this.path + '/split_cell_horizontally.png'
        });
      
        editor.ui.addButton('TableDeleteTable', {
            label : 'Delete Table',
            command : 'tblOpDeleteTable',
            icon : this.path + '/delete_table.gif'
        });
    }
});

Creating a Simple CKEditor Plugin

To sum up, we will need the following file structure for our plugin to work:
  • ckeditor root
    • plugins
      • abbr
        • images
          • icon.png
        • plugin.js

Plugin Source Code

With the following structure ready, it is time to open the plugin.js file in a text editor and to start creating the source code of the plugin.
CKEDITOR.plugins.add( 'abbr',
{
	init: function( editor )
	{
		// Plugin logic goes here...
	}
} );
All CKEditor plugins are created by using the CKEDITOR.plugins.add function. This function should contain the plugin name ('abbr') and the plugin logic placed inside the init function that is called upon the initialization of the editor instance.

Creating an Editor Command

We want our plugin to have a dialog window, so we need to define an editor command that opens a new dialog window. To do this, we will need to use the addCommand function to register the abbrDialog command. That command opens the abbrDialog dialog that we are going to define in a moment by using the CKEDITOR.dialogCommand class.
editor.addCommand( 'abbrDialog', new CKEDITOR.dialogCommand( 'abbrDialog' ) );

Creating a Toolbar Button

The plugin dialog window is to be opened by using a toolbar button. To this end, we need to define a button that will be associated with the dialog window. The CKEditor.ui.addButton function accepts a button name ('Abbr') along with the definition of the tooltip text (label) and the button icon (icon). Note that this.path is the directory where the plugin.js file resides.
These parameters are responsible for the button presentation. To make the button actually work, we need to connect it to the plugin command name defined above by using the command parameter.
editor.ui.addButton( 'Abbr',
{
	label: 'Insert Abbreviation',
	command: 'abbrDialog',
	icon: this.path + 'images/icon.png'
} );

CKEditor Initialization

It is now time to initialize a CKEditor instance that will use the Abbreviation plugin along with its toolbar button.
To register the plugin with CKEditor, we have to add it to the extraPlugins list. We also need to enhance the toolbar definition and add the plugin button by using the toolbar parameter.
Open the page that will contain CKEditor in a text editor and insert a CKEditor instance using the following toolbar and plugin configuration.
<script type="text/javascript">
//<![CDATA[
	// Replace the <textarea id="editor1"> with a CKEditor
	// instance, using default configuration.
	CKEDITOR.replace( 'editor1',
		{
			extraPlugins : 'abbr',
			toolbar :
			[
				['Bold', 'Italic', '-', 'NumberedList', 'BulletedList', '-', 'Link', 'Unlink'],
				['About','-','Abbr']
			]
		});
//]]>
</script>
After you load the page containing the above CKEditor instance, you should be able to see the new plugin toolbar button along with its tooltip.

Plugin Dialog Window

Clicking the button should open the abbrDialog dialog window. First, however, we need to return to the Abbreviation plugin source file and define the dialog window by using the CKEDITOR.dialog.add function. To see all dialog window definition elements, refer to the CKEditor JavaScript API.
In our case we will give the dialog window a name ('abbrDialog') and use the title, minWidth, and minHeight parameters to define its title and minimum dimensions, respectively.
important note
The name selected for the dialog window is the name that appears in the addCommand function above.

Dialog Window Tabs

The dialog window should also contain some contents, so we will begin with adding two tabs along with their labels. Note that by default CKEditor also adds the standard OK and Cancel buttons.
In order to create the Abbreviation plugin dialog window along with two tabs, add the following code in the plugin.js file below the plugin toolbar button definition.
CKEDITOR.dialog.add( 'abbrDialog', function ( editor )
{
	return {
		title : 'Abbreviation Properties',
		minWidth : 400,
		minHeight : 200,
 
		contents :
		[
			{
				id : 'tab1',
				label : 'Basic Settings',
				elements :
				[
					// UI elements of the first tab	will be defined here 
				]
			},
			{
				id : 'tab2',
				label : 'Advanced Settings',
				elements :
				[
					// UI elements of the second tab will be defined here
				]
			}
		]
	};
} );
The result of this change can be seen immediately. Click the Insert Abbreviation toolbar button in order to open the newly created Abbreviation Properties dialog window containing two (empty) tabs.

Dialog Window Tabs Elements

User interface elements that can be added to a dialog window tab are defined in the elements parameter, which is an array ofCKEDITOR.dialog.uiElementDefinition objects.
The Basic Settings tab will contain two mandatory text fields (type : 'text') with the abbreviation and its explanation. Since both fields are obligatory, it is useful to add a simple validation mechanism in order to ensure that the user fills them.
The Advanced Settings tab will contain a single optional text field that allows the user to assign an id to the abbreviation element.
The code snippet presented below shows a full definition of the contents of both plugin tabs.
contents :
[
	{
		id : 'tab1',
		label : 'Basic Settings',
		elements :
		[
			{
				type : 'text',
				id : 'abbr',
				label : 'Abbreviation',
				validate : CKEDITOR.dialog.validate.notEmpty( "Abbreviation field cannot be empty" )
			},
			{
				type : 'text',
				id : 'title',
				label : 'Explanation',
				validate : CKEDITOR.dialog.validate.notEmpty( "Explanation field cannot be empty" )
			}	 
		]
	},
	{
		id : 'tab2',
		label : 'Advanced Settings',
		elements :
		[
			{
				type : 'text',
				id : 'id',
				label : 'Id'
			}
		]
	}
]
When you reload the editor instance and open the Abbreviation Properties dialog window, the Basic Settings tab will now contain two mandatory text fields.
 


Plugin Behavior

The presentation layer of the plugin is now ready, so we can define the plugin behavior to actually make it work.
The onOk method is invoked once the user accepts the changes introduced in the dialog window by clicking the OK button or pressing the Enter key on the keyboard. Since the plugin adds a new <abbr> element to the DOM tree, we can use the createElement function to create a new DOM element.
With the new DOM element created, we can now retrieve the values of the title and (optional) id fields with the getValueOf function and pass them to appropriate <abbr> element attributes by using the setAttribute function.
Finally, we will pass the text entered in the abbr text field as the contents of the <abbr> element by using the setText function.
With the contents of the <abbr> element ready, we can insert it into the document at the location of the cursor by using the insertElement function.
Add the following onOk function code to your dialog window definition, below the code that creates the contents of the dialog.
onOk : function()
{
	var dialog = this;
	var abbr = editor.document.createElement( 'abbr' );
 
	abbr.setAttribute( 'title', dialog.getValueOf( 'tab1', 'title' ) );
	abbr.setText( dialog.getValueOf( 'tab1', 'abbr' ) );
 
	var id = dialog.getValueOf( 'tab2', 'id' );
	if ( id )
		abbr.setAttribute( 'id', id );
 
	editor.insertElement( abbr );
}
important note
Please note that another way to insert HTML code into CKEditor is using the insertHtml function that adds HTML code at the location of the cursor in the document.
editor.insertHtml( '<h2>This is a sample header</h2><p>This is a sample paragraph.</p>' );

Full Source Code

To see the full contents of the plugin.js file, .
important note
You can also download the whole plugin folder inluding the icon and the fully commented source code.

Working Example

The plugin code is now ready. When you click the Insert Abbreviation toolbar button, the Abbreviation Properties dialog window will open. Fill in the obligatory Abbreviation and Explanation fields and click the OK button.
The newly added abbreviation will be inserted into the document and will be displayed using the default styling of your browser. In Firefox, for example, the abbreviation will be underlined using a dotted line and the explanation will be displayed in a tooltip.