Fix #7581 - selection of blocks
[roojs1] / Roo / bootstrap / form / HtmlEditor.js
1 /*
2  * - LGPL
3  *
4  * HtmlEditor
5  * 
6  */
7
8 /**
9  * @class Roo.bootstrap.form.HtmlEditor
10  * @extends Roo.bootstrap.form.TextArea
11  * Bootstrap HtmlEditor class
12
13  * @constructor
14  * Create a new HtmlEditor
15  * @param {Object} config The config object
16  */
17
18 Roo.bootstrap.form.HtmlEditor = function(config){
19     Roo.bootstrap.form.HtmlEditor.superclass.constructor.call(this, config);
20     if (!this.toolbars) {
21         this.toolbars = [];
22     }
23     
24     this.editorcore = new Roo.HtmlEditorCore(Roo.apply({ owner : this} , config));
25     this.addEvents({
26             /**
27              * @event initialize
28              * Fires when the editor is fully initialized (including the iframe)
29              * @param {HtmlEditor} this
30              */
31             initialize: true,
32             /**
33              * @event activate
34              * Fires when the editor is first receives the focus. Any insertion must wait
35              * until after this event.
36              * @param {HtmlEditor} this
37              */
38             activate: true,
39              /**
40              * @event beforesync
41              * Fires before the textarea is updated with content from the editor iframe. Return false
42              * to cancel the sync.
43              * @param {HtmlEditor} this
44              * @param {String} html
45              */
46             beforesync: true,
47              /**
48              * @event beforepush
49              * Fires before the iframe editor is updated with content from the textarea. Return false
50              * to cancel the push.
51              * @param {HtmlEditor} this
52              * @param {String} html
53              */
54             beforepush: true,
55              /**
56              * @event sync
57              * Fires when the textarea is updated with content from the editor iframe.
58              * @param {HtmlEditor} this
59              * @param {String} html
60              */
61             sync: true,
62              /**
63              * @event push
64              * Fires when the iframe editor is updated with content from the textarea.
65              * @param {HtmlEditor} this
66              * @param {String} html
67              */
68             push: true,
69              /**
70              * @event editmodechange
71              * Fires when the editor switches edit modes
72              * @param {HtmlEditor} this
73              * @param {Boolean} sourceEdit True if source edit, false if standard editing.
74              */
75             editmodechange: true,
76             /**
77              * @event editorevent
78              * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
79              * @param {HtmlEditor} this
80              */
81             editorevent: true,
82             /**
83              * @event firstfocus
84              * Fires when on first focus - needed by toolbars..
85              * @param {HtmlEditor} this
86              */
87             firstfocus: true,
88             /**
89              * @event autosave
90              * Auto save the htmlEditor value as a file into Events
91              * @param {HtmlEditor} this
92              */
93             autosave: true,
94             /**
95              * @event savedpreview
96              * preview the saved version of htmlEditor
97              * @param {HtmlEditor} this
98              */
99             savedpreview: true
100         });
101 };
102
103
104 Roo.extend(Roo.bootstrap.form.HtmlEditor, Roo.bootstrap.form.TextArea,  {
105     
106     
107       /**
108      * @cfg {Array|boolean} toolbars Array of toolbars, or names of toolbars. - true for standard, and false for none.
109      */
110     toolbars : true,
111     
112      /**
113     * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
114     */
115     btns : [],
116    
117      /**
118      * @cfg {String} resize  (none|both|horizontal|vertical) - css resize of element
119      */
120     resize : false,
121      /**
122      * @cfg {Number} height (in pixels)
123      */   
124     height: 300,
125    /**
126      * @cfg {Number} width (in pixels)
127      */   
128     width: false,
129     
130     /**
131      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
132      * 
133      */
134     stylesheets: false,
135     
136     // id of frame..
137     frameId: false,
138     
139     // private properties
140     validationEvent : false,
141     deferHeight: true,
142     initialized : false,
143     activated : false,
144     
145     onFocus : Roo.emptyFn,
146     iframePad:3,
147     hideMode:'offsets',
148     
149     tbContainer : false,
150     
151     bodyCls : '',
152     
153     toolbarContainer :function() {
154         return this.wrap.select('.x-html-editor-tb',true).first();
155     },
156
157     /**
158      * Protected method that will not generally be called directly. It
159      * is called when the editor creates its toolbar. Override this method if you need to
160      * add custom toolbar buttons.
161      * @param {HtmlEditor} editor
162      */
163     createToolbar : function()
164     {
165         //Roo.log('renewing');
166         //Roo.log("create toolbars");
167         if (this.toolbars === false) {
168             return;
169         }
170         if (this.toolbars === true) {
171             this.toolbars = [ 'Standard' ];
172         }
173         
174         var ar = Array.from(this.toolbars);
175         this.toolbars = [];
176         ar.forEach(function(t,i) {
177             if (typeof(t) == 'string') {
178                 t = {
179                     xtype : t
180                 };
181             }
182             if (typeof(t) == 'object' && typeof(t.xtype) == 'string') {
183                 t.editor = this;
184                 t.xns = t.xns || Roo.bootstrap.form.HtmlEditorToolbar;
185                 t = Roo.factory(t);
186             }
187             this.toolbars[i] = t;
188             this.toolbars[i].render(this.toolbarContainer());
189         }, this);
190         
191         
192     },
193
194      
195     // private
196     onRender : function(ct, position)
197     {
198        // Roo.log("Call onRender: " + this.xtype);
199         var _t = this;
200         Roo.bootstrap.form.HtmlEditor.superclass.onRender.call(this, ct, position);
201       
202         this.wrap = this.inputEl().wrap({
203             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
204         });
205         
206         this.editorcore.onRender(ct, position);
207          
208          
209         this.createToolbar(this);
210        
211         
212           
213         
214     },
215
216     // private
217     onResize : function(w, h)
218     {
219         Roo.log('resize: ' +w + ',' + h );
220         Roo.bootstrap.form.HtmlEditor.superclass.onResize.apply(this, arguments);
221         var ew = false;
222         var eh = false;
223         
224         if(this.inputEl() ){
225             if(typeof w == 'number'){
226                 var aw = w - this.wrap.getFrameWidth('lr');
227                 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
228                 ew = aw;
229             }
230             if(typeof h == 'number'){
231                  var tbh = -11;  // fixme it needs to tool bar size!
232                 for (var i =0; i < this.toolbars.length;i++) {
233                     // fixme - ask toolbars for heights?
234                     tbh += this.toolbars[i].el.getHeight();
235                     //if (this.toolbars[i].footer) {
236                     //    tbh += this.toolbars[i].footer.el.getHeight();
237                     //}
238                 }
239               
240                 
241                 
242                 
243                 
244                 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
245                 ah -= 5; // knock a few pixes off for look..
246                 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
247                 var eh = ah;
248             }
249         }
250         Roo.log('onResize:' + [w,h,ew,eh].join(',') );
251         this.editorcore.onResize(ew,eh);
252         
253     },
254
255     /**
256      * Toggles the editor between standard and source edit mode.
257      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
258      */
259     toggleSourceEdit : function(sourceEditMode)
260     {
261         this.editorcore.toggleSourceEdit(sourceEditMode);
262         
263         if(this.editorcore.sourceEditMode){
264             Roo.log('editor - showing textarea');
265             
266 //            Roo.log('in');
267 //            Roo.log(this.syncValue());
268             this.syncValue();
269             this.inputEl().removeClass(['hide', 'x-hidden']);
270             this.inputEl().dom.removeAttribute('tabIndex');
271             this.inputEl().focus();
272         }else{
273             Roo.log('editor - hiding textarea');
274 //            Roo.log('out')
275 //            Roo.log(this.pushValue()); 
276             this.pushValue();
277             
278             this.inputEl().addClass(['hide', 'x-hidden']);
279             this.inputEl().dom.setAttribute('tabIndex', -1);
280             //this.deferFocus();
281         }
282          
283         //if(this.resizable){
284         //    this.setSize(this.wrap.getSize());
285         //}
286         
287         this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
288     },
289  
290     // private (for BoxComponent)
291     adjustSize : Roo.BoxComponent.prototype.adjustSize,
292
293     // private (for BoxComponent)
294     getResizeEl : function(){
295         return this.wrap;
296     },
297
298     // private (for BoxComponent)
299     getPositionEl : function(){
300         return this.wrap;
301     },
302
303     // private
304     initEvents : function(){
305         this.originalValue = this.getValue();
306     },
307
308 //    /**
309 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
310 //     * @method
311 //     */
312 //    markInvalid : Roo.emptyFn,
313 //    /**
314 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
315 //     * @method
316 //     */
317 //    clearInvalid : Roo.emptyFn,
318
319     setValue : function(v){
320         Roo.bootstrap.form.HtmlEditor.superclass.setValue.call(this, v);
321         this.editorcore.pushValue();
322     },
323
324      
325     // private
326     deferFocus : function(){
327         this.focus.defer(10, this);
328     },
329
330     // doc'ed in Field
331     focus : function(){
332         this.editorcore.focus();
333         
334     },
335       
336
337     // private
338     onDestroy : function(){
339         
340         
341         
342         if(this.rendered){
343             
344             for (var i =0; i < this.toolbars.length;i++) {
345                 // fixme - ask toolbars for heights?
346                 this.toolbars[i].onDestroy();
347             }
348             
349             this.wrap.dom.innerHTML = '';
350             this.wrap.remove();
351         }
352     },
353
354     // private
355     onFirstFocus : function(){
356         //Roo.log("onFirstFocus");
357         this.editorcore.onFirstFocus();
358          for (var i =0; i < this.toolbars.length;i++) {
359             this.toolbars[i].onFirstFocus();
360         }
361         
362     },
363     
364     // private
365     syncValue : function()
366     {   
367         this.editorcore.syncValue();
368     },
369     
370     pushValue : function()
371     {   
372         this.editorcore.pushValue();
373     }
374      
375     
376     // hide stuff that is not compatible
377     /**
378      * @event blur
379      * @hide
380      */
381     /**
382      * @event change
383      * @hide
384      */
385     /**
386      * @event focus
387      * @hide
388      */
389     /**
390      * @event specialkey
391      * @hide
392      */
393     /**
394      * @cfg {String} fieldClass @hide
395      */
396     /**
397      * @cfg {String} focusClass @hide
398      */
399     /**
400      * @cfg {String} autoCreate @hide
401      */
402     /**
403      * @cfg {String} inputType @hide
404      */
405      
406     /**
407      * @cfg {String} invalidText @hide
408      */
409     /**
410      * @cfg {String} msgFx @hide
411      */
412     /**
413      * @cfg {String} validateOnBlur @hide
414      */
415 });
416  
417     
418    
419    
420    
421