fix broken commit
[roojs1] / Roo / bootstrap / form / HtmlEditorToolbar / Context.js
1   
2 /**
3  * @class Roo.bootstrap.form.HtmlEditorToolbar.Context
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         {
15             xtyle: 'Standard',
16             disable : { fonts: 1 , format: 1, ..., ... , ...],
17             btns : [ .... ]
18         },
19         {
20             xtyle : 'Context',
21             ....
22         }
23     }
24      
25  * 
26  * 
27  */
28  
29 Roo.bootstrap.form.HtmlEditorToolbar.Context = function(config)
30 {
31     
32     Roo.apply(this, config);
33     
34     
35     Roo.bootstrap.form.HtmlEditorToolbar.Context.superclass.constructor.call(this, config);
36     
37     this.editor = config.editor;
38     this.editorcore = config.editor.editorcore;
39     
40     this.buttons   = new Roo.util.MixedCollection(false, function(o) { return o.cmd; });
41     
42 }
43
44 Roo.bootstrap.form.HtmlEditorToolbar.Context.types = {
45     'IMG' : [
46         {
47             name : 'width',
48             title: "Width",
49             width: 40
50         },
51         {
52             name : 'height',
53             title: "Height",
54             width: 40
55         },
56         {
57             name : 'align',
58             title: "Align",
59             opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
60             width : 80
61             
62         },
63         {
64             name : 'border',
65             title: "Border",
66             width: 40
67         },
68         {
69             name : 'alt',
70             title: "Alt",
71             width: 120
72         },
73         {
74             name : 'src',
75             title: "Src",
76             width: 220
77         }
78         
79     ],
80     
81     /*
82     'A' : [
83         {
84             name : 'name',
85             title: "Name",
86             width: 50
87         },
88         {
89             name : 'target',
90             title: "Target",
91             width: 120
92         },
93         {
94             name : 'href',
95             title: "Href",
96             width: 220
97         } // border?
98         
99     ],
100     */
101     /*
102     'INPUT' : [
103         {
104             name : 'name',
105             title: "name",
106             width: 120
107         },
108         {
109             name : 'value',
110             title: "Value",
111             width: 120
112         },
113         {
114             name : 'width',
115             title: "Width",
116             width: 40
117         }
118     ],
119     'LABEL' : [
120          {
121             name : 'for',
122             title: "For",
123             width: 120
124         }
125     ],
126     'TEXTAREA' : [
127         {
128             name : 'name',
129             title: "name",
130             width: 120
131         },
132         {
133             name : 'rows',
134             title: "Rows",
135             width: 20
136         },
137         {
138             name : 'cols',
139             title: "Cols",
140             width: 20
141         }
142     ],
143     'SELECT' : [
144         {
145             name : 'name',
146             title: "name",
147             width: 120
148         },
149         {
150             name : 'selectoptions',
151             title: "Options",
152             width: 200
153         }
154     ],
155     
156     // should we really allow this??
157     // should this just be 
158     'BODY' : [
159         
160         {
161             name : 'title',
162             title: "Title",
163             width: 200,
164             disabled : true
165         }
166     ],
167     */
168     '*' : [
169         // empty.
170     ]
171
172 };
173
174 Roo.extend(Roo.bootstrap.form.HtmlEditorToolbar.Context, Roo.bootstrap.nav.Simplebar,  {
175     
176     editor : false,
177     editorcore : false,
178     buttons : false,
179     
180     button_groups : false, // subtoolbars...  - buttson?
181     active_group : false,
182     
183     selectedNode : false,
184     
185     onRender : function(ct, position)
186     {
187        // Roo.log("Call onRender: " + this.xtype);
188         
189         this.constructor.superclass.onRender.call(this, ct, position);
190        
191         
192          
193         
194           
195         // disable everything...
196         var ty = this.constructor.types;
197         this.button_groups = {};
198         // block toolbars are built in updateToolbar when needed.
199         for (var i in  ty) {
200             this.button_groups[i] = this.buildToolbarGroup(ty[i],i);
201         }
202         this.buildToolbarDelete();
203           this.hide();
204         // the all the btns;
205         this.editor.on('editorevent', this.updateToolbar, this);
206         
207     },
208     onFirstFocus: function() {
209        
210     },
211     
212     
213     buildToolbarGroup: function(tlist, key )
214     {
215         var editor = this.editor;
216         var editorcore = this.editorcore;
217         var tb = this;
218        
219         var ret = [];
220          
221         for (var i = 0; i < tlist.length; i++) {
222             
223             // newer versions will use xtype cfg to create menus.
224             if (typeof(tlist[i].xtype) != 'undefined') {
225                 tb[typeof(tlist[i].name)== 'undefined' ? 'add' : 'addField'](Roo.factory(tlist[i]));
226                 continue;
227             }
228             
229             var item = tlist[i];
230             ret.push(
231                 this.addxtypeChild({
232                     xtype : 'Element',
233                     xns : Roo.bootstrap,
234                     cls : 'roo-htmleditor-context-label-' + key + '-' + item.name,
235                     html : item.title
236                 })  
237             );
238             
239             // add a text entry!?
240             ret.push(
241                 this.addxtypeChild({
242                     xtype : 'Input',
243                     xns : Roo.bootstrap.form,
244                     cls : 'roo-htmleditor-context-entry-' + key + '-' + item.name,
245                     name: '-roo-edit-' + item.name,
246                     attrname : item.name,
247                     width: item.width,
248                     //allowBlank:true,
249                     value: '',
250                     listeners: {
251                         'change' : function(f, nv, ov) {
252                             tb.selectedNode.setAttribute(f.attrname, nv);
253                             editorcore.syncValue();
254                         }
255                     }
256                 })
257             );
258                 
259         }
260         // hide them all..
261         ret.forEach(function(e) {
262             e.hide();
263         });
264         ret.name = key;
265         
266         return ret;
267     },
268     buildToolbarDelete : function()
269     {
270         
271         this.addxtypeChild({
272             xtype : 'Element',
273             xns : Roo.bootstrap,
274             cls : 'roo-htmleditor-fill'
275         });
276         
277         this.deleteBtn = this.addxtypeChild({
278             size : 'sm',
279             xtype: 'Button',
280             xns: Roo.bootstrap,
281             fa: 'trash',
282             listeners : {
283                 click : this.onDelete.createDelegate(this)
284             }
285         });
286         this.deleteBtn.hide();     
287         
288     },
289     
290     
291     onDelete : function()
292     {
293         var range = this.editorcore.createRange();
294         var selection = this.editorcore.getSelection();
295         var sn = this.selectedNode;
296         range.setStart(sn,0);
297         range.setEnd(sn,0); 
298         
299         
300         if (sn.hasAttribute('data-block')) {
301             var block = Roo.htmleditor.Block.factory(tb.selectedNode);
302             if (block) {
303                 block.removeNode();
304                 selection.removeAllRanges();
305                 selection.addRange(range);
306                 this.updateToolbar(null, null, null);
307             }   
308              
309         }
310         if (!sn) {
311             return; // should not really happen..
312         }
313         if (sn && sn.tagName == 'BODY') {
314             return;
315         }
316         var stn =  sn.childNodes[0] || sn.nextSibling || sn.previousSibling || sn.parentNode;
317         
318         // remove and keep parents.
319         a = new Roo.htmleditor.FilterKeepChildren({tag : false});
320         a.replaceTag(sn);
321         
322         selection.removeAllRanges();
323         selection.addRange(range);
324         this.editorcore.fireEditorEvent(false);
325         
326         
327     },
328     /**
329      * Protected method that will not generally be called directly. It triggers
330      * a toolbar update by reading the markup state of the current selection in the editor.
331      *
332      * Note you can force an update by calling on('editorevent', scope, false)
333      */
334     updateToolbar: function(editor ,ev, sel)
335     {
336         var ty = this.constructor.types;
337         
338         
339         if (ev) {
340             ev.stopEvent(); // se if we can stop this looping with mutiple events.
341         }
342         
343          
344         // capture mouse up - this is handy for selecting images..
345         // perhaps should go somewhere else...
346         if(!this.editorcore.activated){
347             this.editor.onFirstFocus();
348             return;
349         }
350         //Roo.log(ev ? ev.target : 'NOTARGET');
351         
352         
353         // http://developer.yahoo.com/yui/docs/simple-editor.js.html
354         // selectNode - might want to handle IE?
355          
356         if (ev &&
357             (ev.type == 'mouseup' || ev.type == 'click' ) &&
358             ev.target && ev.target.tagName != 'BODY' ) { // && ev.target.tagName == 'IMG') {
359             // they have click on an image...
360             // let's see if we can change the selection...
361             sel = ev.target;
362            
363              
364         }
365         
366         // this forces an id..
367         Array.from(this.editorcore.doc.body.querySelectorAll('.roo-ed-selection')).forEach(function(e) {
368             e.classList.remove('roo-ed-selection');
369         });
370           
371         var ans = this.editorcore.getAllAncestors();
372         
373                
374         if (!sel) { 
375             sel = ans.length ? (ans[0] ?  ans[0]  : ans[1]) : this.editorcore.doc.body;
376             sel = sel ? sel : this.editorcore.doc.body;
377             sel = sel.tagName.length ? sel : this.editorcore.doc.body;
378             
379         }
380         
381         var tn = sel.tagName.toUpperCase();
382         var lastSel = this.selectedNode;
383         this.selectedNode = sel;
384          
385         // ok see if we are editing a block?
386         
387         var db = false;
388         // you are not actually selecting the block.
389         if (sel && sel.hasAttribute('data-block')) {
390             db = sel;
391         } else if (sel && sel.closest('[data-block]')) {
392             
393             db = sel.closest('[data-block]');
394              
395         }
396         
397        
398         var block = false;
399         if (db && this.editorcore.enableBlocks) {
400             block = Roo.htmleditor.Block.factory(db);
401             
402             
403             if (block) {
404                 db.className = (
405                         db.classList.length > 0  ? db.className + ' ' : ''
406                     )  + 'roo-ed-selection';
407                  
408                  // since we removed it earlier... its not there..
409                 tn = 'BLOCK.' + db.getAttribute('data-block');
410                 
411                 //this.editorcore.selectNode(db);
412                 if (typeof(this.button_groups[tn]) == 'undefined') {
413                    this.button_groups[tn] = this.buildBlockToolbar( block );
414                 }
415                 this.selectedNode = db;
416                
417                  
418             }
419               
420             
421         }
422         
423         
424         if ( this.active_group !== false && this.active_group.name == tn && lastSel == this.selectedNode && ev !== false) {
425             return; // no change?
426         }
427         
428         if (tn == 'BODY') {
429             this.deleteBtn.hide();
430             this.hide();
431             this.hideActiveGroup();
432             return;
433             
434         }
435         
436         
437         if (this.active_group) {
438             this.hideActiveGroup();
439         }
440         this.showActiveGroup(tn);
441         this.show();
442         this.deleteBtn.show();
443         
444     },
445     hideActiveGroup : function()
446     {
447         this.hide();
448         if (this.active_group === false) {
449             return;
450         }
451         this.active_group.forEach(function(e) {
452             e.hide();
453         });
454         this.active_group = false;
455     },
456     showActiveGroup : function(tn)
457     {
458         
459         if (typeof(this.button_groups[tn]) == 'undefined') {
460             
461             return;
462         }
463         
464         this.active_group = this.button_groups[tn];
465         
466         this.active_group.forEach(function(e) {
467             e.show();
468         });
469         
470         // update attributes
471         if (this.selectedNode.hasAttribute('data-block') ) {
472             var block = Roo.htmleditor.Block.factory(this.selectedNode);
473             this.active_group.forEach(function(e) {
474                 e.setValue(this.selectedNode.getAttribute(block[e.name]));
475             }, this);
476                 
477             return;
478             
479         }
480         // based on attributes...
481         this.active_group.forEach(function(e) {
482             if (typeof(e.attrname) == 'undefined') {
483                 return;
484             }
485              e.setValue(this.selectedNode.getAttribute(e.attrname));
486         }, this);
487         
488             
489     }
490     
491 });