Roo/form/HtmlEditor/ToolbarStandard.js
[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         ['div'],['span']
123     ],
124     
125     cleanStyles : [
126         "font-size",
127         "color"
128     ],
129      /**
130      * @cfg {String} defaultFont default font to use.
131      */
132     defaultFont: 'tahoma',
133    
134     fontSelect : false,
135     
136     
137     formatCombo : false,
138     
139     init : function(editor)
140     {
141         this.editor = editor;
142         
143         
144         var fid = editor.frameId;
145         var etb = this;
146         function btn(id, toggle, handler){
147             var xid = fid + '-'+ id ;
148             return {
149                 id : xid,
150                 cmd : id,
151                 cls : 'x-btn-icon x-edit-'+id,
152                 enableToggle:toggle !== false,
153                 scope: editor, // was editor...
154                 handler:handler||editor.relayBtnCmd,
155                 clickEvent:'mousedown',
156                 tooltip: etb.buttonTips[id] || undefined, ///tips ???
157                 tabIndex:-1
158             };
159         }
160         
161         
162         
163         var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
164         this.tb = tb;
165          // stop form submits
166         tb.el.on('click', function(e){
167             e.preventDefault(); // what does this do?
168         });
169
170         if(!this.disable.font) { // && !Roo.isSafari){
171             /* why no safari for fonts 
172             editor.fontSelect = tb.el.createChild({
173                 tag:'select',
174                 tabIndex: -1,
175                 cls:'x-font-select',
176                 html: this.createFontOptions()
177             });
178             
179             editor.fontSelect.on('change', function(){
180                 var font = editor.fontSelect.dom.value;
181                 editor.relayCmd('fontname', font);
182                 editor.deferFocus();
183             }, editor);
184             
185             tb.add(
186                 editor.fontSelect.dom,
187                 '-'
188             );
189             */
190             
191         };
192         if(!this.disable.formats){
193             this.formatCombo = new Roo.form.ComboBox({
194                 store: new Roo.data.SimpleStore({
195                     id : 'tag',
196                     fields: ['tag'],
197                     data : this.formats // from states.js
198                 }),
199                 blockFocus : true,
200                 name : '',
201                 //autoCreate : {tag: "div",  size: "20"},
202                 displayField:'tag',
203                 typeAhead: false,
204                 mode: 'local',
205                 editable : false,
206                 triggerAction: 'all',
207                 emptyText:'Add tag',
208                 selectOnFocus:true,
209                 width:135,
210                 listeners : {
211                     'select': function(c, r, i) {
212                         editor.insertTag(r.get('tag'));
213                         editor.focus();
214                     }
215                 }
216
217             });
218             tb.addField(this.formatCombo);
219             
220         }
221         
222         if(!this.disable.format){
223             tb.add(
224                 btn('bold'),
225                 btn('italic'),
226                 btn('underline')
227             );
228         };
229         if(!this.disable.fontSize){
230             tb.add(
231                 '-',
232                 
233                 
234                 btn('increasefontsize', false, editor.adjustFont),
235                 btn('decreasefontsize', false, editor.adjustFont)
236             );
237         };
238         
239         
240         if(!this.disable.colors){
241             tb.add(
242                 '-', {
243                     id:editor.frameId +'-forecolor',
244                     cls:'x-btn-icon x-edit-forecolor',
245                     clickEvent:'mousedown',
246                     tooltip: this.buttonTips['forecolor'] || undefined,
247                     tabIndex:-1,
248                     menu : new Roo.menu.ColorMenu({
249                         allowReselect: true,
250                         focus: Roo.emptyFn,
251                         value:'000000',
252                         plain:true,
253                         selectHandler: function(cp, color){
254                             editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
255                             editor.deferFocus();
256                         },
257                         scope: editor,
258                         clickEvent:'mousedown'
259                     })
260                 }, {
261                     id:editor.frameId +'backcolor',
262                     cls:'x-btn-icon x-edit-backcolor',
263                     clickEvent:'mousedown',
264                     tooltip: this.buttonTips['backcolor'] || undefined,
265                     tabIndex:-1,
266                     menu : new Roo.menu.ColorMenu({
267                         focus: Roo.emptyFn,
268                         value:'FFFFFF',
269                         plain:true,
270                         allowReselect: true,
271                         selectHandler: function(cp, color){
272                             if(Roo.isGecko){
273                                 editor.execCmd('useCSS', false);
274                                 editor.execCmd('hilitecolor', color);
275                                 editor.execCmd('useCSS', true);
276                                 editor.deferFocus();
277                             }else{
278                                 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor', 
279                                     Roo.isSafari || Roo.isIE ? '#'+color : color);
280                                 editor.deferFocus();
281                             }
282                         },
283                         scope:editor,
284                         clickEvent:'mousedown'
285                     })
286                 }
287             );
288         };
289         // now add all the items...
290         
291
292         if(!this.disable.alignments){
293             tb.add(
294                 '-',
295                 btn('justifyleft'),
296                 btn('justifycenter'),
297                 btn('justifyright')
298             );
299         };
300
301         //if(!Roo.isSafari){
302             if(!this.disable.links){
303                 tb.add(
304                     '-',
305                     btn('createlink', false, editor.createLink)    /// MOVE TO HERE?!!?!?!?!
306                 );
307             };
308
309             if(!this.disable.lists){
310                 tb.add(
311                     '-',
312                     btn('insertorderedlist'),
313                     btn('insertunorderedlist')
314                 );
315             }
316             if(!this.disable.sourceEdit){
317                 tb.add(
318                     '-',
319                     btn('sourceedit', true, function(btn){
320                         this.toggleSourceEdit(btn.pressed);
321                     })
322                 );
323             }
324         //}
325         
326         var smenu = { };
327         // special menu.. - needs to be tidied up..
328         if (!this.disable.special) {
329             smenu = {
330                 text: "&#169;",
331                 cls: 'x-edit-none',
332                 
333                 menu : {
334                     items : []
335                 }
336             };
337             for (var i =0; i < this.specialChars.length; i++) {
338                 smenu.menu.items.push({
339                     
340                     html: this.specialChars[i],
341                     handler: function(a,b) {
342                         editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
343                         //editor.insertAtCursor(a.html);
344                         
345                     },
346                     tabIndex:-1
347                 });
348             }
349             
350             
351             tb.add(smenu);
352             
353             
354         }
355         
356         var cmenu = { };
357         if (!this.disable.cleanStyles) {
358             Roo.log('init toolbar style');
359             cmenu = {
360                 cls: 'x-btn-icon x-btn-clear',
361                 
362                 menu : {
363                     items : []
364                 }
365             };
366             for (var i =0; i < this.cleanStyles.length; i++) {
367                 cmenu.menu.items.push({
368                     
369                     html: this.cleanStyles[i],
370                     handler: function(a,b) {
371                         var c = Roo.get(editor.doc.body);
372                         c.select('[style]').each(function(s) {
373                             s.dom.style.removeProperty(a.html);
374                         });
375                         
376                     },
377                     tabIndex:-1
378                 });
379             }
380             
381             
382             tb.add(cmenu);
383             
384             
385         }
386          
387         if (!this.disable.specialElements) {
388             var semenu = {
389                 text: "Other;",
390                 cls: 'x-edit-none',
391                 menu : {
392                     items : []
393                 }
394             };
395             for (var i =0; i < this.specialElements.length; i++) {
396                 semenu.menu.items.push(
397                     Roo.apply({ 
398                         handler: function(a,b) {
399                             editor.insertAtCursor(this.ihtml);
400                         }
401                     }, this.specialElements[i])
402                 );
403                     
404             }
405             
406             tb.add(semenu);
407             
408             
409         }
410          
411         
412         if (this.btns) {
413             for(var i =0; i< this.btns.length;i++) {
414                 var b = Roo.factory(this.btns[i],Roo.form);
415                 b.cls =  'x-edit-none';
416                 b.scope = editor;
417                 tb.add(b);
418             }
419         
420         }
421         
422         
423         
424         // disable everything...
425         
426         this.tb.items.each(function(item){
427            if(item.id != editor.frameId+ '-sourceedit'){
428                 item.disable();
429             }
430         });
431         this.rendered = true;
432         
433         // the all the btns;
434         editor.on('editorevent', this.updateToolbar, this);
435         // other toolbars need to implement this..
436         //editor.on('editmodechange', this.updateToolbar, this);
437     },
438     
439     
440     
441     /**
442      * Protected method that will not generally be called directly. It triggers
443      * a toolbar update by reading the markup state of the current selection in the editor.
444      */
445     updateToolbar: function(){
446
447         if(!this.editor.activated){
448             this.editor.onFirstFocus();
449             return;
450         }
451
452         var btns = this.tb.items.map, 
453             doc = this.editor.doc,
454             frameId = this.editor.frameId;
455
456         if(!this.disable.font && !Roo.isSafari){
457             /*
458             var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
459             if(name != this.fontSelect.dom.value){
460                 this.fontSelect.dom.value = name;
461             }
462             */
463         }
464         if(!this.disable.format){
465             btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
466             btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
467             btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
468         }
469         if(!this.disable.alignments){
470             btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
471             btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
472             btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
473         }
474         if(!Roo.isSafari && !this.disable.lists){
475             btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
476             btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
477         }
478         
479         var ans = this.editor.getAllAncestors();
480         if (this.formatCombo) {
481             
482             
483             var store = this.formatCombo.store;
484             this.formatCombo.setValue("");
485             for (var i =0; i < ans.length;i++) {
486                 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
487                     // select it..
488                     this.formatCombo.setValue(ans[i].tagName.toLowerCase());
489                     break;
490                 }
491             }
492         }
493         
494         
495         
496         // hides menus... - so this cant be on a menu...
497         Roo.menu.MenuMgr.hideAll();
498
499         //this.editorsyncValue();
500     },
501    
502     
503     createFontOptions : function(){
504         var buf = [], fs = this.fontFamilies, ff, lc;
505         
506         
507         
508         for(var i = 0, len = fs.length; i< len; i++){
509             ff = fs[i];
510             lc = ff.toLowerCase();
511             buf.push(
512                 '<option value="',lc,'" style="font-family:',ff,';"',
513                     (this.defaultFont == lc ? ' selected="true">' : '>'),
514                     ff,
515                 '</option>'
516             );
517         }
518         return buf.join('');
519     },
520     
521     toggleSourceEdit : function(sourceEditMode){
522         if(sourceEditMode === undefined){
523             sourceEditMode = !this.sourceEditMode;
524         }
525         this.sourceEditMode = sourceEditMode === true;
526         var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
527         // just toggle the button?
528         if(btn.pressed !== this.editor.sourceEditMode){
529             btn.toggle(this.editor.sourceEditMode);
530             return;
531         }
532         
533         if(this.sourceEditMode){
534             this.tb.items.each(function(item){
535                 if(item.cmd != 'sourceedit'){
536                     item.disable();
537                 }
538             });
539           
540         }else{
541             if(this.initialized){
542                 this.tb.items.each(function(item){
543                     item.enable();
544                 });
545             }
546             
547         }
548         // tell the editor that it's been pressed..
549         this.editor.toggleSourceEdit(sourceEditMode);
550        
551     },
552      /**
553      * Object collection of toolbar tooltips for the buttons in the editor. The key
554      * is the command id associated with that button and the value is a valid QuickTips object.
555      * For example:
556 <pre><code>
557 {
558     bold : {
559         title: 'Bold (Ctrl+B)',
560         text: 'Make the selected text bold.',
561         cls: 'x-html-editor-tip'
562     },
563     italic : {
564         title: 'Italic (Ctrl+I)',
565         text: 'Make the selected text italic.',
566         cls: 'x-html-editor-tip'
567     },
568     ...
569 </code></pre>
570     * @type Object
571      */
572     buttonTips : {
573         bold : {
574             title: 'Bold (Ctrl+B)',
575             text: 'Make the selected text bold.',
576             cls: 'x-html-editor-tip'
577         },
578         italic : {
579             title: 'Italic (Ctrl+I)',
580             text: 'Make the selected text italic.',
581             cls: 'x-html-editor-tip'
582         },
583         underline : {
584             title: 'Underline (Ctrl+U)',
585             text: 'Underline the selected text.',
586             cls: 'x-html-editor-tip'
587         },
588         increasefontsize : {
589             title: 'Grow Text',
590             text: 'Increase the font size.',
591             cls: 'x-html-editor-tip'
592         },
593         decreasefontsize : {
594             title: 'Shrink Text',
595             text: 'Decrease the font size.',
596             cls: 'x-html-editor-tip'
597         },
598         backcolor : {
599             title: 'Text Highlight Color',
600             text: 'Change the background color of the selected text.',
601             cls: 'x-html-editor-tip'
602         },
603         forecolor : {
604             title: 'Font Color',
605             text: 'Change the color of the selected text.',
606             cls: 'x-html-editor-tip'
607         },
608         justifyleft : {
609             title: 'Align Text Left',
610             text: 'Align text to the left.',
611             cls: 'x-html-editor-tip'
612         },
613         justifycenter : {
614             title: 'Center Text',
615             text: 'Center text in the editor.',
616             cls: 'x-html-editor-tip'
617         },
618         justifyright : {
619             title: 'Align Text Right',
620             text: 'Align text to the right.',
621             cls: 'x-html-editor-tip'
622         },
623         insertunorderedlist : {
624             title: 'Bullet List',
625             text: 'Start a bulleted list.',
626             cls: 'x-html-editor-tip'
627         },
628         insertorderedlist : {
629             title: 'Numbered List',
630             text: 'Start a numbered list.',
631             cls: 'x-html-editor-tip'
632         },
633         createlink : {
634             title: 'Hyperlink',
635             text: 'Make the selected text a hyperlink.',
636             cls: 'x-html-editor-tip'
637         },
638         sourceedit : {
639             title: 'Source Edit',
640             text: 'Switch to source editing mode.',
641             cls: 'x-html-editor-tip'
642         }
643     },
644     // private
645     onDestroy : function(){
646         if(this.rendered){
647             
648             this.tb.items.each(function(item){
649                 if(item.menu){
650                     item.menu.removeAll();
651                     if(item.menu.el){
652                         item.menu.el.destroy();
653                     }
654                 }
655                 item.destroy();
656             });
657              
658         }
659     },
660     onFirstFocus: function() {
661         this.tb.items.each(function(item){
662            item.enable();
663         });
664     }
665 });
666
667
668
669