Merge remote-tracking branch 'origin/v8/dev' into v9/dev
# Conflicts: # src/SolutionInfo.cs # src/Umbraco.Core/Cache/DataTypeCacheRefresher.cs # src/Umbraco.Core/Extensions/PublishedContentExtensions.cs # src/Umbraco.Core/Extensions/PublishedPropertyExtension.cs # src/Umbraco.Core/Migrations/Install/DatabaseDataCreator.cs # src/Umbraco.Tests/TestHelpers/Entities/MockedContentTypes.cs # src/Umbraco.Web.UI.NetCore/umbraco/config/lang/da.xml # src/Umbraco.Web/PropertyEditors/MediaPickerPropertyEditor.cs
This commit is contained in:
@@ -12,6 +12,11 @@
|
||||
var isLeftColumnAbove = false;
|
||||
scope.editors = [];
|
||||
|
||||
/* we need to keep a count of open editors because the length of the editors array is first changed when animations are done
|
||||
we do this because some infinite editors close more than one editor at the time and we get the wrong count from editors.length
|
||||
because of the animation */
|
||||
let editorCount = 0;
|
||||
|
||||
function addEditor(editor) {
|
||||
editor.inFront = true;
|
||||
editor.moveRight = true;
|
||||
@@ -51,13 +56,16 @@
|
||||
|
||||
updateEditors(-1);
|
||||
|
||||
if(scope.editors.length === 1){
|
||||
if(scope.editors.length === 1) {
|
||||
if(isLeftColumnAbove){
|
||||
$('#leftcolumn').addClass(aboveBackDropCssClass);
|
||||
}
|
||||
|
||||
isLeftColumnAbove = false;
|
||||
}
|
||||
|
||||
// when the last editor is closed remove the focus lock
|
||||
if (editorCount === 0) {
|
||||
// Remove the inert attribute from the #mainwrapper
|
||||
focusLockService.removeInertAttribute();
|
||||
}
|
||||
@@ -105,16 +113,19 @@
|
||||
}
|
||||
|
||||
evts.push(eventsService.on("appState.editors.open", function (name, args) {
|
||||
editorCount = editorCount + 1;
|
||||
addEditor(args.editor);
|
||||
}));
|
||||
|
||||
evts.push(eventsService.on("appState.editors.close", function (name, args) {
|
||||
// remove the closed editor
|
||||
if (args && args.editor) {
|
||||
editorCount = editorCount - 1;
|
||||
removeEditor(args.editor);
|
||||
}
|
||||
// close all editors
|
||||
if (args && !args.editor && args.editors.length === 0) {
|
||||
editorCount = 0;
|
||||
scope.editors = [];
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -40,7 +40,9 @@
|
||||
|
||||
function getDomNodes(){
|
||||
infiniteEditorsWrapper = document.querySelector('.umb-editors');
|
||||
infiniteEditors = Array.from(infiniteEditorsWrapper.querySelectorAll('.umb-editor'));
|
||||
if(infiniteEditorsWrapper) {
|
||||
infiniteEditors = Array.from(infiniteEditorsWrapper.querySelectorAll('.umb-editor') || []);
|
||||
}
|
||||
}
|
||||
|
||||
function getFocusableElements(targetElm) {
|
||||
@@ -84,22 +86,24 @@
|
||||
var defaultFocusedElement = getAutoFocusElement(focusableElements);
|
||||
var lastKnownElement;
|
||||
|
||||
// If an inifite editor is being closed then we reset the focus to the element that triggered the the overlay
|
||||
// If an infinite editor is being closed then we reset the focus to the element that triggered the the overlay
|
||||
if(closingEditor){
|
||||
var lastItemIndex = $rootScope.lastKnownFocusableElements.length - 1;
|
||||
var editorInfo = infiniteEditors[0].querySelector('.editor-info');
|
||||
|
||||
// If there is only one editor open, search for the "editor-info" inside it and set focus on it
|
||||
// This is relevant when a property editor has been selected and the editor where we selected it from
|
||||
// is closed taking us back to the first layer
|
||||
// Otherwise set it to the last element in the lastKnownFocusedElements array
|
||||
if(infiniteEditors.length === 1 && editorInfo !== null){
|
||||
lastKnownElement = editorInfo;
|
||||
if(infiniteEditors && infiniteEditors.length === 1){
|
||||
var editorInfo = infiniteEditors[0].querySelector('.editor-info');
|
||||
if(infiniteEditors && infiniteEditors.length === 1 && editorInfo !== null) {
|
||||
lastKnownElement = editorInfo;
|
||||
|
||||
// Clear the array
|
||||
clearLastKnownFocusedElements();
|
||||
// Clear the array
|
||||
clearLastKnownFocusedElements();
|
||||
}
|
||||
}
|
||||
else {
|
||||
var lastItemIndex = $rootScope.lastKnownFocusableElements.length - 1;
|
||||
lastKnownElement = $rootScope.lastKnownFocusableElements[lastItemIndex];
|
||||
|
||||
// Remove the last item from the array so we always set the correct lastKnowFocus for each layer
|
||||
@@ -149,20 +153,24 @@
|
||||
}
|
||||
|
||||
function cleanupEventHandlers() {
|
||||
var activeEditor = infiniteEditors[infiniteEditors.length - 1];
|
||||
var inactiveEditors = infiniteEditors.filter(editor => editor !== activeEditor);
|
||||
//if we're in infinite editing mode
|
||||
if(infiniteEditors.length > 0) {
|
||||
var activeEditor = infiniteEditors[infiniteEditors.length - 1];
|
||||
var inactiveEditors = infiniteEditors.filter(editor => editor !== activeEditor);
|
||||
|
||||
if(inactiveEditors.length > 0) {
|
||||
for (var index = 0; index < inactiveEditors.length; index++) {
|
||||
var inactiveEditor = inactiveEditors[index];
|
||||
if(inactiveEditors.length > 0) {
|
||||
for (var index = 0; index < inactiveEditors.length; index++) {
|
||||
var inactiveEditor = inactiveEditors[index];
|
||||
|
||||
// Remove event handlers from inactive editors
|
||||
inactiveEditor.removeEventListener('keydown', handleKeydown);
|
||||
// Remove event handlers from inactive editors
|
||||
inactiveEditor.removeEventListener('keydown', handleKeydown);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Why is this one only begin called if there is no other infinite editors, wouldn't it make sense always to clean this up?
|
||||
// Remove event handlers from the active editor
|
||||
activeEditor.removeEventListener('keydown', handleKeydown);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Remove event handlers from the active editor
|
||||
activeEditor.removeEventListener('keydown', handleKeydown);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,10 +181,7 @@
|
||||
// Fetch the DOM nodes we need
|
||||
getDomNodes();
|
||||
|
||||
// Cleanup event handlers if we're in infinite editing mode
|
||||
if(infiniteEditors.length > 0){
|
||||
cleanupEventHandlers();
|
||||
}
|
||||
cleanupEventHandlers();
|
||||
|
||||
getFocusableElements(targetElm);
|
||||
|
||||
@@ -204,17 +209,19 @@
|
||||
// Make sure to disconnect the observer so we potentially don't end up with having many active ones
|
||||
disconnectObserver = true;
|
||||
|
||||
// Pass the correct editor in order to find the focusable elements
|
||||
var newTarget = infiniteEditors[infiniteEditors.length - 2];
|
||||
if(infiniteEditors && infiniteEditors.length > 1) {
|
||||
// Pass the correct editor in order to find the focusable elements
|
||||
var newTarget = infiniteEditors[infiniteEditors.length - 2];
|
||||
|
||||
if(infiniteEditors.length > 1){
|
||||
// Setting closing till true will let us re-apply the last known focus to then opened layer that then becomes
|
||||
// active
|
||||
closingEditor = true;
|
||||
if(infiniteEditors.length > 1) {
|
||||
// Setting closing till true will let us re-apply the last known focus to then opened layer that then becomes
|
||||
// active
|
||||
closingEditor = true;
|
||||
|
||||
onInit(newTarget);
|
||||
onInit(newTarget);
|
||||
|
||||
return;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Clear lastKnownFocusableElements
|
||||
|
||||
@@ -26,7 +26,7 @@ angular.module("umbraco.directives")
|
||||
forceUpdate: '@?'
|
||||
},
|
||||
|
||||
link: function (scope, element, attrs) {
|
||||
link: function (scope, element, attrs, windowResizeListener) {
|
||||
|
||||
var unsubscribe = [];
|
||||
let sliderRef = null;
|
||||
|
||||
@@ -48,8 +48,6 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt
|
||||
});
|
||||
}
|
||||
else if (value[0]) {
|
||||
//notificationsService.error("Validation", value[0]);
|
||||
console.log({type:messageType, header:"Validation", message:value[0]})
|
||||
notificationsService.showNotification({type:messageType, header:"Validation", message:value[0]})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -441,7 +441,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
// We are not ready to limit the pasted elements further than default, we will return to this feature. ( TODO: Make this feature an option. )
|
||||
// We keep spans here, cause removing spans here also removes b-tags inside of them, instead we strip them out later. (TODO: move this definition to the config file... )
|
||||
var validPasteElements = "-strong/b,-em/i,-u,-span,-p,-ol,-ul,-li,-p/div,-a[href|name],sub,sup,strike,br,del,table[width],tr,td[colspan|rowspan|width],th[colspan|rowspan|width],thead,tfoot,tbody,img[src|alt|width|height],ul,ol,li,hr,pre,dl,dt,figure,figcaption,wbr"
|
||||
|
||||
|
||||
// add elements from user configurated styleFormats to our list of validPasteElements.
|
||||
// (This means that we only allow H3-element if its configured as a styleFormat on this specific propertyEditor.)
|
||||
var style, i = 0;
|
||||
@@ -610,7 +610,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
'contenteditable': false
|
||||
},
|
||||
embed.preview);
|
||||
|
||||
|
||||
// Only replace if activeElement is an Embed element.
|
||||
if (activeElement && activeElement.nodeName.toUpperCase() === "DIV" && activeElement.classList.contains("embeditem")){
|
||||
activeElement.replaceWith(wrapper); // directly replaces the html node
|
||||
@@ -738,9 +738,9 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
id: "__mcenew",
|
||||
"data-udi": img.udi
|
||||
};
|
||||
|
||||
|
||||
editor.selection.setContent(editor.dom.createHTML('img', data));
|
||||
|
||||
|
||||
// Using settimeout to wait for a DoM-render, so we can find the new element by ID.
|
||||
$timeout(function () {
|
||||
|
||||
@@ -761,7 +761,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1401,11 +1401,26 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
|
||||
function syncContent() {
|
||||
|
||||
if(args.model.value === args.editor.getContent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//stop watching before we update the value
|
||||
stopWatch();
|
||||
angularHelper.safeApply($rootScope, function () {
|
||||
args.model.value = args.editor.getContent();
|
||||
|
||||
//make the form dirty manually so that the track changes works, setting our model doesn't trigger
|
||||
// the angular bits because tinymce replaces the textarea.
|
||||
if (args.currentForm) {
|
||||
args.currentForm.$setDirty();
|
||||
}
|
||||
// With complex validation we need to set a input field to dirty, not the form. but we will keep the old code for backwards compatibility.
|
||||
if (args.currentFormInput) {
|
||||
args.currentFormInput.$setDirty();
|
||||
}
|
||||
});
|
||||
|
||||
//re-watch the value
|
||||
startWatch();
|
||||
}
|
||||
@@ -1430,7 +1445,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
|
||||
// Upload BLOB images (dragged/pasted ones)
|
||||
// find src attribute where value starts with `blob:`
|
||||
// search is case-insensitive and allows single or double quotes
|
||||
// search is case-insensitive and allows single or double quotes
|
||||
if(content.search(/src=["']blob:.*?["']/gi) !== -1){
|
||||
args.editor.uploadImages(function(data) {
|
||||
// Once all images have been uploaded
|
||||
@@ -1496,6 +1511,9 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
args.editor.on('Change', function (e) {
|
||||
syncContent();
|
||||
});
|
||||
args.editor.on('Keyup', function (e) {
|
||||
syncContent();
|
||||
});
|
||||
|
||||
//when we leave the editor (maybe)
|
||||
args.editor.on('blur', function (e) {
|
||||
@@ -1520,12 +1538,6 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
|
||||
args.editor.on('Dirty', function (e) {
|
||||
syncContent(); // Set model.value to the RTE's content
|
||||
|
||||
//make the form dirty manually so that the track changes works, setting our model doesn't trigger
|
||||
// the angular bits because tinymce replaces the textarea.
|
||||
if (args.currentForm) {
|
||||
args.currentForm.$setDirty();
|
||||
}
|
||||
});
|
||||
|
||||
let self = this;
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
padding: 2px 6px;
|
||||
}
|
||||
.umb-range-slider .noUi-handle {
|
||||
outline: none;
|
||||
cursor: grab;
|
||||
border-radius: 100px;
|
||||
border: none;
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
width="{{crop.width}}"
|
||||
max-size="75">
|
||||
</umb-image-thumbnail>
|
||||
<span class="__text">{{crop.alias}}</span>
|
||||
<span class="__text">{{crop.label}}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
<p style="background-color: #fee4e1; padding: 8px;"><strong>Important:</strong> switching from the (Obsolete) Media Picker to Media Picker will mean all data (references to previously selected media items) will be deleted and no longer available.</p>
|
||||
@@ -5,12 +5,12 @@ angular.module("umbraco")
|
||||
// TODO: A lot of the code below should be shared between the grid rte and the normal rte
|
||||
|
||||
$scope.isLoading = true;
|
||||
|
||||
|
||||
//To id the html textarea we need to use the datetime ticks because we can have multiple rte's per a single property alias
|
||||
// because now we have to support having 2x (maybe more at some stage) content editors being displayed at once. This is because
|
||||
// we have this mini content editor panel that can be launched with MNTP.
|
||||
$scope.textAreaHtmlId = $scope.model.alias + "_" + String.CreateGuid();
|
||||
|
||||
|
||||
var editorConfig = $scope.model.config ? $scope.model.config.editor : null;
|
||||
if (!editorConfig || Utilities.isString(editorConfig)) {
|
||||
editorConfig = tinyMceService.defaultPrevalues();
|
||||
@@ -28,14 +28,14 @@ angular.module("umbraco")
|
||||
$scope.containerOverflow = editorConfig.mode === "distraction-free" ? (height ? "auto" : "inherit") : "inherit";
|
||||
|
||||
var promises = [];
|
||||
|
||||
|
||||
// we need to make sure that the element is initialized before we can init TinyMCE, because we find the placeholder by ID, so it needs to be appended to document before.
|
||||
var initPromise = $q((resolve, reject) => {
|
||||
this.$onInit = resolve;
|
||||
});
|
||||
|
||||
|
||||
promises.push(initPromise);
|
||||
|
||||
|
||||
//queue file loading
|
||||
tinyMceAssets.forEach(function (tinyJsAsset) {
|
||||
promises.push(assetsService.loadJs(tinyJsAsset, $scope));
|
||||
@@ -50,50 +50,50 @@ angular.module("umbraco")
|
||||
toolbar: editorConfig.toolbar,
|
||||
mode: editorConfig.mode
|
||||
}));
|
||||
|
||||
|
||||
//wait for queue to end
|
||||
$q.all(promises).then(function (result) {
|
||||
|
||||
|
||||
var standardConfig = result[promises.length - 1];
|
||||
|
||||
|
||||
if (height !== null) {
|
||||
standardConfig.plugins.splice(standardConfig.plugins.indexOf("autoresize"), 1);
|
||||
}
|
||||
|
||||
|
||||
//create a baseline Config to extend upon
|
||||
var baseLineConfigObj = {
|
||||
maxImageSize: editorConfig.maxImageSize,
|
||||
width: width,
|
||||
height: height
|
||||
};
|
||||
|
||||
|
||||
baseLineConfigObj.setup = function (editor) {
|
||||
|
||||
|
||||
//set the reference
|
||||
tinyMceEditor = editor;
|
||||
|
||||
|
||||
tinyMceEditor.on('init', function (e) {
|
||||
$timeout(function () {
|
||||
$scope.isLoading = false;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
//initialize the standard editor functionality for Umbraco
|
||||
tinyMceService.initializeEditor({
|
||||
editor: editor,
|
||||
model: $scope.model,
|
||||
currentForm: angularHelper.getCurrentForm($scope)
|
||||
currentFormInput: $scope.rteForm.modelValue
|
||||
});
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
angular.extend(baseLineConfigObj, standardConfig);
|
||||
|
||||
|
||||
// We need to wait for DOM to have rendered before we can find the element by ID.
|
||||
$timeout(function () {
|
||||
tinymce.init(baseLineConfigObj);
|
||||
}, 150);
|
||||
|
||||
|
||||
//listen for formSubmitting event (the result is callback used to remove the event subscription)
|
||||
var unsubscribe = $scope.$on("formSubmitting", function () {
|
||||
if (tinyMceEditor !== undefined && tinyMceEditor != null && !$scope.isLoading) {
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.RTEController" class="umb-property-editor umb-rte" ng-class="{'--initialized': !isLoading}">
|
||||
<umb-load-indicator ng-if="isLoading"></umb-load-indicator>
|
||||
|
||||
<div class="umb-rte-editor-con">
|
||||
<input type="text" id="{{model.alias}}" ng-focus="focus()" style="position:absolute;top:0;width:0;height:0;" />
|
||||
<div disable-hotkeys id="{{textAreaHtmlId}}" class="umb-rte-editor" ng-style="{ width: containerWidth, height: containerHeight, overflow: containerOverflow}"></div>
|
||||
</div>
|
||||
<ng-form name="rteForm">
|
||||
<div class="umb-rte-editor-con">
|
||||
<input type="text" id="{{model.alias}}" ng-focus="focus()" name="modelValue" ng-model="model.value" style="position:absolute;top:0;width:0;height:0;" />
|
||||
<div disable-hotkeys id="{{textAreaHtmlId}}" class="umb-rte-editor" ng-style="{ width: containerWidth, height: containerHeight, overflow: containerOverflow}"></div>
|
||||
</div>
|
||||
</ng-form>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user