]> scripts.mit.edu Git - autoinstallsdev/wordpress.git/blob - wp-includes/js/tinymce/themes/modern/theme.js
WordPress 4.3.1
[autoinstallsdev/wordpress.git] / wp-includes / js / tinymce / themes / modern / theme.js
1 /**
2  * theme.js
3  *
4  * Released under LGPL License.
5  * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
6  *
7  * License: http://www.tinymce.com/license
8  * Contributing: http://www.tinymce.com/contributing
9  */
10
11 /*global tinymce:true */
12
13 tinymce.ThemeManager.add('modern', function(editor) {
14         var self = this, settings = editor.settings, Factory = tinymce.ui.Factory,
15                 each = tinymce.each, DOM = tinymce.DOM, Rect = tinymce.ui.Rect, FloatPanel = tinymce.ui.FloatPanel;
16
17         // Default menus
18         var defaultMenus = {
19                 file: {title: 'File', items: 'newdocument'},
20                 edit: {title: 'Edit', items: 'undo redo | cut copy paste pastetext | selectall'},
21                 insert: {title: 'Insert', items: '|'},
22                 view: {title: 'View', items: 'visualaid |'},
23                 format: {title: 'Format', items: 'bold italic underline strikethrough superscript subscript | formats | removeformat'},
24                 table: {title: 'Table'},
25                 tools: {title: 'Tools'}
26         };
27
28         var defaultToolbar = "undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | " +
29                 "bullist numlist outdent indent | link image";
30
31         function createToolbar(items, size) {
32                 var toolbarItems = [], buttonGroup;
33
34                 if (!items) {
35                         return;
36                 }
37
38                 each(items.split(/[ ,]/), function(item) {
39                         var itemName;
40
41                         function bindSelectorChanged() {
42                                 var selection = editor.selection;
43
44                                 if (itemName == "bullist") {
45                                         selection.selectorChanged('ul > li', function(state, args) {
46                                                 var nodeName, i = args.parents.length;
47
48                                                 while (i--) {
49                                                         nodeName = args.parents[i].nodeName;
50                                                         if (nodeName == "OL" || nodeName == "UL") {
51                                                                 break;
52                                                         }
53                                                 }
54
55                                                 item.active(state && nodeName == "UL");
56                                         });
57                                 }
58
59                                 if (itemName == "numlist") {
60                                         selection.selectorChanged('ol > li', function(state, args) {
61                                                 var nodeName, i = args.parents.length;
62
63                                                 while (i--) {
64                                                         nodeName = args.parents[i].nodeName;
65                                                         if (nodeName == "OL" || nodeName == "UL") {
66                                                                 break;
67                                                         }
68                                                 }
69
70                                                 item.active(state && nodeName == "OL");
71                                         });
72                                 }
73
74                                 if (item.settings.stateSelector) {
75                                         selection.selectorChanged(item.settings.stateSelector, function(state) {
76                                                 item.active(state);
77                                         }, true);
78                                 }
79
80                                 if (item.settings.disabledStateSelector) {
81                                         selection.selectorChanged(item.settings.disabledStateSelector, function(state) {
82                                                 item.disabled(state);
83                                         });
84                                 }
85                         }
86
87                         if (item == "|") {
88                                 buttonGroup = null;
89                         } else {
90                                 if (Factory.has(item)) {
91                                         item = {type: item, size: size};
92                                         toolbarItems.push(item);
93                                         buttonGroup = null;
94                                 } else {
95                                         if (!buttonGroup) {
96                                                 buttonGroup = {type: 'buttongroup', items: []};
97                                                 toolbarItems.push(buttonGroup);
98                                         }
99
100                                         if (editor.buttons[item]) {
101                                                 // TODO: Move control creation to some UI class
102                                                 itemName = item;
103                                                 item = editor.buttons[itemName];
104
105                                                 if (typeof item == "function") {
106                                                         item = item();
107                                                 }
108
109                                                 item.type = item.type || 'button';
110                                                 item.size = size;
111
112                                                 item = Factory.create(item);
113                                                 buttonGroup.items.push(item);
114
115                                                 if (editor.initialized) {
116                                                         bindSelectorChanged();
117                                                 } else {
118                                                         editor.on('init', bindSelectorChanged);
119                                                 }
120                                         }
121                                 }
122                         }
123                 });
124
125                 return {
126                         type: 'toolbar',
127                         layout: 'flow',
128                         items: toolbarItems
129                 };
130         }
131
132         /**
133          * Creates the toolbars from config and returns a toolbar array.
134          *
135          * @param {String} size Optional toolbar item size.
136          * @return {Array} Array with toolbars.
137          */
138         function createToolbars(size) {
139                 var toolbars = [];
140
141                 function addToolbar(items) {
142                         if (items) {
143                                 toolbars.push(createToolbar(items, size));
144                                 return true;
145                         }
146                 }
147
148                 // Convert toolbar array to multiple options
149                 if (tinymce.isArray(settings.toolbar)) {
150                         // Empty toolbar array is the same as a disabled toolbar
151                         if (settings.toolbar.length === 0) {
152                                 return;
153                         }
154
155                         tinymce.each(settings.toolbar, function(toolbar, i) {
156                                 settings["toolbar" + (i + 1)] = toolbar;
157                         });
158
159                         delete settings.toolbar;
160                 }
161
162                 // Generate toolbar<n>
163                 for (var i = 1; i < 10; i++) {
164                         if (!addToolbar(settings["toolbar" + i])) {
165                                 break;
166                         }
167                 }
168
169                 // Generate toolbar or default toolbar unless it's disabled
170                 if (!toolbars.length && settings.toolbar !== false) {
171                         addToolbar(settings.toolbar || defaultToolbar);
172                 }
173
174                 if (toolbars.length) {
175                         return {
176                                 type: 'panel',
177                                 layout: 'stack',
178                                 classes: "toolbar-grp",
179                                 ariaRoot: true,
180                                 ariaRemember: true,
181                                 items: toolbars
182                         };
183                 }
184         }
185
186         /**
187          * Creates the menu buttons based on config.
188          *
189          * @return {Array} Menu buttons array.
190          */
191         function createMenuButtons() {
192                 var name, menuButtons = [];
193
194                 function createMenuItem(name) {
195                         var menuItem;
196
197                         if (name == '|') {
198                                 return {text: '|'};
199                         }
200
201                         menuItem = editor.menuItems[name];
202
203                         return menuItem;
204                 }
205
206                 function createMenu(context) {
207                         var menuButton, menu, menuItems, isUserDefined, removedMenuItems;
208
209                         removedMenuItems = tinymce.makeMap((settings.removed_menuitems || '').split(/[ ,]/));
210
211                         // User defined menu
212                         if (settings.menu) {
213                                 menu = settings.menu[context];
214                                 isUserDefined = true;
215                         } else {
216                                 menu = defaultMenus[context];
217                         }
218
219                         if (menu) {
220                                 menuButton = {text: menu.title};
221                                 menuItems = [];
222
223                                 // Default/user defined items
224                                 each((menu.items || '').split(/[ ,]/), function(item) {
225                                         var menuItem = createMenuItem(item);
226
227                                         if (menuItem && !removedMenuItems[item]) {
228                                                 menuItems.push(createMenuItem(item));
229                                         }
230                                 });
231
232                                 // Added though context
233                                 if (!isUserDefined) {
234                                         each(editor.menuItems, function(menuItem) {
235                                                 if (menuItem.context == context) {
236                                                         if (menuItem.separator == 'before') {
237                                                                 menuItems.push({text: '|'});
238                                                         }
239
240                                                         if (menuItem.prependToContext) {
241                                                                 menuItems.unshift(menuItem);
242                                                         } else {
243                                                                 menuItems.push(menuItem);
244                                                         }
245
246                                                         if (menuItem.separator == 'after') {
247                                                                 menuItems.push({text: '|'});
248                                                         }
249                                                 }
250                                         });
251                                 }
252
253                                 for (var i = 0; i < menuItems.length; i++) {
254                                         if (menuItems[i].text == '|') {
255                                                 if (i === 0 || i == menuItems.length - 1) {
256                                                         menuItems.splice(i, 1);
257                                                 }
258                                         }
259                                 }
260
261                                 menuButton.menu = menuItems;
262
263                                 if (!menuButton.menu.length) {
264                                         return null;
265                                 }
266                         }
267
268                         return menuButton;
269                 }
270
271                 var defaultMenuBar = [];
272                 if (settings.menu) {
273                         for (name in settings.menu) {
274                                 defaultMenuBar.push(name);
275                         }
276                 } else {
277                         for (name in defaultMenus) {
278                                 defaultMenuBar.push(name);
279                         }
280                 }
281
282                 var enabledMenuNames = typeof settings.menubar == "string" ? settings.menubar.split(/[ ,]/) : defaultMenuBar;
283                 for (var i = 0; i < enabledMenuNames.length; i++) {
284                         var menu = enabledMenuNames[i];
285                         menu = createMenu(menu);
286
287                         if (menu) {
288                                 menuButtons.push(menu);
289                         }
290                 }
291
292                 return menuButtons;
293         }
294
295         /**
296          * Adds accessibility shortcut keys to panel.
297          *
298          * @param {tinymce.ui.Panel} panel Panel to add focus to.
299          */
300         function addAccessibilityKeys(panel) {
301                 function focus(type) {
302                         var item = panel.find(type)[0];
303
304                         if (item) {
305                                 item.focus(true);
306                         }
307                 }
308
309                 editor.shortcuts.add('Alt+F9', '', function() {
310                         focus('menubar');
311                 });
312
313                 editor.shortcuts.add('Alt+F10', '', function() {
314                         focus('toolbar');
315                 });
316
317                 editor.shortcuts.add('Alt+F11', '', function() {
318                         focus('elementpath');
319                 });
320
321                 panel.on('cancel', function() {
322                         editor.focus();
323                 });
324         }
325
326         /**
327          * Resizes the editor to the specified width, height.
328          */
329         function resizeTo(width, height) {
330                 var containerElm, iframeElm, containerSize, iframeSize;
331
332                 function getSize(elm) {
333                         return {
334                                 width: elm.clientWidth,
335                                 height: elm.clientHeight
336                         };
337                 }
338
339                 containerElm = editor.getContainer();
340                 iframeElm = editor.getContentAreaContainer().firstChild;
341                 containerSize = getSize(containerElm);
342                 iframeSize = getSize(iframeElm);
343
344                 if (width !== null) {
345                         width = Math.max(settings.min_width || 100, width);
346                         width = Math.min(settings.max_width || 0xFFFF, width);
347
348                         DOM.setStyle(containerElm, 'width', width + (containerSize.width - iframeSize.width));
349                         DOM.setStyle(iframeElm, 'width', width);
350                 }
351
352                 height = Math.max(settings.min_height || 100, height);
353                 height = Math.min(settings.max_height || 0xFFFF, height);
354                 DOM.setStyle(iframeElm, 'height', height);
355
356                 editor.fire('ResizeEditor');
357         }
358
359         function resizeBy(dw, dh) {
360                 var elm = editor.getContentAreaContainer();
361                 self.resizeTo(elm.clientWidth + dw, elm.clientHeight + dh);
362         }
363
364         /**
365          * Handles contextual toolbars.
366          */
367         function addContextualToolbars() {
368                 var scrollContainer;
369
370                 function getContextToolbars() {
371                         return editor.contextToolbars || [];
372                 }
373
374                 function getElementRect(elm) {
375                         var pos, targetRect, root;
376
377                         pos = tinymce.DOM.getPos(editor.getContentAreaContainer());
378                         targetRect = editor.dom.getRect(elm);
379                         root = editor.dom.getRoot();
380
381                         // Adjust targetPos for scrolling in the editor
382                         if (root.nodeName == 'BODY') {
383                                 targetRect.x -= root.ownerDocument.documentElement.scrollLeft || root.scrollLeft;
384                                 targetRect.y -= root.ownerDocument.documentElement.scrollTop || root.scrollTop;
385                         }
386
387                         targetRect.x += pos.x;
388                         targetRect.y += pos.y;
389
390                         return targetRect;
391                 }
392
393                 function hideAllFloatingPanels() {
394                         each(editor.contextToolbars, function(toolbar) {
395                                 if (toolbar.panel) {
396                                         toolbar.panel.hide();
397                                 }
398                         });
399                 }
400
401                 function reposition(match) {
402                         var relPos, panelRect, elementRect, contentAreaRect, panel, relRect, testPositions;
403
404                         if (editor.removed) {
405                                 return;
406                         }
407
408                         if (!match || !match.toolbar.panel) {
409                                 hideAllFloatingPanels();
410                                 return;
411                         }
412
413                         testPositions = [
414                                 'tc-bc', 'bc-tc',
415                                 'tl-bl', 'bl-tl',
416                                 'tr-br', 'br-tr'
417                         ];
418
419                         panel = match.toolbar.panel;
420                         panel.show();
421
422                         elementRect = getElementRect(match.element);
423                         panelRect = tinymce.DOM.getRect(panel.getEl());
424                         contentAreaRect = tinymce.DOM.getRect(editor.getContentAreaContainer() || editor.getBody());
425
426                         if (!editor.inline) {
427                                 contentAreaRect.w = editor.getDoc().documentElement.offsetWidth;
428                         }
429
430                         // Inflate the elementRect so it doesn't get placed above resize handles
431                         if (editor.selection.controlSelection.isResizable(match.element)) {
432                                 elementRect = Rect.inflate(elementRect, 0, 7);
433                         }
434
435                         relPos = Rect.findBestRelativePosition(panelRect, elementRect, contentAreaRect, testPositions);
436
437                         if (relPos) {
438                                 each(testPositions.concat('inside'), function(pos) {
439                                         panel.classes.toggle('tinymce-inline-' + pos, pos == relPos);
440                                 });
441
442                                 relRect = Rect.relativePosition(panelRect, elementRect, relPos);
443                                 panel.moveTo(relRect.x, relRect.y);
444                         } else {
445                                 each(testPositions, function(pos) {
446                                         panel.classes.toggle('tinymce-inline-' + pos, false);
447                                 });
448
449                                 panel.classes.toggle('tinymce-inline-inside', true);
450
451                                 elementRect = Rect.intersect(contentAreaRect, elementRect);
452
453                                 if (elementRect) {
454                                         relPos = Rect.findBestRelativePosition(panelRect, elementRect, contentAreaRect, [
455                                                 'tc-tc', 'tl-tl', 'tr-tr'
456                                         ]);
457
458                                         if (relPos) {
459                                                 relRect = Rect.relativePosition(panelRect, elementRect, relPos);
460                                                 panel.moveTo(relRect.x, relRect.y);
461                                         } else {
462                                                 panel.moveTo(elementRect.x, elementRect.y);
463                                         }
464                                 } else {
465                                         panel.hide();
466                                 }
467                         }
468
469                         //drawRect(contentAreaRect, 'blue');
470                         //drawRect(elementRect, 'red');
471                         //drawRect(panelRect, 'green');
472                 }
473
474                 function repositionHandler() {
475                         function execute() {
476                                 if (editor.selection) {
477                                         reposition(findFrontMostMatch(editor.selection.getNode()));
478                                 }
479                         }
480
481                         if (window.requestAnimationFrame) {
482                                 window.requestAnimationFrame(execute);
483                         } else {
484                                 execute();
485                         }
486                 }
487
488                 function bindScrollEvent() {
489                         if (!scrollContainer) {
490                                 scrollContainer = editor.selection.getScrollContainer() || editor.getWin();
491                                 tinymce.$(scrollContainer).on('scroll', repositionHandler);
492
493                                 editor.on('remove', function() {
494                                         tinymce.$(scrollContainer).off('scroll');
495                                 });
496                         }
497                 }
498
499                 function showContextToolbar(match) {
500                         var panel;
501
502                         if (match.toolbar.panel) {
503                                 match.toolbar.panel.show();
504                                 reposition(match);
505                                 return;
506                         }
507
508                         bindScrollEvent();
509
510                         panel = Factory.create({
511                                 type: 'floatpanel',
512                                 role: 'application',
513                                 classes: 'tinymce tinymce-inline',
514                                 layout: 'flex',
515                                 direction: 'column',
516                                 align: 'stretch',
517                                 autohide: false,
518                                 autofix: true,
519                                 fixed: true,
520                                 border: 1,
521                                 items: createToolbar(match.toolbar.items)
522                         });
523
524                         match.toolbar.panel = panel;
525                         panel.renderTo(document.body).reflow();
526                         reposition(match);
527                 }
528
529                 function hideAllContextToolbars() {
530                         tinymce.each(getContextToolbars(), function(toolbar) {
531                                 if (toolbar.panel) {
532                                         toolbar.panel.hide();
533                                 }
534                         });
535                 }
536
537                 function findFrontMostMatch(targetElm) {
538                         var i, y, parentsAndSelf, toolbars = getContextToolbars();
539
540                         parentsAndSelf = editor.$(targetElm).parents().add(targetElm);
541                         for (i = parentsAndSelf.length - 1; i >= 0; i--) {
542                                 for (y = toolbars.length - 1; y >= 0; y--) {
543                                         if (toolbars[y].predicate(parentsAndSelf[i])) {
544                                                 return {
545                                                         toolbar: toolbars[y],
546                                                         element: parentsAndSelf[i]
547                                                 };
548                                         }
549                                 }
550                         }
551
552                         return null;
553                 }
554
555                 editor.on('click keyup blur', function() {
556                         // Needs to be delayed to avoid Chrome img focus out bug
557                         window.setTimeout(function() {
558                                 var match;
559
560                                 if (editor.removed) {
561                                         return;
562                                 }
563
564                                 match = findFrontMostMatch(editor.selection.getNode());
565                                 if (match) {
566                                         showContextToolbar(match);
567                                 } else {
568                                         hideAllContextToolbars();
569                                 }
570                         }, 0);
571                 });
572
573                 editor.on('ObjectResizeStart', function() {
574                         var match = findFrontMostMatch(editor.selection.getNode());
575
576                         if (match && match.toolbar.panel) {
577                                 match.toolbar.panel.hide();
578                         }
579                 });
580
581                 editor.on('nodeChange ResizeEditor ResizeWindow', repositionHandler);
582
583                 editor.on('remove', function() {
584                         tinymce.each(getContextToolbars(), function(toolbar) {
585                                 if (toolbar.panel) {
586                                         toolbar.panel.remove();
587                                 }
588                         });
589
590                         editor.contextToolbars = {};
591                 });
592         }
593
594         /**
595          * Renders the inline editor UI.
596          *
597          * @return {Object} Name/value object with theme data.
598          */
599         function renderInlineUI(args) {
600                 var panel, inlineToolbarContainer;
601
602                 if (settings.fixed_toolbar_container) {
603                         inlineToolbarContainer = DOM.select(settings.fixed_toolbar_container)[0];
604                 }
605
606                 function reposition() {
607                         if (panel && panel.moveRel && panel.visible() && !panel._fixed) {
608                                 // TODO: This is kind of ugly and doesn't handle multiple scrollable elements
609                                 var scrollContainer = editor.selection.getScrollContainer(), body = editor.getBody();
610                                 var deltaX = 0, deltaY = 0;
611
612                                 if (scrollContainer) {
613                                         var bodyPos = DOM.getPos(body), scrollContainerPos = DOM.getPos(scrollContainer);
614
615                                         deltaX = Math.max(0, scrollContainerPos.x - bodyPos.x);
616                                         deltaY = Math.max(0, scrollContainerPos.y - bodyPos.y);
617                                 }
618
619                                 panel.fixed(false).moveRel(body, editor.rtl ? ['tr-br', 'br-tr'] : ['tl-bl', 'bl-tl', 'tr-br']).moveBy(deltaX, deltaY);
620                         }
621                 }
622
623                 function show() {
624                         if (panel) {
625                                 panel.show();
626                                 reposition();
627                                 DOM.addClass(editor.getBody(), 'mce-edit-focus');
628                         }
629                 }
630
631                 function hide() {
632                         if (panel) {
633                                 // We require two events as the inline float panel based toolbar does not have autohide=true
634                                 panel.hide();
635
636                                 // All other autohidden float panels will be closed below.
637                                 FloatPanel.hideAll();
638
639                                 DOM.removeClass(editor.getBody(), 'mce-edit-focus');
640                         }
641                 }
642
643                 function render() {
644                         if (panel) {
645                                 if (!panel.visible()) {
646                                         show();
647                                 }
648
649                                 return;
650                         }
651
652                         // Render a plain panel inside the inlineToolbarContainer if it's defined
653                         panel = self.panel = Factory.create({
654                                 type: inlineToolbarContainer ? 'panel' : 'floatpanel',
655                                 role: 'application',
656                                 classes: 'tinymce tinymce-inline',
657                                 layout: 'flex',
658                                 direction: 'column',
659                                 align: 'stretch',
660                                 autohide: false,
661                                 autofix: true,
662                                 fixed: !!inlineToolbarContainer,
663                                 border: 1,
664                                 items: [
665                                         settings.menubar === false ? null : {type: 'menubar', border: '0 0 1 0', items: createMenuButtons()},
666                                         createToolbars(settings.toolbar_items_size)
667                                 ]
668                         });
669
670                         // Add statusbar
671                         /*if (settings.statusbar !== false) {
672                                 panel.add({type: 'panel', classes: 'statusbar', layout: 'flow', border: '1 0 0 0', items: [
673                                         {type: 'elementpath'}
674                                 ]});
675                         }*/
676
677                         editor.fire('BeforeRenderUI');
678                         panel.renderTo(inlineToolbarContainer || document.body).reflow();
679
680                         addAccessibilityKeys(panel);
681                         show();
682                         addContextualToolbars();
683
684                         editor.on('nodeChange', reposition);
685                         editor.on('activate', show);
686                         editor.on('deactivate', hide);
687
688                         editor.nodeChanged();
689                 }
690
691                 settings.content_editable = true;
692
693                 editor.on('focus', function() {
694                         // Render only when the CSS file has been loaded
695                         if (args.skinUiCss) {
696                                 tinymce.DOM.styleSheetLoader.load(args.skinUiCss, render, render);
697                         } else {
698                                 render();
699                         }
700                 });
701
702                 editor.on('blur hide', hide);
703
704                 // Remove the panel when the editor is removed
705                 editor.on('remove', function() {
706                         if (panel) {
707                                 panel.remove();
708                                 panel = null;
709                         }
710                 });
711
712                 // Preload skin css
713                 if (args.skinUiCss) {
714                         tinymce.DOM.styleSheetLoader.load(args.skinUiCss);
715                 }
716
717                 return {};
718         }
719
720         /**
721          * Renders the iframe editor UI.
722          *
723          * @param {Object} args Details about target element etc.
724          * @return {Object} Name/value object with theme data.
725          */
726         function renderIframeUI(args) {
727                 var panel, resizeHandleCtrl, startSize;
728
729                 if (args.skinUiCss) {
730                         tinymce.DOM.loadCSS(args.skinUiCss);
731                 }
732
733                 // Basic UI layout
734                 panel = self.panel = Factory.create({
735                         type: 'panel',
736                         role: 'application',
737                         classes: 'tinymce',
738                         style: 'visibility: hidden',
739                         layout: 'stack',
740                         border: 1,
741                         items: [
742                                 settings.menubar === false ? null : {type: 'menubar', border: '0 0 1 0', items: createMenuButtons()},
743                                 createToolbars(settings.toolbar_items_size),
744                                 {type: 'panel', name: 'iframe', layout: 'stack', classes: 'edit-area', html: '', border: '1 0 0 0'}
745                         ]
746                 });
747
748                 if (settings.resize !== false) {
749                         resizeHandleCtrl = {
750                                 type: 'resizehandle',
751                                 direction: settings.resize,
752
753                                 onResizeStart: function() {
754                                         var elm = editor.getContentAreaContainer().firstChild;
755
756                                         startSize = {
757                                                 width: elm.clientWidth,
758                                                 height: elm.clientHeight
759                                         };
760                                 },
761
762                                 onResize: function(e) {
763                                         if (settings.resize == 'both') {
764                                                 resizeTo(startSize.width + e.deltaX, startSize.height + e.deltaY);
765                                         } else {
766                                                 resizeTo(null, startSize.height + e.deltaY);
767                                         }
768                                 }
769                         };
770                 }
771
772                 // Add statusbar if needed
773                 if (settings.statusbar !== false) {
774                         panel.add({type: 'panel', name: 'statusbar', classes: 'statusbar', layout: 'flow', border: '1 0 0 0', ariaRoot: true, items: [
775                                 {type: 'elementpath'},
776                                 resizeHandleCtrl
777                         ]});
778                 }
779
780                 if (settings.readonly) {
781                         panel.find('*').disabled(true);
782                 }
783
784                 editor.fire('BeforeRenderUI');
785                 panel.renderBefore(args.targetNode).reflow();
786
787                 if (settings.width) {
788                         tinymce.DOM.setStyle(panel.getEl(), 'width', settings.width);
789                 }
790
791                 // Remove the panel when the editor is removed
792                 editor.on('remove', function() {
793                         panel.remove();
794                         panel = null;
795                 });
796
797                 // Add accesibility shortcuts
798                 addAccessibilityKeys(panel);
799                 addContextualToolbars();
800
801                 return {
802                         iframeContainer: panel.find('#iframe')[0].getEl(),
803                         editorContainer: panel.getEl()
804                 };
805         }
806
807         /**
808          * Renders the UI for the theme. This gets called by the editor.
809          *
810          * @param {Object} args Details about target element etc.
811          * @return {Object} Theme UI data items.
812          */
813         self.renderUI = function(args) {
814                 var skin = settings.skin !== false ? settings.skin || 'lightgray' : false;
815
816                 if (skin) {
817                         var skinUrl = settings.skin_url;
818
819                         if (skinUrl) {
820                                 skinUrl = editor.documentBaseURI.toAbsolute(skinUrl);
821                         } else {
822                                 skinUrl = tinymce.baseURL + '/skins/' + skin;
823                         }
824
825                         // Load special skin for IE7
826                         // TODO: Remove this when we drop IE7 support
827                         if (tinymce.Env.documentMode <= 7) {
828                                 args.skinUiCss = skinUrl + '/skin.ie7.min.css';
829                         } else {
830                                 args.skinUiCss = skinUrl + '/skin.min.css';
831                         }
832
833                         // Load content.min.css or content.inline.min.css
834                         editor.contentCSS.push(skinUrl + '/content' + (editor.inline ? '.inline' : '') + '.min.css');
835                 }
836
837                 // Handle editor setProgressState change
838                 editor.on('ProgressState', function(e) {
839                         self.throbber = self.throbber || new tinymce.ui.Throbber(self.panel.getEl('body'));
840
841                         if (e.state) {
842                                 self.throbber.show(e.time);
843                         } else {
844                                 self.throbber.hide();
845                         }
846                 });
847
848                 if (settings.inline) {
849                         return renderInlineUI(args);
850                 }
851
852                 return renderIframeUI(args);
853         };
854
855         self.resizeTo = resizeTo;
856         self.resizeBy = resizeBy;
857 });