tinymce.ThemeManager.add('modern', function(editor) {
var self = this, settings = editor.settings, Factory = tinymce.ui.Factory,
- each = tinymce.each, DOM = tinymce.DOM, Rect = tinymce.ui.Rect, FloatPanel = tinymce.ui.FloatPanel;
+ each = tinymce.each, DOM = tinymce.DOM, Rect = tinymce.geom.Rect, FloatPanel = tinymce.ui.FloatPanel;
// Default menus
var defaultMenus = {
function bindSelectorChanged() {
var selection = editor.selection;
- if (itemName == "bullist") {
- selection.selectorChanged('ul > li', function(state, args) {
+ function setActiveItem(name) {
+ return function(state, args) {
var nodeName, i = args.parents.length;
while (i--) {
}
}
- item.active(state && nodeName == "UL");
- });
+ item.active(state && nodeName == name);
+ };
}
- if (itemName == "numlist") {
- selection.selectorChanged('ol > li', function(state, args) {
- var nodeName, i = args.parents.length;
-
- while (i--) {
- nodeName = args.parents[i].nodeName;
- if (nodeName == "OL" || nodeName == "UL") {
- break;
- }
- }
+ if (itemName == "bullist") {
+ selection.selectorChanged('ul > li', setActiveItem("UL"));
+ }
- item.active(state && nodeName == "OL");
- });
+ if (itemName == "numlist") {
+ selection.selectorChanged('ol > li', setActiveItem("OL"));
}
if (item.settings.stateSelector) {
});
}
+ 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;
+ var relPos, panelRect, elementRect, contentAreaRect, panel, relRect, testPositions, smallElementWidthThreshold;
if (editor.removed) {
return;
}
testPositions = [
- 'tc-bc', 'bc-tc',
+ 'bc-tc', 'tc-bc',
'tl-bl', 'bl-tl',
'tr-br', 'br-tr'
];
elementRect = getElementRect(match.element);
panelRect = tinymce.DOM.getRect(panel.getEl());
contentAreaRect = tinymce.DOM.getRect(editor.getContentAreaContainer() || editor.getBody());
+ smallElementWidthThreshold = 25;
+
+ // 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, 7);
+ if (editor.selection.controlSelection.isResizable(match.element) && elementRect.w < smallElementWidthThreshold) {
+ elementRect = Rect.inflate(elementRect, 0, 8);
}
relPos = Rect.findBestRelativePosition(panelRect, elementRect, contentAreaRect, testPositions);
+ elementRect = Rect.clamp(elementRect, contentAreaRect);
if (relPos) {
- each(testPositions.concat('inside'), function(pos) {
- panel.classes.toggle('tinymce-inline-' + pos, pos == relPos);
- });
-
relRect = Rect.relativePosition(panelRect, elementRect, relPos);
- panel.moveTo(relRect.x, relRect.y);
+ movePanelTo(panel, userConstrain(relRect.x, relRect.y, elementRect, contentAreaRect, panelRect));
} else {
- each(testPositions, function(pos) {
- panel.classes.toggle('tinymce-inline-' + pos, false);
- });
-
- panel.classes.toggle('tinymce-inline-inside', true);
+ // Allow overflow below the editor to avoid placing toolbars ontop of tables
+ contentAreaRect.h += panelRect.h;
elementRect = Rect.intersect(contentAreaRect, elementRect);
-
if (elementRect) {
relPos = Rect.findBestRelativePosition(panelRect, elementRect, contentAreaRect, [
- 'tc-tc', 'tl-tl', 'tr-tr'
+ 'bc-tc', 'bl-tl', 'br-tr'
]);
if (relPos) {
relRect = Rect.relativePosition(panelRect, elementRect, relPos);
- panel.moveTo(relRect.x, relRect.y);
+ movePanelTo(panel, userConstrain(relRect.x, relRect.y, elementRect, contentAreaRect, panelRect));
} else {
- panel.moveTo(elementRect.x, elementRect.y);
+ movePanelTo(panel, userConstrain(elementRect.x, elementRect.y, elementRect, contentAreaRect, panelRect));
}
} else {
panel.hide();
}
}
+ togglePositionClass(panel, relPos, function(pos1, pos2) {
+ return pos1 === pos2;
+ });
+
//drawRect(contentAreaRect, 'blue');
//drawRect(elementRect, 'red');
//drawRect(panelRect, 'green');
}
}
- if (window.requestAnimationFrame) {
- window.requestAnimationFrame(execute);
- } else {
- execute();
- }
+ tinymce.util.Delay.requestAnimationFrame(execute);
}
function bindScrollEvent() {
panel = Factory.create({
type: 'floatpanel',
- role: 'application',
- classes: 'tinymce tinymce-inline',
+ role: 'dialog',
+ classes: 'tinymce tinymce-inline arrow',
+ ariaLabel: 'Inline toolbar',
layout: 'flex',
direction: 'column',
align: 'stretch',
autofix: true,
fixed: true,
border: 1,
- items: createToolbar(match.toolbar.items)
+ items: createToolbar(match.toolbar.items),
+ oncancel: function() {
+ editor.focus();
+ }
});
match.toolbar.panel = panel;
return null;
}
- editor.on('click keyup blur', function() {
+ 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
- window.setTimeout(function() {
+ tinymce.util.Delay.setEditorTimeout(editor, function() {
var match;
- if (editor.removed) {
- return;
- }
-
match = findFrontMostMatch(editor.selection.getNode());
if (match) {
+ hideAllContextToolbars();
showContextToolbar(match);
} else {
hideAllContextToolbars();
}
- }, 0);
+ });
});
+ editor.on('blur hide', hideAllContextToolbars);
+
editor.on('ObjectResizeStart', function() {
var match = findFrontMostMatch(editor.selection.getNode());
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');
+ });
+ }
+ };
}
/**
// Preload skin css
if (args.skinUiCss) {
- tinymce.DOM.styleSheetLoader.load(args.skinUiCss);
+ tinymce.DOM.styleSheetLoader.load(args.skinUiCss, fireSkinLoaded(editor));
}
return {};
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.loadCSS(args.skinUiCss);
+ tinymce.DOM.styleSheetLoader.load(args.skinUiCss, fireSkinLoaded(editor));
}
// Basic UI layout
// 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'},
+ {type: 'elementpath', editor: editor},
resizeHandleCtrl
]});
}
- if (settings.readonly) {
- panel.find('*').disabled(true);
- }
-
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);
}