Suit Up! Simple and easy WYSIWYG

mercredi 23 janvier 2013



This article is divided into three parts:
  • Entry
  • How to make a simple editor itself , and there will be no theory, just practice. Be warned, for many, this part will seem simple and obvious, since the text is oriented, we can say to ourselves, in the past (no, I do not travel in time :));
  • Description of a very light editor "Suit Up" (original code size: 5.97KB (1.87KB gzipped), minimized: 3.35KB (1.37KB gzipped) as of this writing, not counting the sprite and styles).
UPD Criticism


Entry


Not so long ago, and, more precisely, about two years ago, in the range of developers with whom I had the honor to talk (almost all - beginners), each person who received the task to put WYSIWYG, put monstrous TinyMCE. This editor is considered the standard for some reason, many Web developers, though, few people needed a large number of features that were offered to programmers. Here you and this and that. I guess so, newcomers trying to say to the client, "Look, we want you to website gashes Ward."

Once (can not remember under what conditions), I wanted or needed to sort out how the browser "Rich editory." To my surprise there was a point where I do not having any deep knowledge of web development, made two buttons: Bold and Italic, which proved to be a very simple task. I wanted to know more about what to do next. So I was introduced to a series of articles «WYSIWYG HTML editor in the browser" (the link is the first article, I recommend reading). But the information at the time seemed to me a somewhat complicated. So I decided at random, stepping on rakes have trampled someone to write a simple editor.

I did it as a jQuery plugin, and I think it is not necessary to answer the "why." Get some make it work in different browsers. Then I had the idea to write an article on the Habr, after some modifications. Time passed, I put dopilivanie, postponed ... Two years, hell, for two years. But I'll try to improve.


A simple editor


In order to allow the user to change the contents of the block (in this case, the usual diva) just give it a (block) attribute contenteditable:
<div contenteditable></div> 

The editor is ready!

Just kidding :)

In order to make some changes in the text (eg font color), there is a method document.execCommand , which is applied to the current selection or the position of the carriage. The method takes three arguments:
  1. Command name (eg, italic).
  2. Show whether the standard dialog to get the value (correct if the definition is wrong). People really do not enjoy it, so the value will always be false.
  3. The value of the team.


Embed button Bold, emphasize the text:
 <button class="bold"></button> 

Writing a simple click handler:
 $( '.bold' ).on( 'click', function() { document.execCommand( 'bold', null, null ); }); 

Done. Select the text in the divas, click on the button: op, bold text. Press again: Hob, the text was the same.

Add two more buttons
 <button class="italic">italic</button> <button class="red">Red</button> 

The first will make the text italic (italic, bold as not require a value, since even in Africa italic), the second - to change the text color to red.

 $( '.italic' ).on( 'click', function() { document.execCommand( 'italic', false, null ); }); $( '.red' ).on( 'click', function() { document.execCommand( 'forecolor', false, 'red' ); }); 


Team forecolor , obviously, can not do without a value, or does not understand what it is necessary to set the color of the text.

Result: jsfiddle.net/6BkPu /

That's it, now it is small:
1. Take .innerHTML diva and do with it what you want: to send to the server, insert the textarea , etc.
2. Similar to add commands that you can look at this link .
3. Add icons and play around with fonts.

To illuminate the buttons (to check the current value of commands) used methods document.queryCommandValue and document.queryCommandState . Their behavior will not, as it depends on the browser. Only the manufacturer browser decides to throw an exception or not, only the browser manufacturer decides to return, so I suggest themselves, if desired, to find out what's what. Have, in general, to understand random.

Not to be unfounded, I will give an example.
document.queryCommandValue( 'formatblock' ) in FF and Chrome with the following values: h1, h2, p ..., despite the fact that the values ​​in document.execCommand( 'formatblock', ... ) have been framed in angle brackets: <h1>, <h2>, <p> for it to work in IE, which does not accept the third argument to execCommand( 'formatblock' ... ) values ​​without brackets. This is understandable: we can always define a "block name", which will always be the same. But IE ... what would you dumaliii? .. in response to the call queryCommandValue( 'formatblock' ) returns the "Заголовок 1", "Заголовок 2", "Обычный" , respectively. Catch the name of the block is simply impossible, given that, obviously, for each language has its own individual set of return values. And all this in an innovative, fast and glorious IE10. Hell, in an innovative, fast and glorious IE10! Mazilla and Google is slow but steadily working on bringing the behavior of these methods to the same species, but Melkosoft does not itch.


Editor SuitUp


Demo
So, want to show their version of lightweight editor, which of course is not as cool as multifunctional phenol-freezer-Alarm-irons, but copes with problems undemanding developer. Although, the number of supported methods is large.

The objective was to provide a comfortable layer between the teams and a programmer :)

Started this business, as well as all plugins in this way:
 $( '.my-textarea' ).suitUp(); 

The arguments can be passed to the command list:
 $( '.my-textarea' ).suitUp( 'italic', 'bold', '|', 'formatblock#<h1>' ); 

Or argument in an array
 $( '.my-textarea' ).suitUp([ 'italic', 'bold', '|', 'formatblock#<h1>' ]); 


«|» In the list means a conventional separator, as a design element. Elements that include a grid, we are told that the front of the grille is a team, after - value. Just write nazvanie_komandy # value to arrive at a normal button. Other elements - this is the team to be established, or do not know how we have to get the value. If the behavior is not specified, then the default value will be null. Below I will try to give examples for clarity.

Certain commands (as they should behave team)

To determine the command was created on jQuery.suitUp.commands, containing key-value pairs (your cap), where the key is the name of the command, for example, 'forecolor', and a value can be of three types:

1. Actually, the very value: forecolor it may be red:
 $.suitUp.commands = { forecolor: 'red' } 

or
 $.extend( jQuery.suitUp.commands, { forecolor: 'red' }) 

or
 $.suitUp.commands.forecolor = 'red' // (просто помните, что commands - обычный объект) 

Connect:
 $( '.suitup-textarea' ).suitUp( 'forecolor' ); 

2. Dictionary values ​​(object)
 $.suitUp.commands.forecolor = { 'Make Red': 'red', 'Make Green': 'green' } 

It is converted to a regular tag select, option, which looks like a dictionary key, which is activated when you select the dictionary value.

Hooking up the same way:
 $( '.suitup-textarea' ).suitUp( 'forecolor' ); 



3. Function, which is responsible for the way we have to get the value of the team. It is asynchronous, that is, the function can create a modal window asking value. For an example, the normal propmt:

 jQuery.suitUp.commands.forecolor = function( callback ) { var color = prompt( 'Введите цвет', '' ); // произвольным образом получаем значение callback( color ); //передаём в коллбек } 

And again:
 $( '.suitup-textarea' ).suitUp( 'forecolor' ); 


Of the commands defined in the script, some - in a separate file, the command list is large enough so as not to bother with a definition. That is, you can simply pass the arguments to the method suitUp and it will just work:
 $( 'textarea' ).suitUp( 'italic', 'bold', '|', 'link', 'formatblock#<h1>' ); 

Let's try to add a few buttons. Enjoying a team on the site of Mozilla . Let's say we want to add:
1. Again Bold.
2. Font selection.
3. Dialogue, in which the user needs to enter a value in the custom color box and click "OK".

And pretend that none of the commands are defined.

 $.extend( $.suitUp.commands, { bold: null, // строка для наглядности, не определенные команды по умолчанию имеют значение null fontname: { Arial: 'arial', Times: 'times', Verdana: 'verdana' }, forecolor: function( callback ){ var blackBackground = $( '<div/>' ).css({ background: 'black', position: 'absolute', top: 0, left:0, opacity: .5, width: '100%', height: '100%' }).on( 'click', function(){ popup.add( this ).remove(); }).appendTo('body'), popup = $( '<div/>' ).css({ padding: '10px 20px', width: 200, position: 'absolute', background: 'white', top: 200, left: $( window ).width()/2 - 110, zIndex: 100 }).appendTo('body'); $( '<input/>' ).appendTo( popup ); $( '<button/>' ).appendTo( popup ).text( 'Go!' ).on( 'click', function() { var val = popup.children( 'input' ).val(); blackBackground.add( popup ).remove() callback( val ); }); } }); 


Run
 $( '.suitup-textarea' ).suitUp( 'bold', 'fontname', 'forecolor' ); 








With the first and second team, I think, is clear. The third most of the code is the creation of the elements, you only pay attention to the handler for a click on button. In it, after getting the color and remove popups, called callback, which is transmitted and received color. Callback returns the focus to the editor, restores the selection before clicking forecolor command and applies to the selection.

 document.execCommand( 'forecolor', false, 'введенное значение' ); 

Warning: Although not that teams from different sources identified as camelCase, for correct operation of the plug, all characters must be in lower case. This also applies to the command value.

Custom commands

Besides being able to use the standard commands, plug-in supports the creation of its own elements. In order not to split hairs, I decided to add custom controls are generally functions that return an item.

As is the case with commands for custom elements using an ordinary object:
 $.suitUp.custom = {}; 

Add the item, when clicked, which is called a normal alert welcomed.

 $.extend( jQuery.suitUp.custom, { helloWorld: function() { return $( '<span/>', { 'class': 'suitup-control' // задаёт размеры кнопки }).css( 'backgroundColor', 'red' ).on( 'click', function() { alert( 'Hello World!' ); }); } }); 


Now call:
 $( '.suitup-textarea' ).suitUp( 'bold', 'fontname', 'forecolor', 'helloWorld' ); 



Please note that the custom commands case does not matter.

By default, the list of custom elements is there an element of «link», which in addition to adding a reference (command «createlink»), removes a reference in the current selection (team «unlink»).

 ... { link: function() { return jQuery._createElement( 'a', { className: 'suitup-control', href: '#' }).attr({ 'data-command': 'createlink' // добавляет такой же стиль как и у команды createlink }).on( 'click', function() { if( !$.suitUp.hasSelectedNodeParent( 'a' ) ) { document.execCommand( 'createlink', false, window.prompt( 'URL:', '' ) ); } else { document.execCommand( 'unlink', false, null ); } }); } } 

As can be seen, custom elements are needed not only to create unusual controls (as in the case of the helloWorld), but also can solve the problem with the standard commands.

As a result we have the following ways of creating buttons:
  • In the enumeration of arguments suitUp not specify a command (which is not defined in commands), with the default value is null.
  • Not specify a command is set through the bars ( forecolor#red )
  • Define a command in three ways:
    1. Set the value.
    2. Specify a list of values.
    3. Define a function "extract" value (for example, some colorpicker).

    And listing it as one of the arguments suitUp.
  • Add custom control.


A list of commands by default

Instead of continuing to pass arguments to the method suitUp can declare a set of keys only once:
 $.suitUp.controls = [ 'bold', 'italic' ]; $( '.suitup-textarea' ).suitUp(); // почти то же самое, что и $( '.suitup-textarea' ).suitUp( 'bold', 'italic' ); 

In the array of controls contains a list of buttons that are connected by default. This is an ordinary array. For example, you can add to the default list is one element:

 $.suitUp.controls.push( 'forecolor' ); $( '.suitup-textarea' ).suitUp(); 

Or do this:
 $( '.suitup-textarea' ).suitUp( $.suitUp.controls.concat([ 'forecolor' ]) ); 
in order to add a button for a specific editor (if more than a page).

Several additional features

To simplify certain actions, including the creation of alternative control, object $. SuitUp added a few features. Just warning you, they were written to be used within the plugin and in this framework works well. If you're going to juzat separately, they can not behave like count.

$. SuitUp.getSelection
Returns the current selection. For normal browsers and to asses the return value will be different.

$. SuitUp.restoreSelection
Restores the selection. As the only argument passed to the value obtained in getSelection.

 var sel = $.suitUp.getSelection(); // делаем что-то, при этом теряя фокус $( '.suitup-editor' ).focus(); // возвращаем фокус jQuery.suitUp.restoreSelection( sel ); // восстанавливаем выделение 


$. SuitUp.getSelectedNode
Returns the node of the current selection (which can be as a tag and a text node)

$. SuitUp.hasSelectedNodeParent
Minimis function can only be used in custom item «link». Checks whether the parent node of the current selection with a tag defined in a single argument.
 jQuery.suitUp.hasSelectedNodeParent( 'a' ); // true/false 


The script was tested in Chrome, Firefox, IE10 (+ IE7 Mode)
Hastily created a repository, use: github.com / finom / Suitup

The file contains extended-commands.suitup.jquery.js several teams for testing. Uncomment the code with 50 lines to vote is not an abundance of all the commands that are supported by the plugin.



With typos and inaccuracies, please come to the PM.

Rays beaver.

UPD

Criticism of the comments

Probably should inform potential users, what problems they may encounter when working with the editor. All criticism of the comments comes down to features of the browser, which may be improper if the project requires a standardized format.
1. For different browsers some teams lined text in different tags. For example, the bold text in Chrome surrounds the tag b, but in IE the tag strong.
2. Processing of action may be different in different browsers (examples so far not come to mind).
3. The user can use the formatting that is not implied. For example, can copy the text from Word and paste into the editor.

All of this - a tribute to the compactness of the plugin. If you want to use the editor for a serious public project, I, as an author, I advise you to use alternative solutions. Editor suitable for smaller projects and domestic use, for example, in the admin. The impression of the use in this way - very positive.

Once again good.

0 commentaires:

Enregistrer un commentaire

 
© Copyright 2010-2011 GARMOBI All Rights Reserved.
Template Design by Herdiansyah Hamzah | Published by Borneo Templates | Powered by Blogger.com.