X-Git-Url: https://scripts.mit.edu/gitweb/autoinstalls/wordpress.git/blobdiff_plain/58b0523c599c731e868bd4bc05b0d686a98d254f..e0feb3b2e5b436a06bbb04fbc838d1cd6ec95399:/wp-includes/js/tinymce/themes/modern/theme.js diff --git a/wp-includes/js/tinymce/themes/modern/theme.js b/wp-includes/js/tinymce/themes/modern/theme.js index 251182ec..47739f85 100644 --- a/wp-includes/js/tinymce/themes/modern/theme.js +++ b/wp-includes/js/tinymce/themes/modern/theme.js @@ -1,8 +1,8 @@ /** * theme.js * - * Copyright, Moxiecode Systems AB * 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 @@ -11,7 +11,8 @@ /*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; + var self = this, settings = editor.settings, Factory = tinymce.ui.Factory, + each = tinymce.each, DOM = tinymce.DOM, Rect = tinymce.ui.Rect, FloatPanel = tinymce.ui.FloatPanel; // Default menus var defaultMenus = { @@ -27,119 +28,128 @@ tinymce.ThemeManager.add('modern', function(editor) { var defaultToolbar = "undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | " + "bullist numlist outdent indent | link image"; - /** - * Creates the toolbars from config and returns a toolbar array. - * - * @return {Array} Array with toolbars. - */ - function createToolbars() { - var toolbars = []; - - function addToolbar(items) { - var toolbarItems = [], buttonGroup; + function createToolbar(items) { + var toolbarItems = [], buttonGroup; - if (!items) { - return; - } + if (!items) { + return; + } - each(items.split(/[ ,]/), function(item) { - var itemName; + each(items.split(/[ ,]/), function(item) { + var itemName; - function bindSelectorChanged() { - var selection = editor.selection; + function bindSelectorChanged() { + var selection = editor.selection; - if (itemName == "bullist") { - selection.selectorChanged('ul > li', function(state, args) { - var nodeName, i = args.parents.length; + if (itemName == "bullist") { + selection.selectorChanged('ul > li', function(state, args) { + var nodeName, i = args.parents.length; - while (i--) { - nodeName = args.parents[i].nodeName; - if (nodeName == "OL" || nodeName == "UL") { - break; - } + while (i--) { + nodeName = args.parents[i].nodeName; + if (nodeName == "OL" || nodeName == "UL") { + break; } + } - item.active(state && nodeName == "UL"); - }); - } + item.active(state && nodeName == "UL"); + }); + } - if (itemName == "numlist") { - selection.selectorChanged('ol > li', function(state, args) { - var nodeName, i = args.parents.length; + 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; - } + while (i--) { + nodeName = args.parents[i].nodeName; + if (nodeName == "OL" || nodeName == "UL") { + break; } + } - item.active(state && nodeName == "OL"); - }); - } + item.active(state && nodeName == "OL"); + }); + } - if (item.settings.stateSelector) { - selection.selectorChanged(item.settings.stateSelector, function(state) { - item.active(state); - }, true); - } + 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.settings.disabledStateSelector) { + selection.selectorChanged(item.settings.disabledStateSelector, function(state) { + item.disabled(state); + }); } + } + + if (item == "|") { + buttonGroup = null; + } else { + if (Factory.has(item)) { + item = {type: item}; - if (item == "|") { + if (settings.toolbar_items_size) { + item.size = settings.toolbar_items_size; + } + + toolbarItems.push(item); buttonGroup = null; } else { - if (Factory.has(item)) { - item = {type: item}; + if (!buttonGroup) { + buttonGroup = {type: 'buttongroup', items: []}; + toolbarItems.push(buttonGroup); + } - if (settings.toolbar_items_size) { - item.size = settings.toolbar_items_size; - } + if (editor.buttons[item]) { + // TODO: Move control creation to some UI class + itemName = item; + item = editor.buttons[itemName]; - toolbarItems.push(item); - buttonGroup = null; - } else { - if (!buttonGroup) { - buttonGroup = {type: 'buttongroup', items: []}; - toolbarItems.push(buttonGroup); + if (typeof item == "function") { + item = item(); } - 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.type = item.type || 'button'; - if (settings.toolbar_items_size) { - item.size = settings.toolbar_items_size; - } + if (settings.toolbar_items_size) { + item.size = settings.toolbar_items_size; + } - item = Factory.create(item); - buttonGroup.items.push(item); + item = Factory.create(item); + buttonGroup.items.push(item); - if (editor.initialized) { - bindSelectorChanged(); - } else { - editor.on('init', bindSelectorChanged); - } + if (editor.initialized) { + bindSelectorChanged(); + } else { + editor.on('init', bindSelectorChanged); } } } - }); + } + }); - toolbars.push({type: 'toolbar', layout: 'flow', items: toolbarItems}); + return { + type: 'toolbar', + layout: 'flow', + items: toolbarItems + }; + } - return true; + /** + * Creates the toolbars from config and returns a toolbar array. + * + * @return {Array} Array with toolbars. + */ + function createToolbars() { + var toolbars = []; + + function addToolbar(items) { + if (items) { + toolbars.push(createToolbar(items)); + return true; + } } // Convert toolbar array to multiple options @@ -358,6 +368,236 @@ tinymce.ThemeManager.add('modern', function(editor) { 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 reposition(match) { + var relPos, panelRect, elementRect, contentAreaRect, panel, relRect, testPositions; + + if (editor.removed) { + return; + } + + if (!match || !match.toolbar.panel) { + hideAllFloatingPanels(); + return; + } + + testPositions = [ + 'tc-bc', 'bc-tc', + '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()); + + 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); + } + + relPos = Rect.findBestRelativePosition(panelRect, elementRect, contentAreaRect, testPositions); + + 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); + } else { + each(testPositions, function(pos) { + panel.classes.toggle('tinymce-inline-' + pos, false); + }); + + panel.classes.toggle('tinymce-inline-inside', true); + + elementRect = Rect.intersect(contentAreaRect, elementRect); + + if (elementRect) { + relPos = Rect.findBestRelativePosition(panelRect, elementRect, contentAreaRect, [ + 'tc-tc', 'tl-tl', 'tr-tr' + ]); + + if (relPos) { + relRect = Rect.relativePosition(panelRect, elementRect, relPos); + panel.moveTo(relRect.x, relRect.y); + } else { + panel.moveTo(elementRect.x, elementRect.y); + } + } else { + panel.hide(); + } + } + + //drawRect(contentAreaRect, 'blue'); + //drawRect(elementRect, 'red'); + //drawRect(panelRect, 'green'); + } + + function repositionHandler() { + function execute() { + if (editor.selection) { + reposition(findFrontMostMatch(editor.selection.getNode())); + } + } + + if (window.requestAnimationFrame) { + window.requestAnimationFrame(execute); + } else { + 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: 'application', + classes: 'tinymce tinymce-inline', + layout: 'flex', + direction: 'column', + align: 'stretch', + autohide: false, + autofix: true, + fixed: true, + border: 1, + items: createToolbar(match.toolbar.items) + }); + + 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 blur', function() { + // Needs to be delayed to avoid Chrome img focus out bug + window.setTimeout(function() { + var match; + + if (editor.removed) { + return; + } + + match = findFrontMostMatch(editor.selection.getNode()); + if (match) { + showContextToolbar(match); + } else { + hideAllContextToolbars(); + } + }, 0); + }); + + 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 = {}; + }); + } + /** * Renders the inline editor UI. * @@ -397,7 +637,12 @@ tinymce.ThemeManager.add('modern', function(editor) { 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'); } } @@ -441,6 +686,7 @@ tinymce.ThemeManager.add('modern', function(editor) { addAccessibilityKeys(panel); show(); + addContextualToolbars(); editor.on('nodeChange', reposition); editor.on('activate', show); @@ -555,8 +801,9 @@ tinymce.ThemeManager.add('modern', function(editor) { panel = null; }); - // Add accesibility shortkuts + // Add accesibility shortcuts addAccessibilityKeys(panel); + addContextualToolbars(); return { iframeContainer: panel.find('#iframe')[0].getEl(),