mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
87f2933654
ae99a273e
updated TinyMCE from 4.3.4 to 4.3.8 directly, instead of through NPM.
This failed "npm run sanity". Updated to the latest (4.3.11) through NPM now.
934 lines
22 KiB
JavaScript
934 lines
22 KiB
JavaScript
/**
|
|
* theme.js
|
|
*
|
|
* Released under LGPL License.
|
|
* Copyright (c) 1999-2015 Ephox Corp. All rights reserved
|
|
*
|
|
* License: http://www.tinymce.com/license
|
|
* Contributing: http://www.tinymce.com/contributing
|
|
*/
|
|
|
|
/*global tinymce:true */
|
|
|
|
tinymce.ThemeManager.add('modern', function(editor) {
|
|
var self = this, settings = editor.settings, Factory = tinymce.ui.Factory,
|
|
each = tinymce.each, DOM = tinymce.DOM, Rect = tinymce.geom.Rect, FloatPanel = tinymce.ui.FloatPanel;
|
|
|
|
// Default menus
|
|
var defaultMenus = {
|
|
file: {title: 'File', items: 'newdocument'},
|
|
edit: {title: 'Edit', items: 'undo redo | cut copy paste pastetext | selectall'},
|
|
insert: {title: 'Insert', items: '|'},
|
|
view: {title: 'View', items: 'visualaid |'},
|
|
format: {title: 'Format', items: 'bold italic underline strikethrough superscript subscript | formats | removeformat'},
|
|
table: {title: 'Table'},
|
|
tools: {title: 'Tools'}
|
|
};
|
|
|
|
var defaultToolbar = "undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | " +
|
|
"bullist numlist outdent indent | link image";
|
|
|
|
function createToolbar(items, size) {
|
|
var toolbarItems = [], buttonGroup;
|
|
|
|
if (!items) {
|
|
return;
|
|
}
|
|
|
|
each(items.split(/[ ,]/), function(item) {
|
|
var itemName;
|
|
|
|
function bindSelectorChanged() {
|
|
var selection = editor.selection;
|
|
|
|
function setActiveItem(name) {
|
|
return function(state, args) {
|
|
var nodeName, i = args.parents.length;
|
|
|
|
while (i--) {
|
|
nodeName = args.parents[i].nodeName;
|
|
if (nodeName == "OL" || nodeName == "UL") {
|
|
break;
|
|
}
|
|
}
|
|
|
|
item.active(state && nodeName == name);
|
|
};
|
|
}
|
|
|
|
if (itemName == "bullist") {
|
|
selection.selectorChanged('ul > li', setActiveItem("UL"));
|
|
}
|
|
|
|
if (itemName == "numlist") {
|
|
selection.selectorChanged('ol > li', setActiveItem("OL"));
|
|
}
|
|
|
|
if (item.settings.stateSelector) {
|
|
selection.selectorChanged(item.settings.stateSelector, function(state) {
|
|
item.active(state);
|
|
}, true);
|
|
}
|
|
|
|
if (item.settings.disabledStateSelector) {
|
|
selection.selectorChanged(item.settings.disabledStateSelector, function(state) {
|
|
item.disabled(state);
|
|
});
|
|
}
|
|
}
|
|
|
|
if (item == "|") {
|
|
buttonGroup = null;
|
|
} else {
|
|
if (Factory.has(item)) {
|
|
item = {type: item, size: size};
|
|
toolbarItems.push(item);
|
|
buttonGroup = null;
|
|
} else {
|
|
if (!buttonGroup) {
|
|
buttonGroup = {type: 'buttongroup', items: []};
|
|
toolbarItems.push(buttonGroup);
|
|
}
|
|
|
|
if (editor.buttons[item]) {
|
|
// TODO: Move control creation to some UI class
|
|
itemName = item;
|
|
item = editor.buttons[itemName];
|
|
|
|
if (typeof item == "function") {
|
|
item = item();
|
|
}
|
|
|
|
item.type = item.type || 'button';
|
|
item.size = size;
|
|
|
|
item = Factory.create(item);
|
|
buttonGroup.items.push(item);
|
|
|
|
if (editor.initialized) {
|
|
bindSelectorChanged();
|
|
} else {
|
|
editor.on('init', bindSelectorChanged);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
return {
|
|
type: 'toolbar',
|
|
layout: 'flow',
|
|
items: toolbarItems
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Creates the toolbars from config and returns a toolbar array.
|
|
*
|
|
* @param {String} size Optional toolbar item size.
|
|
* @return {Array} Array with toolbars.
|
|
*/
|
|
function createToolbars(size) {
|
|
var toolbars = [];
|
|
|
|
function addToolbar(items) {
|
|
if (items) {
|
|
toolbars.push(createToolbar(items, size));
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Convert toolbar array to multiple options
|
|
if (tinymce.isArray(settings.toolbar)) {
|
|
// Empty toolbar array is the same as a disabled toolbar
|
|
if (settings.toolbar.length === 0) {
|
|
return;
|
|
}
|
|
|
|
tinymce.each(settings.toolbar, function(toolbar, i) {
|
|
settings["toolbar" + (i + 1)] = toolbar;
|
|
});
|
|
|
|
delete settings.toolbar;
|
|
}
|
|
|
|
// Generate toolbar<n>
|
|
for (var i = 1; i < 10; i++) {
|
|
if (!addToolbar(settings["toolbar" + i])) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Generate toolbar or default toolbar unless it's disabled
|
|
if (!toolbars.length && settings.toolbar !== false) {
|
|
addToolbar(settings.toolbar || defaultToolbar);
|
|
}
|
|
|
|
if (toolbars.length) {
|
|
return {
|
|
type: 'panel',
|
|
layout: 'stack',
|
|
classes: "toolbar-grp",
|
|
ariaRoot: true,
|
|
ariaRemember: true,
|
|
items: toolbars
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Creates the menu buttons based on config.
|
|
*
|
|
* @return {Array} Menu buttons array.
|
|
*/
|
|
function createMenuButtons() {
|
|
var name, menuButtons = [];
|
|
|
|
function createMenuItem(name) {
|
|
var menuItem;
|
|
|
|
if (name == '|') {
|
|
return {text: '|'};
|
|
}
|
|
|
|
menuItem = editor.menuItems[name];
|
|
|
|
return menuItem;
|
|
}
|
|
|
|
function createMenu(context) {
|
|
var menuButton, menu, menuItems, isUserDefined, removedMenuItems;
|
|
|
|
removedMenuItems = tinymce.makeMap((settings.removed_menuitems || '').split(/[ ,]/));
|
|
|
|
// User defined menu
|
|
if (settings.menu) {
|
|
menu = settings.menu[context];
|
|
isUserDefined = true;
|
|
} else {
|
|
menu = defaultMenus[context];
|
|
}
|
|
|
|
if (menu) {
|
|
menuButton = {text: menu.title};
|
|
menuItems = [];
|
|
|
|
// Default/user defined items
|
|
each((menu.items || '').split(/[ ,]/), function(item) {
|
|
var menuItem = createMenuItem(item);
|
|
|
|
if (menuItem && !removedMenuItems[item]) {
|
|
menuItems.push(createMenuItem(item));
|
|
}
|
|
});
|
|
|
|
// Added though context
|
|
if (!isUserDefined) {
|
|
each(editor.menuItems, function(menuItem) {
|
|
if (menuItem.context == context) {
|
|
if (menuItem.separator == 'before') {
|
|
menuItems.push({text: '|'});
|
|
}
|
|
|
|
if (menuItem.prependToContext) {
|
|
menuItems.unshift(menuItem);
|
|
} else {
|
|
menuItems.push(menuItem);
|
|
}
|
|
|
|
if (menuItem.separator == 'after') {
|
|
menuItems.push({text: '|'});
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
for (var i = 0; i < menuItems.length; i++) {
|
|
if (menuItems[i].text == '|') {
|
|
if (i === 0 || i == menuItems.length - 1) {
|
|
menuItems.splice(i, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
menuButton.menu = menuItems;
|
|
|
|
if (!menuButton.menu.length) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
return menuButton;
|
|
}
|
|
|
|
var defaultMenuBar = [];
|
|
if (settings.menu) {
|
|
for (name in settings.menu) {
|
|
defaultMenuBar.push(name);
|
|
}
|
|
} else {
|
|
for (name in defaultMenus) {
|
|
defaultMenuBar.push(name);
|
|
}
|
|
}
|
|
|
|
var enabledMenuNames = typeof settings.menubar == "string" ? settings.menubar.split(/[ ,]/) : defaultMenuBar;
|
|
for (var i = 0; i < enabledMenuNames.length; i++) {
|
|
var menu = enabledMenuNames[i];
|
|
menu = createMenu(menu);
|
|
|
|
if (menu) {
|
|
menuButtons.push(menu);
|
|
}
|
|
}
|
|
|
|
return menuButtons;
|
|
}
|
|
|
|
/**
|
|
* Adds accessibility shortcut keys to panel.
|
|
*
|
|
* @param {tinymce.ui.Panel} panel Panel to add focus to.
|
|
*/
|
|
function addAccessibilityKeys(panel) {
|
|
function focus(type) {
|
|
var item = panel.find(type)[0];
|
|
|
|
if (item) {
|
|
item.focus(true);
|
|
}
|
|
}
|
|
|
|
editor.shortcuts.add('Alt+F9', '', function() {
|
|
focus('menubar');
|
|
});
|
|
|
|
editor.shortcuts.add('Alt+F10', '', function() {
|
|
focus('toolbar');
|
|
});
|
|
|
|
editor.shortcuts.add('Alt+F11', '', function() {
|
|
focus('elementpath');
|
|
});
|
|
|
|
panel.on('cancel', function() {
|
|
editor.focus();
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Resizes the editor to the specified width, height.
|
|
*/
|
|
function resizeTo(width, height) {
|
|
var containerElm, iframeElm, containerSize, iframeSize;
|
|
|
|
function getSize(elm) {
|
|
return {
|
|
width: elm.clientWidth,
|
|
height: elm.clientHeight
|
|
};
|
|
}
|
|
|
|
containerElm = editor.getContainer();
|
|
iframeElm = editor.getContentAreaContainer().firstChild;
|
|
containerSize = getSize(containerElm);
|
|
iframeSize = getSize(iframeElm);
|
|
|
|
if (width !== null) {
|
|
width = Math.max(settings.min_width || 100, width);
|
|
width = Math.min(settings.max_width || 0xFFFF, width);
|
|
|
|
DOM.setStyle(containerElm, 'width', width + (containerSize.width - iframeSize.width));
|
|
DOM.setStyle(iframeElm, 'width', width);
|
|
}
|
|
|
|
height = Math.max(settings.min_height || 100, height);
|
|
height = Math.min(settings.max_height || 0xFFFF, height);
|
|
DOM.setStyle(iframeElm, 'height', height);
|
|
|
|
editor.fire('ResizeEditor');
|
|
}
|
|
|
|
function resizeBy(dw, dh) {
|
|
var elm = editor.getContentAreaContainer();
|
|
self.resizeTo(elm.clientWidth + dw, elm.clientHeight + dh);
|
|
}
|
|
|
|
/**
|
|
* Handles contextual toolbars.
|
|
*/
|
|
function addContextualToolbars() {
|
|
var scrollContainer;
|
|
|
|
function getContextToolbars() {
|
|
return editor.contextToolbars || [];
|
|
}
|
|
|
|
function getElementRect(elm) {
|
|
var pos, targetRect, root;
|
|
|
|
pos = tinymce.DOM.getPos(editor.getContentAreaContainer());
|
|
targetRect = editor.dom.getRect(elm);
|
|
root = editor.dom.getRoot();
|
|
|
|
// Adjust targetPos for scrolling in the editor
|
|
if (root.nodeName == 'BODY') {
|
|
targetRect.x -= root.ownerDocument.documentElement.scrollLeft || root.scrollLeft;
|
|
targetRect.y -= root.ownerDocument.documentElement.scrollTop || root.scrollTop;
|
|
}
|
|
|
|
targetRect.x += pos.x;
|
|
targetRect.y += pos.y;
|
|
|
|
return targetRect;
|
|
}
|
|
|
|
function hideAllFloatingPanels() {
|
|
each(editor.contextToolbars, function(toolbar) {
|
|
if (toolbar.panel) {
|
|
toolbar.panel.hide();
|
|
}
|
|
});
|
|
}
|
|
|
|
function togglePositionClass(panel, relPos, predicate) {
|
|
relPos = relPos ? relPos.substr(0, 2) : '';
|
|
|
|
each({
|
|
t: 'down',
|
|
b: 'up'
|
|
}, function(cls, pos) {
|
|
panel.classes.toggle('arrow-' + cls, predicate(pos, relPos.substr(0, 1)));
|
|
});
|
|
|
|
each({
|
|
l: 'left',
|
|
r: 'right'
|
|
}, function(cls, pos) {
|
|
panel.classes.toggle('arrow-' + cls, predicate(pos, relPos.substr(1, 1)));
|
|
});
|
|
}
|
|
|
|
function toClientRect(geomRect) {
|
|
return {
|
|
left: geomRect.x,
|
|
top: geomRect.y,
|
|
width: geomRect.w,
|
|
height: geomRect.h,
|
|
right: geomRect.x + geomRect.w,
|
|
bottom: geomRect.y + geomRect.h
|
|
};
|
|
}
|
|
|
|
function userConstrain(x, y, elementRect, contentAreaRect, panelRect) {
|
|
panelRect = toClientRect({x: x, y: y, w: panelRect.w, h: panelRect.h});
|
|
|
|
if (settings.inline_toolbar_position_handler) {
|
|
panelRect = settings.inline_toolbar_position_handler({
|
|
elementRect: toClientRect(elementRect),
|
|
contentAreaRect: toClientRect(contentAreaRect),
|
|
panelRect: panelRect
|
|
});
|
|
}
|
|
|
|
return panelRect;
|
|
}
|
|
|
|
function movePanelTo(panel, pos) {
|
|
panel.moveTo(pos.left, pos.top);
|
|
}
|
|
|
|
function reposition(match) {
|
|
var relPos, panelRect, elementRect, contentAreaRect, panel, relRect, testPositions;
|
|
|
|
if (editor.removed) {
|
|
return;
|
|
}
|
|
|
|
if (!match || !match.toolbar.panel) {
|
|
hideAllFloatingPanels();
|
|
return;
|
|
}
|
|
|
|
testPositions = [
|
|
'bc-tc', 'tc-bc',
|
|
'tl-bl', 'bl-tl',
|
|
'tr-br', 'br-tr'
|
|
];
|
|
|
|
panel = match.toolbar.panel;
|
|
panel.show();
|
|
|
|
elementRect = getElementRect(match.element);
|
|
panelRect = tinymce.DOM.getRect(panel.getEl());
|
|
contentAreaRect = tinymce.DOM.getRect(editor.getContentAreaContainer() || editor.getBody());
|
|
|
|
// We need to use these instead of the rect values since the style
|
|
// size properites might not be the same as the real size for a table
|
|
elementRect.w = match.element.clientWidth;
|
|
elementRect.h = match.element.clientHeight;
|
|
|
|
if (!editor.inline) {
|
|
contentAreaRect.w = editor.getDoc().documentElement.offsetWidth;
|
|
}
|
|
|
|
// Inflate the elementRect so it doesn't get placed above resize handles
|
|
if (editor.selection.controlSelection.isResizable(match.element)) {
|
|
elementRect = Rect.inflate(elementRect, 0, 8);
|
|
}
|
|
|
|
relPos = Rect.findBestRelativePosition(panelRect, elementRect, contentAreaRect, testPositions);
|
|
elementRect = Rect.clamp(elementRect, contentAreaRect);
|
|
|
|
if (relPos) {
|
|
relRect = Rect.relativePosition(panelRect, elementRect, relPos);
|
|
movePanelTo(panel, userConstrain(relRect.x, relRect.y, elementRect, contentAreaRect, panelRect));
|
|
} else {
|
|
// Allow overflow below the editor to avoid placing toolbars ontop of tables
|
|
contentAreaRect.h += 40;
|
|
|
|
elementRect = Rect.intersect(contentAreaRect, elementRect);
|
|
if (elementRect) {
|
|
relPos = Rect.findBestRelativePosition(panelRect, elementRect, contentAreaRect, [
|
|
'bc-tc', 'bl-tl', 'br-tr'
|
|
]);
|
|
|
|
if (relPos) {
|
|
relRect = Rect.relativePosition(panelRect, elementRect, relPos);
|
|
movePanelTo(panel, userConstrain(relRect.x, relRect.y, elementRect, contentAreaRect, panelRect));
|
|
} else {
|
|
movePanelTo(panel, userConstrain(elementRect.x, elementRect.y, elementRect, contentAreaRect, panelRect));
|
|
}
|
|
} else {
|
|
panel.hide();
|
|
}
|
|
}
|
|
|
|
togglePositionClass(panel, relPos, function(pos1, pos2) {
|
|
return (!elementRect || elementRect.w > 40) && pos1 === pos2;
|
|
});
|
|
|
|
//drawRect(contentAreaRect, 'blue');
|
|
//drawRect(elementRect, 'red');
|
|
//drawRect(panelRect, 'green');
|
|
}
|
|
|
|
function repositionHandler() {
|
|
function execute() {
|
|
if (editor.selection) {
|
|
reposition(findFrontMostMatch(editor.selection.getNode()));
|
|
}
|
|
}
|
|
|
|
tinymce.util.Delay.requestAnimationFrame(execute);
|
|
}
|
|
|
|
function bindScrollEvent() {
|
|
if (!scrollContainer) {
|
|
scrollContainer = editor.selection.getScrollContainer() || editor.getWin();
|
|
tinymce.$(scrollContainer).on('scroll', repositionHandler);
|
|
|
|
editor.on('remove', function() {
|
|
tinymce.$(scrollContainer).off('scroll');
|
|
});
|
|
}
|
|
}
|
|
|
|
function showContextToolbar(match) {
|
|
var panel;
|
|
|
|
if (match.toolbar.panel) {
|
|
match.toolbar.panel.show();
|
|
reposition(match);
|
|
return;
|
|
}
|
|
|
|
bindScrollEvent();
|
|
|
|
panel = Factory.create({
|
|
type: 'floatpanel',
|
|
role: 'dialog',
|
|
classes: 'tinymce tinymce-inline arrow',
|
|
ariaLabel: 'Inline toolbar',
|
|
layout: 'flex',
|
|
direction: 'column',
|
|
align: 'stretch',
|
|
autohide: false,
|
|
autofix: true,
|
|
fixed: true,
|
|
border: 1,
|
|
items: createToolbar(match.toolbar.items),
|
|
oncancel: function() {
|
|
editor.focus();
|
|
}
|
|
});
|
|
|
|
match.toolbar.panel = panel;
|
|
panel.renderTo(document.body).reflow();
|
|
reposition(match);
|
|
}
|
|
|
|
function hideAllContextToolbars() {
|
|
tinymce.each(getContextToolbars(), function(toolbar) {
|
|
if (toolbar.panel) {
|
|
toolbar.panel.hide();
|
|
}
|
|
});
|
|
}
|
|
|
|
function findFrontMostMatch(targetElm) {
|
|
var i, y, parentsAndSelf, toolbars = getContextToolbars();
|
|
|
|
parentsAndSelf = editor.$(targetElm).parents().add(targetElm);
|
|
for (i = parentsAndSelf.length - 1; i >= 0; i--) {
|
|
for (y = toolbars.length - 1; y >= 0; y--) {
|
|
if (toolbars[y].predicate(parentsAndSelf[i])) {
|
|
return {
|
|
toolbar: toolbars[y],
|
|
element: parentsAndSelf[i]
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
editor.on('click keyup setContent', function(e) {
|
|
// Only act on partial inserts
|
|
if (e.type == 'setcontent' && !e.selection) {
|
|
return;
|
|
}
|
|
|
|
// Needs to be delayed to avoid Chrome img focus out bug
|
|
tinymce.util.Delay.setEditorTimeout(editor, function() {
|
|
var match;
|
|
|
|
match = findFrontMostMatch(editor.selection.getNode());
|
|
if (match) {
|
|
hideAllContextToolbars();
|
|
showContextToolbar(match);
|
|
} else {
|
|
hideAllContextToolbars();
|
|
}
|
|
});
|
|
});
|
|
|
|
editor.on('blur hide', hideAllContextToolbars);
|
|
|
|
editor.on('ObjectResizeStart', function() {
|
|
var match = findFrontMostMatch(editor.selection.getNode());
|
|
|
|
if (match && match.toolbar.panel) {
|
|
match.toolbar.panel.hide();
|
|
}
|
|
});
|
|
|
|
editor.on('nodeChange ResizeEditor ResizeWindow', repositionHandler);
|
|
|
|
editor.on('remove', function() {
|
|
tinymce.each(getContextToolbars(), function(toolbar) {
|
|
if (toolbar.panel) {
|
|
toolbar.panel.remove();
|
|
}
|
|
});
|
|
|
|
editor.contextToolbars = {};
|
|
});
|
|
|
|
editor.shortcuts.add('ctrl+shift+e > ctrl+shift+p', '', function() {
|
|
var match = findFrontMostMatch(editor.selection.getNode());
|
|
if (match && match.toolbar.panel) {
|
|
match.toolbar.panel.items()[0].focus();
|
|
}
|
|
});
|
|
}
|
|
|
|
function fireSkinLoaded(editor) {
|
|
return function() {
|
|
if (editor.initialized) {
|
|
editor.fire('SkinLoaded');
|
|
} else {
|
|
editor.on('init', function() {
|
|
editor.fire('SkinLoaded');
|
|
});
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Renders the inline editor UI.
|
|
*
|
|
* @return {Object} Name/value object with theme data.
|
|
*/
|
|
function renderInlineUI(args) {
|
|
var panel, inlineToolbarContainer;
|
|
|
|
if (settings.fixed_toolbar_container) {
|
|
inlineToolbarContainer = DOM.select(settings.fixed_toolbar_container)[0];
|
|
}
|
|
|
|
function reposition() {
|
|
if (panel && panel.moveRel && panel.visible() && !panel._fixed) {
|
|
// TODO: This is kind of ugly and doesn't handle multiple scrollable elements
|
|
var scrollContainer = editor.selection.getScrollContainer(), body = editor.getBody();
|
|
var deltaX = 0, deltaY = 0;
|
|
|
|
if (scrollContainer) {
|
|
var bodyPos = DOM.getPos(body), scrollContainerPos = DOM.getPos(scrollContainer);
|
|
|
|
deltaX = Math.max(0, scrollContainerPos.x - bodyPos.x);
|
|
deltaY = Math.max(0, scrollContainerPos.y - bodyPos.y);
|
|
}
|
|
|
|
panel.fixed(false).moveRel(body, editor.rtl ? ['tr-br', 'br-tr'] : ['tl-bl', 'bl-tl', 'tr-br']).moveBy(deltaX, deltaY);
|
|
}
|
|
}
|
|
|
|
function show() {
|
|
if (panel) {
|
|
panel.show();
|
|
reposition();
|
|
DOM.addClass(editor.getBody(), 'mce-edit-focus');
|
|
}
|
|
}
|
|
|
|
function hide() {
|
|
if (panel) {
|
|
// We require two events as the inline float panel based toolbar does not have autohide=true
|
|
panel.hide();
|
|
|
|
// All other autohidden float panels will be closed below.
|
|
FloatPanel.hideAll();
|
|
|
|
DOM.removeClass(editor.getBody(), 'mce-edit-focus');
|
|
}
|
|
}
|
|
|
|
function render() {
|
|
if (panel) {
|
|
if (!panel.visible()) {
|
|
show();
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
// Render a plain panel inside the inlineToolbarContainer if it's defined
|
|
panel = self.panel = Factory.create({
|
|
type: inlineToolbarContainer ? 'panel' : 'floatpanel',
|
|
role: 'application',
|
|
classes: 'tinymce tinymce-inline',
|
|
layout: 'flex',
|
|
direction: 'column',
|
|
align: 'stretch',
|
|
autohide: false,
|
|
autofix: true,
|
|
fixed: !!inlineToolbarContainer,
|
|
border: 1,
|
|
items: [
|
|
settings.menubar === false ? null : {type: 'menubar', border: '0 0 1 0', items: createMenuButtons()},
|
|
createToolbars(settings.toolbar_items_size)
|
|
]
|
|
});
|
|
|
|
// Add statusbar
|
|
/*if (settings.statusbar !== false) {
|
|
panel.add({type: 'panel', classes: 'statusbar', layout: 'flow', border: '1 0 0 0', items: [
|
|
{type: 'elementpath'}
|
|
]});
|
|
}*/
|
|
|
|
editor.fire('BeforeRenderUI');
|
|
panel.renderTo(inlineToolbarContainer || document.body).reflow();
|
|
|
|
addAccessibilityKeys(panel);
|
|
show();
|
|
addContextualToolbars();
|
|
|
|
editor.on('nodeChange', reposition);
|
|
editor.on('activate', show);
|
|
editor.on('deactivate', hide);
|
|
|
|
editor.nodeChanged();
|
|
}
|
|
|
|
settings.content_editable = true;
|
|
|
|
editor.on('focus', function() {
|
|
// Render only when the CSS file has been loaded
|
|
if (args.skinUiCss) {
|
|
tinymce.DOM.styleSheetLoader.load(args.skinUiCss, render, render);
|
|
} else {
|
|
render();
|
|
}
|
|
});
|
|
|
|
editor.on('blur hide', hide);
|
|
|
|
// Remove the panel when the editor is removed
|
|
editor.on('remove', function() {
|
|
if (panel) {
|
|
panel.remove();
|
|
panel = null;
|
|
}
|
|
});
|
|
|
|
// Preload skin css
|
|
if (args.skinUiCss) {
|
|
tinymce.DOM.styleSheetLoader.load(args.skinUiCss, fireSkinLoaded(editor));
|
|
}
|
|
|
|
return {};
|
|
}
|
|
|
|
/**
|
|
* Renders the iframe editor UI.
|
|
*
|
|
* @param {Object} args Details about target element etc.
|
|
* @return {Object} Name/value object with theme data.
|
|
*/
|
|
function renderIframeUI(args) {
|
|
var panel, resizeHandleCtrl, startSize;
|
|
|
|
function switchMode() {
|
|
return function(e) {
|
|
if (e.mode == 'readonly') {
|
|
panel.find('*').disabled(true);
|
|
} else {
|
|
panel.find('*').disabled(false);
|
|
}
|
|
};
|
|
}
|
|
|
|
if (args.skinUiCss) {
|
|
tinymce.DOM.styleSheetLoader.load(args.skinUiCss, fireSkinLoaded(editor));
|
|
}
|
|
|
|
// Basic UI layout
|
|
panel = self.panel = Factory.create({
|
|
type: 'panel',
|
|
role: 'application',
|
|
classes: 'tinymce',
|
|
style: 'visibility: hidden',
|
|
layout: 'stack',
|
|
border: 1,
|
|
items: [
|
|
settings.menubar === false ? null : {type: 'menubar', border: '0 0 1 0', items: createMenuButtons()},
|
|
createToolbars(settings.toolbar_items_size),
|
|
{type: 'panel', name: 'iframe', layout: 'stack', classes: 'edit-area', html: '', border: '1 0 0 0'}
|
|
]
|
|
});
|
|
|
|
if (settings.resize !== false) {
|
|
resizeHandleCtrl = {
|
|
type: 'resizehandle',
|
|
direction: settings.resize,
|
|
|
|
onResizeStart: function() {
|
|
var elm = editor.getContentAreaContainer().firstChild;
|
|
|
|
startSize = {
|
|
width: elm.clientWidth,
|
|
height: elm.clientHeight
|
|
};
|
|
},
|
|
|
|
onResize: function(e) {
|
|
if (settings.resize == 'both') {
|
|
resizeTo(startSize.width + e.deltaX, startSize.height + e.deltaY);
|
|
} else {
|
|
resizeTo(null, startSize.height + e.deltaY);
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
// Add statusbar if needed
|
|
if (settings.statusbar !== false) {
|
|
panel.add({type: 'panel', name: 'statusbar', classes: 'statusbar', layout: 'flow', border: '1 0 0 0', ariaRoot: true, items: [
|
|
{type: 'elementpath'},
|
|
resizeHandleCtrl
|
|
]});
|
|
}
|
|
|
|
editor.fire('BeforeRenderUI');
|
|
editor.on('SwitchMode', switchMode());
|
|
panel.renderBefore(args.targetNode).reflow();
|
|
|
|
if (settings.readonly) {
|
|
editor.setMode('readonly');
|
|
}
|
|
|
|
if (settings.width) {
|
|
tinymce.DOM.setStyle(panel.getEl(), 'width', settings.width);
|
|
}
|
|
|
|
// Remove the panel when the editor is removed
|
|
editor.on('remove', function() {
|
|
panel.remove();
|
|
panel = null;
|
|
});
|
|
|
|
// Add accesibility shortcuts
|
|
addAccessibilityKeys(panel);
|
|
addContextualToolbars();
|
|
|
|
return {
|
|
iframeContainer: panel.find('#iframe')[0].getEl(),
|
|
editorContainer: panel.getEl()
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Renders the UI for the theme. This gets called by the editor.
|
|
*
|
|
* @param {Object} args Details about target element etc.
|
|
* @return {Object} Theme UI data items.
|
|
*/
|
|
self.renderUI = function(args) {
|
|
var skin = settings.skin !== false ? settings.skin || 'lightgray' : false;
|
|
|
|
if (skin) {
|
|
var skinUrl = settings.skin_url;
|
|
|
|
if (skinUrl) {
|
|
skinUrl = editor.documentBaseURI.toAbsolute(skinUrl);
|
|
} else {
|
|
skinUrl = tinymce.baseURL + '/skins/' + skin;
|
|
}
|
|
|
|
// Load special skin for IE7
|
|
// TODO: Remove this when we drop IE7 support
|
|
if (tinymce.Env.documentMode <= 7) {
|
|
args.skinUiCss = skinUrl + '/skin.ie7.min.css';
|
|
} else {
|
|
args.skinUiCss = skinUrl + '/skin.min.css';
|
|
}
|
|
|
|
// Load content.min.css or content.inline.min.css
|
|
editor.contentCSS.push(skinUrl + '/content' + (editor.inline ? '.inline' : '') + '.min.css');
|
|
}
|
|
|
|
// Handle editor setProgressState change
|
|
editor.on('ProgressState', function(e) {
|
|
self.throbber = self.throbber || new tinymce.ui.Throbber(self.panel.getEl('body'));
|
|
|
|
if (e.state) {
|
|
self.throbber.show(e.time);
|
|
} else {
|
|
self.throbber.hide();
|
|
}
|
|
});
|
|
|
|
if (settings.inline) {
|
|
return renderInlineUI(args);
|
|
}
|
|
|
|
return renderIframeUI(args);
|
|
};
|
|
|
|
self.resizeTo = resizeTo;
|
|
self.resizeBy = resizeBy;
|
|
});
|