fixes rte property editor to ensure that data is saved since tinymce events are a bit strange. fixes up selection changes and ensures that macro markup in the editor can never be modified.
This commit is contained in:
@@ -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 */
|
||||
|
||||
@@ -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<ltr?rtl|lang|xml::lang|onclick|ondblclick|"
|
||||
@@ -47,11 +47,36 @@ angular.module("umbraco")
|
||||
height: 340,
|
||||
toolbar: toolbar,
|
||||
setup: function (editor) {
|
||||
|
||||
//We need to listen on multiple things here because of the nature of tinymce, it doesn't
|
||||
//fire events when you think!
|
||||
//The change event doesn't fire when content changes, only when cursor points are changed and undo points
|
||||
//are created. the blur event doesn't fire if you insert content into the editor with a button and then
|
||||
//press save.
|
||||
//We have a couple of options, one is to do a set timeout and check for isDirty on the editor, or we can
|
||||
//listen to both change and blur and also on our own 'saving' event. I think this will be best because a
|
||||
//timer might end up using unwanted cpu and we'd still have to listen to our saving event in case they clicked
|
||||
//save before the timeout elapsed.
|
||||
editor.on('change', function (e) {
|
||||
angularHelper.safeApply($scope, function() {
|
||||
$scope.model.value = editor.getContent();
|
||||
});
|
||||
});
|
||||
editor.on('blur', function (e) {
|
||||
$scope.$apply(function () {
|
||||
angularHelper.safeApply($scope, function () {
|
||||
$scope.model.value = editor.getContent();
|
||||
});
|
||||
});
|
||||
var unsubscribe = $scope.$on("saving", function() {
|
||||
$scope.model.value = editor.getContent();
|
||||
});
|
||||
|
||||
//when the element is disposed we need to unsubscribe!
|
||||
// NOTE: this is very important otherwise if this is part of a modal, the listener still exists because the dom
|
||||
// element might still be there even after the modal has been hidden.
|
||||
$element.bind('$destroy', function () {
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
//Create the insert media plugin
|
||||
tinyMceService.createMediaPicker(editor, $scope);
|
||||
|
||||
Reference in New Issue
Block a user