Roo/bootstrap/form/HtmlEditorToolbar/Standard.js
[roojs1] / Roo / bootstrap / form / HtmlEditorToolbar / Standard.js
1   
2 /**
3  * @class Roo.bootstrap.form.HtmlEditorToolbar.Standard
4  * @parent Roo.bootstrap.form.HtmlEditor
5  * @extends Roo.bootstrap.nav.Simplebar
6  * Basic Toolbar
7  * 
8  * @example
9  * Usage:
10  *
11  new Roo.bootstrap.form.HtmlEditor({
12     ....
13     toolbars : [
14         new Roo.bootstrap.form.HtmlEditorToolbar.Standard({
15             disable : { fonts: 1 , format: 1, ..., ... , ...],
16             btns : [ .... ]
17         })
18     }
19      
20  * 
21  * @cfg {Object} disable List of elements to disable..
22  * @cfg {Array} btns List of additional buttons.
23  * 
24  * 
25  * NEEDS Extra CSS? 
26  * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
27  */
28  
29 Roo.bootstrap.form.HtmlEditorToolbar.Standard = function(config)
30 {
31     
32     Roo.apply(this, config);
33     
34     // default disabled, based on 'good practice'..
35     this.disable = this.disable || {};
36     Roo.applyIf(this.disable, {
37         fontSize : true,
38         colors : true,
39         specialElements : true
40     });
41     Roo.bootstrap.form.HtmlEditorToolbar.Standard.superclass.constructor.call(this, config);
42     
43     this.editor = config.editor;
44     this.editorcore = config.editor.editorcore;
45     
46     this.buttons   = new Roo.util.MixedCollection(false, function(o) { return o.btnid; });
47     
48     //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
49     // dont call parent... till later.
50 }
51 Roo.extend(Roo.bootstrap.form.HtmlEditorToolbar.Standard, Roo.bootstrap.nav.Simplebar,  {
52      
53     bar : true,
54     
55     editor : false,
56     editorcore : false,
57     
58     
59     formats : [
60         "p" ,  
61         "h1","h2","h3","h4","h5","h6", 
62         "pre", "code", 
63         "abbr", "acronym", "address", "cite", "samp", "var",
64         'div','span'
65     ],
66     
67     
68     deleteBtn: false,
69     
70     onRender : function(ct, position)
71     {
72        // Roo.log("Call onRender: " + this.xtype);
73         
74        Roo.bootstrap.form.HtmlEditorToolbar.Standard.superclass.onRender.call(this, ct, position);
75        Roo.log(this.el);
76        this.el.dom.style.marginBottom = '0';
77        var _this = this;
78        var editorcore = this.editorcore;
79        var editor= this.editor;
80        
81        var children = [];
82        var btn = function(id, cmd , toggle, handler, html){
83        
84             var  event = toggle ? 'toggle' : 'click';
85        
86             var a = {
87                 size : 'sm',
88                 xtype: 'Button',
89                 xns: Roo.bootstrap,
90                 //glyphicon : id,
91                 btnid : id,
92                 fa: id,
93                 cmd : cmd, // why id || cmd
94                 enableToggle: toggle !== false,
95                 html : html || '',
96                 pressed : toggle ? false : null,
97                 listeners : {}
98             };
99             a.listeners[toggle ? 'toggle' : 'click'] = function() {
100                 handler ? handler.call(_this,this) :_this.onBtnClick.call(_this, cmd ||  id);
101             };
102             children.push(a);
103             return a;
104        }
105        
106     //    var cb_box = function...
107         
108         var style = {
109                 xtype: 'Button',
110                 size : 'sm',
111                 xns: Roo.bootstrap,
112                 fa : 'font',
113                 //html : 'submit'
114                 menu : {
115                     xtype: 'Menu',
116                     xns: Roo.bootstrap,
117                     items:  []
118                 }
119         };
120         Roo.each(this.formats, function(f) {
121             style.menu.items.push({
122                 xtype :'MenuItem',
123                 xns: Roo.bootstrap,
124                 html : '<'+ f+' style="margin:2px">'+f +'</'+ f+'>',
125                 tagname : f,
126                 listeners : {
127                     click : function()
128                     {
129                         editorcore.insertTag(this.tagname);
130                         editor.focus();
131                     }
132                 }
133                 
134             });
135         });
136         children.push(style);   
137         
138         btn('bold',         false,true);
139         btn('italic',       false,true);
140         btn('align-left',   'justifyleft',true);
141         btn('align-center', 'justifycenter',true);
142         btn('align-right' , 'justifyright',true);
143         btn('link', false, true, function(btn) {
144             var url = this.selectedNode && this.selectedNode.tagName.toUpperCase() == 'A' ?
145                     this.selectedNode.getAttribute('url') : '';
146                 
147             Roo.bootstrap.MessageBox.show({
148                 title : "Add / Edit Link URL",
149                 msg : "Enter the URL for the link",
150                 buttons: this.OKCANCEL,
151                 minWidth: 250,
152                 scope : scope,
153                 prompt:true,
154                 multiline: false,
155                 modal : true,
156                 value : url,
157                 fn:  function(pressed, url) {
158                     if (pressed != 'ok') {
159                         return;
160                     }
161                     
162                     if(url && url.match(/http(s):\/\/.+/)) {
163                         this.editorcore.relayCmd('createlink', url);
164                     }
165                 }
166             });
167         });
168         btn('list','insertunorderedlist',true);
169         btn('list-ol','insertorderedlist',true);
170
171         btn('pencil', false,true, function(btn){
172                 Roo.log(this);
173                 this.toggleSourceEdit(btn.pressed);
174         });
175         
176         if (this.editor.btns.length > 0) {
177             for (var i = 0; i<this.editor.btns.length; i++) {
178                 children.push(this.editor.btns[i]);
179             }
180         }
181         
182         
183          
184         this.xtype = 'NavSimplebar'; // why?
185         
186         for(var i=0;i< children.length;i++) {
187             
188             this.buttons.add(this.addxtypeChild(children[i]));
189             
190         }
191         this.buildToolbarDelete();
192
193         editor.on('editorevent', this.updateToolbar, this);
194     },
195     
196     buildToolbarDelete : function()
197     {
198         
199        /* this.addxtypeChild({
200             xtype : 'Element',
201             xns : Roo.bootstrap,
202             cls : 'roo-htmleditor-fill'
203         });
204         */
205         this.deleteBtn = this.addxtypeChild({
206             size : 'sm',
207             xtype: 'Button',
208             xns: Roo.bootstrap,
209             fa: 'trash',
210             listeners : {
211                 click : this.onDelete.createDelegate(this)
212             }
213         });
214         this.deleteBtn.hide();     
215         
216     },
217     
218     
219     onBtnClick : function(id)
220     {
221        this.editorcore.relayCmd(id);
222        this.editorcore.focus();
223     },
224     
225     /**
226      * Protected method that will not generally be called directly. It triggers
227      * a toolbar update by reading the markup state of the current selection in the editor.
228      */
229     updateToolbar: function(editor ,ev, sel){
230
231         if(!this.editorcore.activated){
232             this.editor.onFirstFocus(); // is this neeed?
233             return;
234         }
235
236         var btns = this.buttons; 
237         var doc = this.editorcore.doc;
238         var hasToggle  = false;
239         btns.each(function(e) {
240             if (e.enableToggle && e.cmd) {
241                 hasToggle = hasToggle  || (['align-left', 'align-right', 'align-center'].indexOf(e.cmd) < 0 || doc.queryCommandState(e.cmd));
242                 e.setActive(doc.queryCommandState(e.cmd));
243             }
244         }, this);
245         
246         
247         if (ev &&
248             (ev.type == 'mouseup' || ev.type == 'click' ) &&
249             ev.target && ev.target.tagName != 'BODY' ) { // && ev.target.tagName == 'IMG') {
250             // they have click on an image...
251             // let's see if we can change the selection...
252             sel = ev.target;
253             
254         }
255         
256         var ans = this.editorcore.getAllAncestors();
257         if (!sel) { 
258             sel = ans.length ? (ans[0] ?  ans[0]  : ans[1]) : this.editorcore.doc.body;
259             sel = sel ? sel : this.editorcore.doc.body;
260             sel = sel.tagName.length ? sel : this.editorcore.doc.body;
261             
262         }
263         
264         var lastSel = this.selectedNode;
265         this.selectedNode = sel;
266          
267         // ok see if we are editing a block?
268         
269         var db = false;
270         // you are not actually selecting the block.
271         if (sel && sel.hasAttribute('data-block')) {
272             db = sel;
273         } else if (sel && sel.closest('[data-block]')) {
274             db = sel.closest('[data-block]');
275         }
276         
277        
278         var block = false;
279         if (db && this.editorcore.enableBlocks) {
280             block = Roo.htmleditor.Block.factory(db);
281             
282             if (block) {
283                 db.className = (
284                         db.classList.length > 0  ? db.className + ' ' : ''
285                     )  + 'roo-ed-selection';
286                 sel = this.selectedNode = db;
287             }
288         }
289         
290         // highlight the 'a'..
291         var tn = sel && sel.tagName.toUpperCase() || '';
292         if (!block && sel && tn != 'A') {
293             var asel = sel.closest('A');
294             if (asel) {
295                 sel = asel;
296             }
297         }
298        
299         btns.get('link').setActive(tn == 'A' && this.selectedNode.hasAttribute('href'));
300         
301         Roo.bootstrap.menu.Manager.hideAll();
302          
303         
304         Array.from(this.editorcore.doc.body.querySelectorAll('.roo-ed-selection')).forEach(function(e) {
305             e.classList.remove('roo-ed-selection');
306         });
307         
308         
309         // handle delete button..
310         if (hasToggle || (tn.length && tn == 'BODY')) {
311             this.deleteBtn.hide();
312             return;
313             
314         }
315         this.deleteBtn.show();
316         
317         
318         
319         //this.editorsyncValue();
320     },
321     onFirstFocus: function() {
322         this.buttons.each(function(item){
323            item.enable();
324         });
325     },
326     
327     onDelete : function()
328     {
329         var range = this.editorcore.createRange();
330         var selection = this.editorcore.getSelection();
331         var sn = this.selectedNode;
332         range.setStart(sn,0);
333         range.setEnd(sn,0); 
334         
335         
336         if (sn.hasAttribute('data-block')) {
337             var block = Roo.htmleditor.Block.factory(tb.selectedNode);
338             if (block) {
339                 block.removeNode();
340                 selection.removeAllRanges();
341                 selection.addRange(range);
342                 this.updateToolbar(null, null, null);
343             }   
344              
345         }
346         if (!sn) {
347             return; // should not really happen..
348         }
349         if (sn && sn.tagName == 'BODY') {
350             return;
351         }
352         var stn =  sn.childNodes[0] || sn.nextSibling || sn.previousSibling || sn.parentNode;
353         
354         // remove and keep parents.
355         a = new Roo.htmleditor.FilterKeepChildren({tag : false});
356         a.replaceTag(sn);
357         
358         selection.removeAllRanges();
359         selection.addRange(range);
360         this.editorcore.fireEditorEvent(false);
361         
362         
363     },
364     
365     
366     toggleSourceEdit : function(sourceEditMode){
367         
368           
369         if(sourceEditMode){
370             Roo.log("disabling buttons");
371            this.buttons.each( function(item){
372                 if(item.cmd != 'pencil'){
373                     item.disable();
374                 }
375             });
376           
377         }else{
378             Roo.log("enabling buttons");
379             if(this.editorcore.initialized){
380                 this.buttons.each( function(item){
381                     item.enable();
382                 });
383             }
384             
385         }
386         Roo.log("calling toggole on editor");
387         // tell the editor that it's been pressed..
388         this.editor.toggleSourceEdit(sourceEditMode);
389        
390     }
391 });
392
393
394
395