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