diff --git a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js index d3d0060ff5..82e2eb632c 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js @@ -194,7 +194,7 @@ function tinyMceService(dialogService, $log, imageHelper, assetsService, $timeou } }); } - + /** Adds the button instance */ editor.addButton('umbmacro', { icon: 'custom icon-settings-alt', @@ -204,6 +204,57 @@ function tinyMceService(dialogService, $log, imageHelper, assetsService, $timeou var ctrl = this; var isOnMacroElement = false; + /** + if the selection comes from a different element that is not the macro's + we need to check if the selection includes part of the macro, if so we'll force the selection + to clear to the next element since if people can select part of the macro markup they can then modify it. + */ + function handleSelectionChange() { + + if (!editor.selection.isCollapsed()) { + var endSelection = tinymce.activeEditor.selection.getEnd(); + var startSelection = tinymce.activeEditor.selection.getStart(); + //don't proceed if it's an entire element selected + if (endSelection !== startSelection) { + + //if the end selection is a macro then move the cursor + //NOTE: we don't have to handle when the selection comes from a previous parent because + // that is automatically taken care of with the normal onNodeChanged logic since the + // evt.element will be the macro once it becomes part of the selection. + var $testForMacro = $(endSelection).closest(".umb-macro-holder"); + if ($testForMacro.length > 0) { + + //it came from before so move after, if there is no after then select ourselves + var next = $testForMacro.next(); + if (next.length > 0) { + editor.selection.setCursorLocation($testForMacro.next().get(0)); + } + else { + selectMacroElement($testForMacro.get(0)); + } + + } + } + } + } + + /** helper method to select the macro element */ + function selectMacroElement(macroElement) { + // move selection to top element to ensure we can't edit this + editor.selection.select(macroElement); + + // check if the current selection *is* the element (ie bug) + var currentSelection = editor.selection.getStart(); + if (tinymce.isIE) { + if (!editor.dom.hasClass(currentSelection, 'umb-macro-holder')) { + while (!editor.dom.hasClass(currentSelection, 'umb-macro-holder') && currentSelection.parentNode) { + currentSelection = currentSelection.parentNode; + } + editor.selection.select(currentSelection); + } + } + } + /** * Add a node change handler, test if we're editing a macro and select the whole thing, then set our isOnMacroElement flag. * If we change the selection inside this method, then we end up in an infinite loop, so we have to remove ourselves @@ -214,7 +265,10 @@ function tinyMceService(dialogService, $log, imageHelper, assetsService, $timeou //set our macro button active when on a node of class umb-macro-holder var $macroElement = $(evt.element).closest(".umb-macro-holder"); + + handleSelectionChange(); + //set the button active ctrl.active($macroElement.length !== 0); if ($macroElement.length > 0) { @@ -222,20 +276,8 @@ function tinyMceService(dialogService, $log, imageHelper, assetsService, $timeou //remove the event listener before re-selecting editor.off('NodeChange', onNodeChanged); - - // move selection to top element to ensure we can't edit this - editor.selection.select(macroElement); - // check if the current selection *is* the element (ie bug) - var currentSelection = editor.selection.getStart(); - if (tinymce.isIE) { - if (!editor.dom.hasClass(currentSelection, 'umb-macro-holder')) { - while (!editor.dom.hasClass(currentSelection, 'umb-macro-holder') && currentSelection.parentNode) { - currentSelection = currentSelection.parentNode; - } - editor.selection.select(currentSelection); - } - } + selectMacroElement(macroElement); //set the flag isOnMacroElement = true; @@ -257,7 +299,6 @@ function tinyMceService(dialogService, $log, imageHelper, assetsService, $timeou loadMacroContent($(this)); }); - }); /** This prevents any other commands from executing when the current element is the macro so the content cannot be edited */ diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js index 183d842dca..5dad072c39 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js @@ -1,6 +1,6 @@ angular.module("umbraco") .controller("Umbraco.Editors.RTEController", - function ($rootScope, $scope, dialogService, $log, imageHelper, assetsService, $timeout, tinyMceService) { + function ($rootScope, $element, $scope, dialogService, $log, imageHelper, assetsService, $timeout, tinyMceService, angularHelper) { //TODO: This should be configurable (i.e. from the config file we have and/or from pre-values) var validElements = "@[id|class|style|title|dir