roojs-bootstrap.js
[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             * @event stylesheetsclick
102             * Fires when press the Sytlesheets button
103             * @param {Roo.HtmlEditorCore} this
104             */
105             stylesheetsclick: true,
106             /**
107             * @event paste
108             * Fires when press user pastes into the editor
109             * @param {Roo.HtmlEditorCore} this
110             */
111             paste: true,
112             /**
113             * @event imageadd
114             * Fires when on any editor when an image is added (excluding paste)
115             * @param {Roo.HtmlEditorCore} this
116             */
117            imageadd: true ,
118             /**
119             * @event imagedelete
120             * Fires when on any editor when an image is deleted
121             * @param {Roo.HtmlEditorCore} this
122             */
123            imagedelete: true  
124         });
125 };
126
127
128 Roo.extend(Roo.bootstrap.form.HtmlEditor, Roo.bootstrap.form.TextArea,  {
129     
130     
131       /**
132      * @cfg {Array|boolean} toolbars Array of toolbars, or names of toolbars. - true for standard, and false for none.
133      */
134     toolbars : true,
135     
136      /**
137     * @cfg {Array} buttons Array of toolbar's buttons. - defaults to empty
138     */
139     btns : [],
140    
141      /**
142      * @cfg {String} resize  (none|both|horizontal|vertical) - css resize of element
143      */
144     resize : false,
145      /**
146      * @cfg {Number} height (in pixels)
147      */   
148     height: 300,
149    /**
150      * @cfg {Number} width (in pixels)
151      */   
152     width: false,
153     
154     /**
155      * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
156      * 
157      */
158     stylesheets: false,
159     
160     // id of frame..
161     frameId: false,
162     
163     // private properties
164     validationEvent : false,
165     deferHeight: true,
166     initialized : false,
167     activated : false,
168     
169     onFocus : Roo.emptyFn,
170     iframePad:3,
171     hideMode:'offsets',
172     
173     tbContainer : false,
174     
175     bodyCls : '',
176     
177     toolbarContainer :function() {
178         return this.wrap.select('.x-html-editor-tb',true).first();
179     },
180
181     /**
182      * Protected method that will not generally be called directly. It
183      * is called when the editor creates its toolbar. Override this method if you need to
184      * add custom toolbar buttons.
185      * @param {HtmlEditor} editor
186      */
187     createToolbar : function()
188     {
189         //Roo.log('renewing');
190         //Roo.log("create toolbars");
191         if (this.toolbars === false) {
192             return;
193         }
194         if (this.toolbars === true) {
195             this.toolbars = [ 'Standard' ];
196         }
197         
198         var ar = Array.from(this.toolbars);
199         this.toolbars = [];
200         ar.forEach(function(t,i) {
201             if (typeof(t) == 'string') {
202                 t = {
203                     xtype : t
204                 };
205             }
206             if (typeof(t) == 'object' && typeof(t.xtype) == 'string') {
207                 t.editor = this;
208                 t.xns = t.xns || Roo.bootstrap.form.HtmlEditorToolbar;
209                 t = Roo.factory(t);
210             }
211             this.toolbars[i] = t;
212             this.toolbars[i].render(this.toolbarContainer());
213         }, this);
214         
215         
216     },
217
218      
219     // private
220     onRender : function(ct, position)
221     {
222        // Roo.log("Call onRender: " + this.xtype);
223         var _t = this;
224         Roo.bootstrap.form.HtmlEditor.superclass.onRender.call(this, ct, position);
225       
226         this.wrap = this.inputEl().wrap({
227             cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
228         });
229         
230         this.editorcore.onRender(ct, position);
231          
232          
233         this.createToolbar(this);
234        
235         
236           
237         
238     },
239
240     // private
241     onResize : function(w, h)
242     {
243         Roo.log('resize: ' +w + ',' + h );
244         Roo.bootstrap.form.HtmlEditor.superclass.onResize.apply(this, arguments);
245         var ew = false;
246         var eh = false;
247         
248         if(this.inputEl() ){
249             if(typeof w == 'number'){
250                 var aw = w - this.wrap.getFrameWidth('lr');
251                 this.inputEl().setWidth(this.adjustWidth('textarea', aw));
252                 ew = aw;
253             }
254             if(typeof h == 'number'){
255                  var tbh = -11;  // fixme it needs to tool bar size!
256                 for (var i =0; i < this.toolbars.length;i++) {
257                     // fixme - ask toolbars for heights?
258                     tbh += this.toolbars[i].el.getHeight();
259                     //if (this.toolbars[i].footer) {
260                     //    tbh += this.toolbars[i].footer.el.getHeight();
261                     //}
262                 }
263               
264                 
265                 
266                 
267                 
268                 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
269                 ah -= 5; // knock a few pixes off for look..
270                 this.inputEl().setHeight(this.adjustWidth('textarea', ah));
271                 var eh = ah;
272             }
273         }
274         Roo.log('onResize:' + [w,h,ew,eh].join(',') );
275         this.editorcore.onResize(ew,eh);
276         
277     },
278
279     /**
280      * Toggles the editor between standard and source edit mode.
281      * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
282      */
283     toggleSourceEdit : function(sourceEditMode)
284     {
285         this.editorcore.toggleSourceEdit(sourceEditMode);
286         
287         if(this.editorcore.sourceEditMode){
288             Roo.log('editor - showing textarea');
289             
290 //            Roo.log('in');
291 //            Roo.log(this.syncValue());
292             this.syncValue();
293             this.inputEl().removeClass(['hide', 'x-hidden']);
294             this.inputEl().dom.removeAttribute('tabIndex');
295             this.inputEl().focus();
296         }else{
297             Roo.log('editor - hiding textarea');
298 //            Roo.log('out')
299 //            Roo.log(this.pushValue()); 
300             this.pushValue();
301             
302             this.inputEl().addClass(['hide', 'x-hidden']);
303             this.inputEl().dom.setAttribute('tabIndex', -1);
304             //this.deferFocus();
305         }
306          
307         //if(this.resizable){
308         //    this.setSize(this.wrap.getSize());
309         //}
310         
311         this.fireEvent('editmodechange', this, this.editorcore.sourceEditMode);
312     },
313  
314     // private (for BoxComponent)
315     adjustSize : Roo.BoxComponent.prototype.adjustSize,
316
317     // private (for BoxComponent)
318     getResizeEl : function(){
319         return this.wrap;
320     },
321
322     // private (for BoxComponent)
323     getPositionEl : function(){
324         return this.wrap;
325     },
326
327     // private
328     initEvents : function(){
329         this.originalValue = this.getValue();
330     },
331
332 //    /**
333 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
334 //     * @method
335 //     */
336 //    markInvalid : Roo.emptyFn,
337 //    /**
338 //     * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
339 //     * @method
340 //     */
341 //    clearInvalid : Roo.emptyFn,
342
343     setValue : function(v){
344         Roo.bootstrap.form.HtmlEditor.superclass.setValue.call(this, v);
345         this.editorcore.pushValue();
346     },
347
348      
349     // private
350     deferFocus : function(){
351         this.focus.defer(10, this);
352     },
353
354     // doc'ed in Field
355     focus : function(){
356         this.editorcore.focus();
357         
358     },
359       
360
361     // private
362     onDestroy : function(){
363         
364         
365         
366         if(this.rendered){
367             
368             for (var i =0; i < this.toolbars.length;i++) {
369                 // fixme - ask toolbars for heights?
370                 this.toolbars[i].onDestroy();
371             }
372             
373             this.wrap.dom.innerHTML = '';
374             this.wrap.remove();
375         }
376     },
377
378     // private
379     onFirstFocus : function(){
380         //Roo.log("onFirstFocus");
381         this.editorcore.onFirstFocus();
382          for (var i =0; i < this.toolbars.length;i++) {
383             this.toolbars[i].onFirstFocus();
384         }
385         
386     },
387     
388     // private
389     syncValue : function()
390     {   
391         this.editorcore.syncValue();
392     },
393     
394     pushValue : function()
395     {   
396         this.editorcore.pushValue();
397     }
398      
399     
400     // hide stuff that is not compatible
401     /**
402      * @event blur
403      * @hide
404      */
405     /**
406      * @event change
407      * @hide
408      */
409     /**
410      * @event focus
411      * @hide
412      */
413     /**
414      * @event specialkey
415      * @hide
416      */
417     /**
418      * @cfg {String} fieldClass @hide
419      */
420     /**
421      * @cfg {String} focusClass @hide
422      */
423     /**
424      * @cfg {String} autoCreate @hide
425      */
426     /**
427      * @cfg {String} inputType @hide
428      */
429      
430     /**
431      * @cfg {String} invalidText @hide
432      */
433     /**
434      * @cfg {String} msgFx @hide
435      */
436     /**
437      * @cfg {String} validateOnBlur @hide
438      */
439 });
440  
441     
442    
443    
444    
445