Merge branch 'master' of http://git.roojs.com:8081/roojs1
[roojs1] / Roo / form / HtmlEditor / ToolbarStandard.js
1 // <script type="text/javascript">
2 /*
3  * Based on
4  * Ext JS Library 1.1.1
5  * Copyright(c) 2006-2007, Ext JS, LLC.
6  *  
7  
8  */
9
10 /**
11  * @class Roo.form.HtmlEditorToolbar1
12  * Basic Toolbar
13  * 
14  * Usage:
15  *
16  new Roo.form.HtmlEditor({
17     ....
18     toolbars : [
19         new Roo.form.HtmlEditorToolbar1({
20             disable : { fonts: 1 , format: 1, ..., ... , ...],
21             btns : [ .... ]
22         })
23     }
24      
25  * 
26  * @cfg {Object} disable List of elements to disable..
27  * @cfg {Array} btns List of additional buttons.
28  * 
29  * 
30  * NEEDS Extra CSS? 
31  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
32  */
33  
34 Roo.form.HtmlEditor.ToolbarStandard = function(config)
35 {
36     
37     Roo.apply(this, config);
38     
39     // default disabled, based on 'good practice'..
40     this.disable = this.disable || {};
41     Roo.applyIf(this.disable, {
42         fontSize : true,
43         colors : true,
44         specialElements : true
45     });
46     
47     
48     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
49     // dont call parent... till later.
50 }
51
52 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype,  {
53     
54     tb: false,
55     
56     rendered: false,
57     
58     editor : false,
59     /**
60      * @cfg {Object} disable  List of toolbar elements to disable
61          
62      */
63     disable : false,
64       /**
65      * @cfg {Array} fontFamilies An array of available font families
66      */
67     fontFamilies : [
68         'Arial',
69         'Courier New',
70         'Tahoma',
71         'Times New Roman',
72         'Verdana'
73     ],
74     
75     specialChars : [
76            "&#169;",
77           "&#174;",     
78           "&#8482;",    
79           "&#163;" ,    
80          // "&#8212;",    
81           "&#8230;",    
82           "&#247;" ,    
83         //  "&#225;" ,     ?? a acute?
84            "&#8364;"    , //Euro
85        //   "&#8220;"    ,
86         //  "&#8221;"    ,
87         //  "&#8226;"    ,
88           "&#176;"  //   , // degrees
89
90          // "&#233;"     , // e ecute
91          // "&#250;"     , // u ecute?
92     ],
93     
94     specialElements : [
95         {
96             text: "Insert Table",
97             xtype: 'MenuItem',
98             xns : Roo.Menu,
99             ihtml :  '<table><tr><td>Cell</td></tr></table>' 
100                 
101         },
102         {    
103             text: "Insert Image",
104             xtype: 'MenuItem',
105             xns : Roo.Menu,
106             ihtml : '<img src="about:blank"/>'
107             
108         }
109         
110          
111     ],
112     
113     
114     inputElements : [ 
115             "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password", 
116             "input:submit", "input:button", "select", "textarea", "label" ],
117     formats : [
118         ["p"] ,  
119         ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"], 
120         ["pre"],[ "code"], 
121         ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
122     ],
123      /**
124      * @cfg {String} defaultFont default font to use.
125      */
126     defaultFont: 'tahoma',
127    
128     fontSelect : false,
129     
130     
131     formatCombo : false,
132     
133     init : function(editor)
134     {
135         this.editor = editor;
136         
137         
138         var fid = editor.frameId;
139         var etb = this;
140         function btn(id, toggle, handler){
141             var xid = fid + '-'+ id ;
142             return {
143                 id : xid,
144                 cmd : id,
145                 cls : 'x-btn-icon x-edit-'+id,
146                 enableToggle:toggle !== false,
147                 scope: editor, // was editor...
148                 handler:handler||editor.relayBtnCmd,
149                 clickEvent:'mousedown',
150                 tooltip: etb.buttonTips[id] || undefined, ///tips ???
151                 tabIndex:-1
152             };
153         }
154         
155         
156         
157         var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
158         this.tb = tb;
159          // stop form submits
160         tb.el.on('click', function(e){
161             e.preventDefault(); // what does this do?
162         });
163
164         if(!this.disable.font && !Roo.isSafari){
165             /* why no safari for fonts
166             editor.fontSelect = tb.el.createChild({
167                 tag:'select',
168                 tabIndex: -1,
169                 cls:'x-font-select',
170                 html: editor.createFontOptions()
171             });
172             editor.fontSelect.on('change', function(){
173                 var font = editor.fontSelect.dom.value;
174                 editor.relayCmd('fontname', font);
175                 editor.deferFocus();
176             }, editor);
177             tb.add(
178                 editor.fontSelect.dom,
179                 '-'
180             );
181             */
182         };
183         if(!this.disable.formats){
184             this.formatCombo = new Roo.form.ComboBox({
185                 store: new Roo.data.SimpleStore({
186                     id : 'tag',
187                     fields: ['tag'],
188                     data : this.formats // from states.js
189                 }),
190                 blockFocus : true,
191                 //autoCreate : {tag: "div",  size: "20"},
192                 displayField:'tag',
193                 typeAhead: false,
194                 mode: 'local',
195                 editable : false,
196                 triggerAction: 'all',
197                 emptyText:'Add tag',
198                 selectOnFocus:true,
199                 width:135,
200                 listeners : {
201                     'select': function(c, r, i) {
202                         editor.insertTag(r.get('tag'));
203                         editor.focus();
204                     }
205                 }
206
207             });
208             tb.addField(this.formatCombo);
209             
210         }
211         
212         if(!this.disable.format){
213             tb.add(
214                 btn('bold'),
215                 btn('italic'),
216                 btn('underline')
217             );
218         };
219         if(!this.disable.fontSize){
220             tb.add(
221                 '-',
222                 
223                 
224                 btn('increasefontsize', false, editor.adjustFont),
225                 btn('decreasefontsize', false, editor.adjustFont)
226             );
227         };
228         
229         
230         if(!this.disable.colors){
231             tb.add(
232                 '-', {
233                     id:editor.frameId +'-forecolor',
234                     cls:'x-btn-icon x-edit-forecolor',
235                     clickEvent:'mousedown',
236                     tooltip: this.buttonTips['forecolor'] || undefined,
237                     tabIndex:-1,
238                     menu : new Roo.menu.ColorMenu({
239                         allowReselect: true,
240                         focus: Roo.emptyFn,
241                         value:'000000',
242                         plain:true,
243                         selectHandler: function(cp, color){
244                             editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
245                             editor.deferFocus();
246                         },
247                         scope: editor,
248                         clickEvent:'mousedown'
249                     })
250                 }, {
251                     id:editor.frameId +'backcolor',
252                     cls:'x-btn-icon x-edit-backcolor',
253                     clickEvent:'mousedown',
254                     tooltip: this.buttonTips['backcolor'] || undefined,
255                     tabIndex:-1,
256                     menu : new Roo.menu.ColorMenu({
257                         focus: Roo.emptyFn,
258                         value:'FFFFFF',
259                         plain:true,
260                         allowReselect: true,
261                         selectHandler: function(cp, color){
262                             if(Roo.isGecko){
263                                 editor.execCmd('useCSS', false);
264                                 editor.execCmd('hilitecolor', color);
265                                 editor.execCmd('useCSS', true);
266                                 editor.deferFocus();
267                             }else{
268                                 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor', 
269                                     Roo.isSafari || Roo.isIE ? '#'+color : color);
270                                 editor.deferFocus();
271                             }
272                         },
273                         scope:editor,
274                         clickEvent:'mousedown'
275                     })
276                 }
277             );
278         };
279         // now add all the items...
280         
281
282         if(!this.disable.alignments){
283             tb.add(
284                 '-',
285                 btn('justifyleft'),
286                 btn('justifycenter'),
287                 btn('justifyright')
288             );
289         };
290
291         //if(!Roo.isSafari){
292             if(!this.disable.links){
293                 tb.add(
294                     '-',
295                     btn('createlink', false, editor.createLink)    /// MOVE TO HERE?!!?!?!?!
296                 );
297             };
298
299             if(!this.disable.lists){
300                 tb.add(
301                     '-',
302                     btn('insertorderedlist'),
303                     btn('insertunorderedlist')
304                 );
305             }
306             if(!this.disable.sourceEdit){
307                 tb.add(
308                     '-',
309                     btn('sourceedit', true, function(btn){
310                         this.toggleSourceEdit(btn.pressed);
311                     })
312                 );
313             }
314         //}
315         
316         var smenu = { };
317         // special menu.. - needs to be tidied up..
318         if (!this.disable.special) {
319             smenu = {
320                 text: "&#169;",
321                 cls: 'x-edit-none',
322                 
323                 menu : {
324                     items : []
325                 }
326             };
327             for (var i =0; i < this.specialChars.length; i++) {
328                 smenu.menu.items.push({
329                     
330                     html: this.specialChars[i],
331                     handler: function(a,b) {
332                         editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
333                         //editor.insertAtCursor(a.html);
334                         
335                     },
336                     tabIndex:-1
337                 });
338             }
339             
340             
341             tb.add(smenu);
342             
343             
344         }
345          
346         if (!this.disable.specialElements) {
347             var semenu = {
348                 text: "Other;",
349                 cls: 'x-edit-none',
350                 menu : {
351                     items : []
352                 }
353             };
354             for (var i =0; i < this.specialElements.length; i++) {
355                 semenu.menu.items.push(
356                     Roo.apply({ 
357                         handler: function(a,b) {
358                             editor.insertAtCursor(this.ihtml);
359                         }
360                     }, this.specialElements[i])
361                 );
362                     
363             }
364             
365             tb.add(semenu);
366             
367             
368         }
369          
370         
371         if (this.btns) {
372             for(var i =0; i< this.btns.length;i++) {
373                 var b = this.btns[i];
374                 b.cls =  'x-edit-none';
375                 b.scope = editor;
376                 tb.add(b);
377             }
378         
379         }
380         
381         
382         
383         // disable everything...
384         
385         this.tb.items.each(function(item){
386            if(item.id != editor.frameId+ '-sourceedit'){
387                 item.disable();
388             }
389         });
390         this.rendered = true;
391         
392         // the all the btns;
393         editor.on('editorevent', this.updateToolbar, this);
394         // other toolbars need to implement this..
395         //editor.on('editmodechange', this.updateToolbar, this);
396     },
397     
398     
399     
400     /**
401      * Protected method that will not generally be called directly. It triggers
402      * a toolbar update by reading the markup state of the current selection in the editor.
403      */
404     updateToolbar: function(){
405
406         if(!this.editor.activated){
407             this.editor.onFirstFocus();
408             return;
409         }
410
411         var btns = this.tb.items.map, 
412             doc = this.editor.doc,
413             frameId = this.editor.frameId;
414
415         if(!this.disable.font && !Roo.isSafari){
416             /*
417             var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
418             if(name != this.fontSelect.dom.value){
419                 this.fontSelect.dom.value = name;
420             }
421             */
422         }
423         if(!this.disable.format){
424             btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
425             btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
426             btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
427         }
428         if(!this.disable.alignments){
429             btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
430             btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
431             btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
432         }
433         if(!Roo.isSafari && !this.disable.lists){
434             btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
435             btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
436         }
437         
438         var ans = this.editor.getAllAncestors();
439         if (this.formatCombo) {
440             
441             
442             var store = this.formatCombo.store;
443             this.formatCombo.setValue("");
444             for (var i =0; i < ans.length;i++) {
445                 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
446                     // select it..
447                     this.formatCombo.setValue(ans[i].tagName.toLowerCase());
448                     break;
449                 }
450             }
451         }
452         
453         
454         
455         // hides menus... - so this cant be on a menu...
456         Roo.menu.MenuMgr.hideAll();
457
458         //this.editorsyncValue();
459     },
460    
461     
462     createFontOptions : function(){
463         var buf = [], fs = this.fontFamilies, ff, lc;
464         for(var i = 0, len = fs.length; i< len; i++){
465             ff = fs[i];
466             lc = ff.toLowerCase();
467             buf.push(
468                 '<option value="',lc,'" style="font-family:',ff,';"',
469                     (this.defaultFont == lc ? ' selected="true">' : '>'),
470                     ff,
471                 '</option>'
472             );
473         }
474         return buf.join('');
475     },
476     
477     toggleSourceEdit : function(sourceEditMode){
478         if(sourceEditMode === undefined){
479             sourceEditMode = !this.sourceEditMode;
480         }
481         this.sourceEditMode = sourceEditMode === true;
482         var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
483         // just toggle the button?
484         if(btn.pressed !== this.editor.sourceEditMode){
485             btn.toggle(this.editor.sourceEditMode);
486             return;
487         }
488         
489         if(this.sourceEditMode){
490             this.tb.items.each(function(item){
491                 if(item.cmd != 'sourceedit'){
492                     item.disable();
493                 }
494             });
495           
496         }else{
497             if(this.initialized){
498                 this.tb.items.each(function(item){
499                     item.enable();
500                 });
501             }
502             
503         }
504         // tell the editor that it's been pressed..
505         this.editor.toggleSourceEdit(sourceEditMode);
506        
507     },
508      /**
509      * Object collection of toolbar tooltips for the buttons in the editor. The key
510      * is the command id associated with that button and the value is a valid QuickTips object.
511      * For example:
512 <pre><code>
513 {
514     bold : {
515         title: 'Bold (Ctrl+B)',
516         text: 'Make the selected text bold.',
517         cls: 'x-html-editor-tip'
518     },
519     italic : {
520         title: 'Italic (Ctrl+I)',
521         text: 'Make the selected text italic.',
522         cls: 'x-html-editor-tip'
523     },
524     ...
525 </code></pre>
526     * @type Object
527      */
528     buttonTips : {
529         bold : {
530             title: 'Bold (Ctrl+B)',
531             text: 'Make the selected text bold.',
532             cls: 'x-html-editor-tip'
533         },
534         italic : {
535             title: 'Italic (Ctrl+I)',
536             text: 'Make the selected text italic.',
537             cls: 'x-html-editor-tip'
538         },
539         underline : {
540             title: 'Underline (Ctrl+U)',
541             text: 'Underline the selected text.',
542             cls: 'x-html-editor-tip'
543         },
544         increasefontsize : {
545             title: 'Grow Text',
546             text: 'Increase the font size.',
547             cls: 'x-html-editor-tip'
548         },
549         decreasefontsize : {
550             title: 'Shrink Text',
551             text: 'Decrease the font size.',
552             cls: 'x-html-editor-tip'
553         },
554         backcolor : {
555             title: 'Text Highlight Color',
556             text: 'Change the background color of the selected text.',
557             cls: 'x-html-editor-tip'
558         },
559         forecolor : {
560             title: 'Font Color',
561             text: 'Change the color of the selected text.',
562             cls: 'x-html-editor-tip'
563         },
564         justifyleft : {
565             title: 'Align Text Left',
566             text: 'Align text to the left.',
567             cls: 'x-html-editor-tip'
568         },
569         justifycenter : {
570             title: 'Center Text',
571             text: 'Center text in the editor.',
572             cls: 'x-html-editor-tip'
573         },
574         justifyright : {
575             title: 'Align Text Right',
576             text: 'Align text to the right.',
577             cls: 'x-html-editor-tip'
578         },
579         insertunorderedlist : {
580             title: 'Bullet List',
581             text: 'Start a bulleted list.',
582             cls: 'x-html-editor-tip'
583         },
584         insertorderedlist : {
585             title: 'Numbered List',
586             text: 'Start a numbered list.',
587             cls: 'x-html-editor-tip'
588         },
589         createlink : {
590             title: 'Hyperlink',
591             text: 'Make the selected text a hyperlink.',
592             cls: 'x-html-editor-tip'
593         },
594         sourceedit : {
595             title: 'Source Edit',
596             text: 'Switch to source editing mode.',
597             cls: 'x-html-editor-tip'
598         }
599     },
600     // private
601     onDestroy : function(){
602         if(this.rendered){
603             
604             this.tb.items.each(function(item){
605                 if(item.menu){
606                     item.menu.removeAll();
607                     if(item.menu.el){
608                         item.menu.el.destroy();
609                     }
610                 }
611                 item.destroy();
612             });
613              
614         }
615     },
616     onFirstFocus: function() {
617         this.tb.items.each(function(item){
618            item.enable();
619         });
620     }
621 });
622
623
624
625