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