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