Merge branch 'v8/dev' into v8/contrib
# Conflicts: # src/Umbraco.Examine/ContentIndexPopulator.cs
This commit is contained in:
@@ -30,6 +30,7 @@ module.exports = {
|
||||
// js files for backoffice
|
||||
// processed in the js task
|
||||
js: {
|
||||
websitepreview: { files: "./src/websitepreview/**/*.js", out: "umbraco.websitepreview.js" },
|
||||
preview: { files: "./src/preview/**/*.js", out: "umbraco.preview.js" },
|
||||
installer: { files: "./src/installer/**/*.js", out: "umbraco.installer.js" },
|
||||
filters: { files: "./src/common/filters/**/*.js", out: "umbraco.filters.js" },
|
||||
@@ -56,7 +57,7 @@ module.exports = {
|
||||
],
|
||||
out: "umbraco.directives.js"
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
|
||||
//selectors for copying all views into the build
|
||||
|
||||
@@ -164,7 +164,7 @@
|
||||
|
||||
function inviteSavePassword() {
|
||||
|
||||
if (formHelper.submitForm({ scope: $scope })) {
|
||||
if (formHelper.submitForm({ scope: $scope, formCtrl: vm.inviteUserPasswordForm })) {
|
||||
|
||||
vm.invitedUserPasswordModel.buttonState = "busy";
|
||||
|
||||
@@ -172,7 +172,7 @@
|
||||
.then(function (data) {
|
||||
|
||||
//success
|
||||
formHelper.resetForm({ scope: $scope });
|
||||
formHelper.resetForm({ scope: $scope, formCtrl: vm.inviteUserPasswordForm });
|
||||
vm.invitedUserPasswordModel.buttonState = "success";
|
||||
//set the user and set them as logged in
|
||||
vm.invitedUser = data;
|
||||
@@ -181,7 +181,7 @@
|
||||
vm.inviteStep = 2;
|
||||
|
||||
}, function (err) {
|
||||
formHelper.resetForm({ scope: $scope, hasErrors: true });
|
||||
formHelper.resetForm({ scope: $scope, hasErrors: true, formCtrl: vm.inviteUserPasswordForm });
|
||||
formHelper.handleError(err);
|
||||
vm.invitedUserPasswordModel.buttonState = "error";
|
||||
});
|
||||
|
||||
@@ -57,14 +57,32 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
function replaceElementTypeBlockListUDIsResolver(obj, propClearingMethod) {
|
||||
replaceRawBlockListUDIsResolver(obj.value, propClearingMethod);
|
||||
function removeBlockReferences(obj) {
|
||||
for (var k in obj) {
|
||||
if(k === "contentUdi") {
|
||||
delete obj[k];
|
||||
} else if(k === "settingsUdi") {
|
||||
delete obj[k];
|
||||
} else {
|
||||
// lets crawl through all properties of layout to make sure get captured all `contentUdi` and `settingsUdi` properties.
|
||||
var propType = typeof obj[k];
|
||||
if(propType != null && (propType === "object" || propType === "array")) {
|
||||
removeBlockReferences(obj[k])
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
clipboardService.registerPastePropertyResolver(replaceElementTypeBlockListUDIsResolver, clipboardService.TYPES.ELEMENT_TYPE);
|
||||
|
||||
function elementTypeBlockResolver(obj, propPasteResolverMethod) {
|
||||
// we could filter for specific Property Editor Aliases, but as the Block Editor structure can be used by many Property Editor we do not in this code know a good way to detect that this is a Block Editor and will therefor leave it to the value structure to determin this.
|
||||
rawBlockResolver(obj.value, propPasteResolverMethod);
|
||||
}
|
||||
|
||||
clipboardService.registerPastePropertyResolver(elementTypeBlockResolver, clipboardService.TYPES.ELEMENT_TYPE);
|
||||
|
||||
|
||||
function replaceRawBlockListUDIsResolver(value, propClearingMethod) {
|
||||
function rawBlockResolver(value, propPasteResolverMethod) {
|
||||
if (value != null && typeof value === "object") {
|
||||
|
||||
// we got an object, and it has these three props then we are most likely dealing with a Block Editor.
|
||||
@@ -72,19 +90,19 @@
|
||||
|
||||
replaceUdisOfObject(value.layout, value);
|
||||
|
||||
// replace UDIs for inner properties of this Block Editors content data.
|
||||
// run resolvers for inner properties of this Blocks content data.
|
||||
if(value.contentData.length > 0) {
|
||||
value.contentData.forEach((item) => {
|
||||
for (var k in item) {
|
||||
propClearingMethod(item[k], clipboardService.TYPES.RAW);
|
||||
propPasteResolverMethod(item[k], clipboardService.TYPES.RAW);
|
||||
}
|
||||
});
|
||||
}
|
||||
// replace UDIs for inner properties of this Block Editors settings data.
|
||||
// run resolvers for inner properties of this Blocks settings data.
|
||||
if(value.settingsData.length > 0) {
|
||||
value.settingsData.forEach((item) => {
|
||||
for (var k in item) {
|
||||
propClearingMethod(item[k], clipboardService.TYPES.RAW);
|
||||
propPasteResolverMethod(item[k], clipboardService.TYPES.RAW);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -93,7 +111,29 @@
|
||||
}
|
||||
}
|
||||
|
||||
clipboardService.registerPastePropertyResolver(replaceRawBlockListUDIsResolver, clipboardService.TYPES.RAW);
|
||||
clipboardService.registerPastePropertyResolver(rawBlockResolver, clipboardService.TYPES.RAW);
|
||||
|
||||
|
||||
function provideNewUdisForBlockResolver(block, propPasteResolverMethod) {
|
||||
|
||||
if(block.layout) {
|
||||
// We do not support layout child blocks currently, these should be stripped out as we only will be copying a single entry.
|
||||
removeBlockReferences(block.layout);
|
||||
}
|
||||
|
||||
if(block.data) {
|
||||
// Make new UDI for content-element
|
||||
block.data.udi = block.layout.contentUdi = udiService.create("element");
|
||||
}
|
||||
|
||||
if(block.settingsData) {
|
||||
// Make new UDI for settings-element
|
||||
block.settingsData.udi = block.layout.settingsUdi = udiService.create("element");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
clipboardService.registerPastePropertyResolver(provideNewUdisForBlockResolver, clipboardService.TYPES.BLOCK);
|
||||
|
||||
}]);
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function blockEditorModelObjectFactory($interpolate, $q, udiService, contentResource, localizationService, umbRequestHelper, clipboardService) {
|
||||
function blockEditorModelObjectFactory($interpolate, $q, udiService, contentResource, localizationService, umbRequestHelper, clipboardService, notificationsService) {
|
||||
|
||||
/**
|
||||
* Simple mapping from property model content entry to editing model,
|
||||
@@ -773,6 +773,57 @@
|
||||
|
||||
return layoutEntry;
|
||||
|
||||
},
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name createFromBlockData
|
||||
* @methodOf umbraco.services.blockEditorModelObject
|
||||
* @description Insert data from raw models
|
||||
* @return {Object | null} Layout entry object, to be inserted at a decired location in the layout object. Or ´null´ if the given ElementType isnt supported by the block configuration.
|
||||
*/
|
||||
createFromBlockData: function (blockData) {
|
||||
|
||||
blockData = clipboardService.parseContentForPaste(blockData, clipboardService.TYPES.BLOCK);
|
||||
|
||||
// As the blockData is a cloned object we can use its layout part for our layout entry.
|
||||
var layoutEntry = blockData.layout;
|
||||
if (layoutEntry === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var blockConfiguration;
|
||||
|
||||
if (blockData.data) {
|
||||
// Ensure that we support the alias:
|
||||
blockConfiguration = this.getBlockConfiguration(blockData.data.contentTypeKey);
|
||||
if(blockConfiguration === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
this.value.contentData.push(blockData.data);
|
||||
} else {
|
||||
// We do not have data, this cannot be succesful paste.
|
||||
return null;
|
||||
}
|
||||
|
||||
if (blockData.settingsData) {
|
||||
// Ensure that we support the alias:
|
||||
if(blockConfiguration.settingsElementTypeKey) {
|
||||
// If we have settings for this Block Configuration, we need to check that they align, if we dont we do not want to fail.
|
||||
if(blockConfiguration.settingsElementTypeKey === blockData.settingsData.contentTypeKey) {
|
||||
this.value.settingsData.push(blockData.settingsData);
|
||||
} else {
|
||||
notificationsService.error("Clipboard", "Couldn't paste because settings-data is not compatible.");
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
// We do not have settings currently, so lets get rid of the settings part and move on with the paste.
|
||||
delete layoutEntry.settingUdi;
|
||||
}
|
||||
}
|
||||
|
||||
return layoutEntry;
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,33 +10,67 @@
|
||||
* The service has a set way for defining a data-set by a entryType and alias, which later will be used to retrive the posible entries for a paste scenario.
|
||||
*
|
||||
*/
|
||||
function clipboardService(notificationsService, eventsService, localStorageService, iconHelper) {
|
||||
function clipboardService($window, notificationsService, eventsService, localStorageService, iconHelper) {
|
||||
|
||||
|
||||
const TYPES = {};
|
||||
TYPES.ELEMENT_TYPE = "elementType";
|
||||
TYPES.BLOCK = "block";
|
||||
TYPES.RAW = "raw";
|
||||
|
||||
var clearPropertyResolvers = {};
|
||||
var pastePropertyResolvers = {};
|
||||
var clipboardTypeResolvers = {};
|
||||
|
||||
clipboardTypeResolvers[TYPES.ELEMENT_TYPE] = function(data, propMethod) {
|
||||
for (var t = 0; t < data.variants[0].tabs.length; t++) {
|
||||
var tab = data.variants[0].tabs[t];
|
||||
clipboardTypeResolvers[TYPES.ELEMENT_TYPE] = function(element, propMethod) {
|
||||
for (var t = 0; t < element.variants[0].tabs.length; t++) {
|
||||
var tab = element.variants[0].tabs[t];
|
||||
for (var p = 0; p < tab.properties.length; p++) {
|
||||
var prop = tab.properties[p];
|
||||
propMethod(prop, TYPES.ELEMENT_TYPE);
|
||||
}
|
||||
}
|
||||
}
|
||||
clipboardTypeResolvers[TYPES.BLOCK] = function (block, propMethod) {
|
||||
|
||||
propMethod(block, TYPES.BLOCK);
|
||||
|
||||
if(block.data) {
|
||||
Object.keys(block.data).forEach( key => {
|
||||
if(key === 'udi' || key === 'contentTypeKey') {
|
||||
return;
|
||||
}
|
||||
propMethod(block.data[key], TYPES.RAW);
|
||||
});
|
||||
}
|
||||
|
||||
if(block.settingsData) {
|
||||
Object.keys(block.settingsData).forEach( key => {
|
||||
if(key === 'udi' || key === 'contentTypeKey') {
|
||||
return;
|
||||
}
|
||||
propMethod(block.settingsData[key], TYPES.RAW);
|
||||
});
|
||||
}
|
||||
|
||||
/*
|
||||
// Concept for supporting Block that contains other Blocks.
|
||||
// Missing clarifications:
|
||||
// How do we ensure that the inner blocks of a block is supported in the new scenario. Not that likely but still relevant, so considerations should be made.
|
||||
if(block.references) {
|
||||
// A Block clipboard entry can contain other Block Clipboard Entries, here we will make sure to resolve those identical to the main entry.
|
||||
for (var r = 0; r < block.references.length; r++) {
|
||||
clipboardTypeResolvers[TYPES.BLOCK](block.references[r], propMethod);
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
clipboardTypeResolvers[TYPES.RAW] = function(data, propMethod) {
|
||||
for (var p = 0; p < data.length; p++) {
|
||||
propMethod(data[p], TYPES.RAW);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var STORAGE_KEY = "umbClipboardService";
|
||||
|
||||
var retriveStorage = function() {
|
||||
@@ -64,7 +98,10 @@ function clipboardService(notificationsService, eventsService, localStorageServi
|
||||
var storageString = JSON.stringify(storage);
|
||||
|
||||
try {
|
||||
// Check that we can parse the JSON:
|
||||
var storageJSON = JSON.parse(storageString);
|
||||
|
||||
// Store the string:
|
||||
localStorageService.set(STORAGE_KEY, storageString);
|
||||
|
||||
eventsService.emit("clipboardService.storageUpdate");
|
||||
@@ -82,11 +119,11 @@ function clipboardService(notificationsService, eventsService, localStorageServi
|
||||
|
||||
type = type || "raw";
|
||||
var resolvers = clearPropertyResolvers[type];
|
||||
|
||||
for (var i=0; i<resolvers.length; i++) {
|
||||
resolvers[i](prop, resolvePropertyForStorage);
|
||||
if (resolvers) {
|
||||
for (var i=0; i<resolvers.length; i++) {
|
||||
resolvers[i](prop, resolvePropertyForStorage);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var prepareEntryForStorage = function(type, entryData, firstLevelClearupMethod) {
|
||||
@@ -123,9 +160,10 @@ function clipboardService(notificationsService, eventsService, localStorageServi
|
||||
|
||||
type = type || "raw";
|
||||
var resolvers = pastePropertyResolvers[type];
|
||||
|
||||
for (var i=0; i<resolvers.length; i++) {
|
||||
resolvers[i](prop, resolvePropertyForPaste);
|
||||
if (resolvers) {
|
||||
for (var i=0; i<resolvers.length; i++) {
|
||||
resolvers[i](prop, resolvePropertyForPaste);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,7 +192,7 @@ function clipboardService(notificationsService, eventsService, localStorageServi
|
||||
var cloneData = Utilities.copy(pasteEntryData);
|
||||
|
||||
var typeResolver = clipboardTypeResolvers[type];
|
||||
if(typeResolver) {
|
||||
if (typeResolver) {
|
||||
typeResolver(cloneData, resolvePropertyForPaste);
|
||||
} else {
|
||||
console.warn("Umbraco.service.clipboardService has no type resolver for '" + type + "'.");
|
||||
@@ -427,10 +465,17 @@ function clipboardService(notificationsService, eventsService, localStorageServi
|
||||
};
|
||||
|
||||
|
||||
var emitClipboardStorageUpdate = _.debounce(function(e) {
|
||||
eventsService.emit("clipboardService.storageUpdate");
|
||||
}, 1000);
|
||||
|
||||
// Fires if LocalStorage was changed from another tab than this one.
|
||||
$window.addEventListener("storage", emitClipboardStorageUpdate);
|
||||
|
||||
|
||||
|
||||
return service;
|
||||
}
|
||||
|
||||
|
||||
angular.module("umbraco.services").factory("clipboardService", clipboardService);
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ function externalLoginInfoService(externalLoginInfo, umbRequestHelper) {
|
||||
}
|
||||
|
||||
function getLoginProviderView(provider) {
|
||||
if (provider && provider.properties.UmbracoBackOfficeExternalLoginOptions && provider.properties.UmbracoBackOfficeExternalLoginOptions.CustomBackOfficeView) {
|
||||
if (provider && provider.properties && provider.properties.UmbracoBackOfficeExternalLoginOptions && provider.properties.UmbracoBackOfficeExternalLoginOptions.CustomBackOfficeView) {
|
||||
return umbRequestHelper.convertVirtualToAbsolutePath(provider.properties.UmbracoBackOfficeExternalLoginOptions.CustomBackOfficeView);
|
||||
}
|
||||
return null;
|
||||
@@ -26,10 +26,10 @@ function externalLoginInfoService(externalLoginInfo, umbRequestHelper) {
|
||||
*/
|
||||
function hasDenyLocalLogin(provider) {
|
||||
if (!provider) {
|
||||
return _.some(externalLoginInfo.providers, x => x.properties.UmbracoBackOfficeExternalLoginOptions.DenyLocalLogin === true);
|
||||
return _.some(externalLoginInfo.providers, x => x.properties && x.properties.UmbracoBackOfficeExternalLoginOptions && (x.properties.UmbracoBackOfficeExternalLoginOptions.DenyLocalLogin === true));
|
||||
}
|
||||
else {
|
||||
return provider.properties.UmbracoBackOfficeExternalLoginOptions.DenyLocalLogin;
|
||||
return provider && provider.properties && provider.properties.UmbracoBackOfficeExternalLoginOptions && (provider.properties.UmbracoBackOfficeExternalLoginOptions.DenyLocalLogin === true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -101,6 +101,7 @@
|
||||
|
||||
}
|
||||
|
||||
|
||||
&__check {
|
||||
display: flex;
|
||||
position: relative;
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
yeah so this is a pain, but we must be super specific in targeting the mandatory property labels,
|
||||
otherwise all properties within a reqired, nested, nested content property will all appear mandatory
|
||||
*/
|
||||
> ng-form > .control-group > .umb-el-wrap > .control-header label:after {
|
||||
.umb-property > ng-form > .control-group > .umb-el-wrap > .control-header label:after {
|
||||
content: '*';
|
||||
color: @red;
|
||||
}
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
|
||||
var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.services'])
|
||||
|
||||
.controller("previewController", function ($scope, $window, $location) {
|
||||
.controller("previewController", function ($scope, $window, $location, $http) {
|
||||
|
||||
$scope.currentCulture = { iso: '', title: '...', icon: 'icon-loading' }
|
||||
var cultures = [];
|
||||
|
||||
$scope.tabbingActive = false;
|
||||
// There are a number of ways to detect when a focus state should be shown when using the tab key and this seems to be the simplest solution.
|
||||
// There are a number of ways to detect when a focus state should be shown when using the tab key and this seems to be the simplest solution.
|
||||
// For more information about this approach, see https://hackernoon.com/removing-that-ugly-focus-ring-and-keeping-it-too-6c8727fefcd2
|
||||
function handleFirstTab(evt) {
|
||||
if (evt.keyCode === 9) {
|
||||
@@ -110,7 +110,7 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi
|
||||
if (isInit === "true") {
|
||||
//do not continue, this is the first load of this new window, if this is passed in it means it's been
|
||||
//initialized by the content editor and then the content editor will actually re-load this window without
|
||||
//this flag. This is a required trick to get around chrome popup mgr.
|
||||
//this flag. This is a required trick to get around chrome popup mgr.
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi
|
||||
|
||||
$scope.valueAreLoaded = false;
|
||||
$scope.devices = [
|
||||
{ name: "fullsize", css: "fullsize", icon: "icon-application-window-alt", title: "Browser" },
|
||||
{ name: "fullsize", css: "fullsize", icon: "icon-application-window-alt", title: "Fit browser" },
|
||||
{ name: "desktop", css: "desktop shadow", icon: "icon-display", title: "Desktop" },
|
||||
{ name: "laptop - 1366px", css: "laptop shadow", icon: "icon-laptop", title: "Laptop" },
|
||||
{ name: "iPad portrait - 768px", css: "iPad-portrait shadow", icon: "icon-ipad", title: "Tablet portrait" },
|
||||
@@ -157,17 +157,33 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi
|
||||
$scope.windowClickHandler = function () {
|
||||
closeOthers();
|
||||
}
|
||||
|
||||
function windowBlurHandler() {
|
||||
closeOthers();
|
||||
$scope.$digest();
|
||||
}
|
||||
window.addEventListener("blur", windowBlurHandler);
|
||||
|
||||
var win = $($window);
|
||||
function windowVisibilityHandler(e) {
|
||||
|
||||
win.on("blur", windowBlurHandler);
|
||||
var amountOfPreviewSessions = localStorage.getItem('UmbPreviewSessionAmount');
|
||||
|
||||
// When tab is visible again:
|
||||
if(document.hidden === false) {
|
||||
checkPreviewState();
|
||||
}
|
||||
}
|
||||
document.addEventListener("visibilitychange", windowVisibilityHandler);
|
||||
|
||||
function beforeUnloadHandler(e) {
|
||||
endPreviewSession();
|
||||
}
|
||||
window.addEventListener("beforeunload", beforeUnloadHandler, false);
|
||||
|
||||
$scope.$on("$destroy", function () {
|
||||
win.off("blur", handleBlwindowBlurHandlerur);
|
||||
window.removeEventListener("blur", windowBlurHandler);
|
||||
document.removeEventListener("visibilitychange", windowVisibilityHandler);
|
||||
window.removeEventListener("beforeunload", beforeUnloadHandler);
|
||||
});
|
||||
|
||||
|
||||
@@ -183,6 +199,197 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi
|
||||
$scope.pageUrl = "frame?" + query;
|
||||
}
|
||||
}
|
||||
function getCookie(cname) {
|
||||
var name = cname + "=";
|
||||
var ca = document.cookie.split(";");
|
||||
for(var i = 0; i < ca.length; i++) {
|
||||
var c = ca[i];
|
||||
while (c.charAt(0) == " ") {
|
||||
c = c.substring(1);
|
||||
}
|
||||
if (c.indexOf(name) == 0) {
|
||||
return c.substring(name.length, c.length);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function setCookie(cname, cvalue, exminutes) {
|
||||
var d = new Date();
|
||||
d.setTime(d.getTime() + (exminutes * 60 * 1000));
|
||||
document.cookie = cname + "=" + cvalue + ";expires="+d.toUTCString() + ";path=/";
|
||||
}
|
||||
var hasPreviewDialog = false;
|
||||
function checkPreviewState() {
|
||||
if (getCookie("UMB_PREVIEW") === null) {
|
||||
|
||||
if(hasPreviewDialog === true) return;
|
||||
hasPreviewDialog = true;
|
||||
|
||||
// Ask to re-enter preview mode?
|
||||
|
||||
const localizeVarsFallback = {
|
||||
"returnToPreviewHeadline": "Preview content?",
|
||||
"returnToPreviewDescription":"You have ended preview mode, do you want to continue previewing this content?",
|
||||
"returnToPreviewButton":"Preview"
|
||||
};
|
||||
const umbLocalizedVars = Object.assign(localizeVarsFallback, $window.umbLocalizedVars);
|
||||
|
||||
|
||||
// This modal is also used in websitepreview.js
|
||||
var modelStyles = `
|
||||
|
||||
/* Webfont: LatoLatin-Bold */
|
||||
@font-face {
|
||||
font-family: 'Lato';
|
||||
src: url('https://fonts.googleapis.com/css2?family=Lato:wght@700&display=swap');
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
.umbraco-preview-dialog {
|
||||
position: fixed;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 99999999;
|
||||
top:0;
|
||||
bottom:0;
|
||||
left:0;
|
||||
right:0;
|
||||
overflow: auto;
|
||||
background-color: rgba(0,0,0,0.6);
|
||||
}
|
||||
|
||||
.umbraco-preview-dialog__modal {
|
||||
background-color: #fff;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 3px 7px rgba(0,0,0,0.3);
|
||||
margin: auto;
|
||||
padding: 30px 40px;
|
||||
width: 100%;
|
||||
max-width: 540px;
|
||||
font-family: Lato,Helvetica Neue,Helvetica,Arial,sans-serif;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.umbraco-preview-dialog__headline {
|
||||
font-weight: 700;
|
||||
font-size: 22px;
|
||||
color: #1b264f;
|
||||
margin-top:10px;
|
||||
margin-bottom:20px;
|
||||
}
|
||||
.umbraco-preview-dialog__question {
|
||||
margin-bottom:30px;
|
||||
}
|
||||
.umbraco-preview-dialog__modal > button {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
padding: 8px 18px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
border-radius: 3px;
|
||||
border:none;
|
||||
font-family: inherit;
|
||||
font-weight: 700;
|
||||
font-size: 15px;
|
||||
float:right;
|
||||
margin-left:10px;
|
||||
|
||||
color: #1b264f;
|
||||
background-color: #f6f1ef;
|
||||
}
|
||||
.umbraco-preview-dialog__modal > button:hover {
|
||||
color: #2152a3;
|
||||
background-color: #f6f1ef;
|
||||
}
|
||||
.umbraco-preview-dialog__modal > button.umbraco-preview-dialog__continue {
|
||||
color: #fff;
|
||||
background-color: #2bc37c;
|
||||
}
|
||||
.umbraco-preview-dialog__modal > button.umbraco-preview-dialog__continue:hover {
|
||||
background-color: #39d38b;
|
||||
}
|
||||
`;
|
||||
|
||||
var bodyEl = document.getElementsByTagName("BODY")[0];
|
||||
|
||||
var fragment = document.createElement("div");
|
||||
var shadowRoot = fragment.attachShadow({ mode: 'open' });
|
||||
|
||||
var style = document.createElement("style");
|
||||
style.innerHTML = modelStyles;
|
||||
shadowRoot.appendChild(style);
|
||||
|
||||
var con = document.createElement("div");
|
||||
con.className = "umbraco-preview-dialog";
|
||||
shadowRoot.appendChild(con);
|
||||
|
||||
var modal = document.createElement("div");
|
||||
modal.className = "umbraco-preview-dialog__modal";
|
||||
modal.innerHTML = `<div class="umbraco-preview-dialog__headline">${umbLocalizedVars.returnToPreviewHeadline}</div>
|
||||
<div class="umbraco-preview-dialog__question">${umbLocalizedVars.returnToPreviewDescription}</div>`;
|
||||
con.appendChild(modal);
|
||||
|
||||
var continueButton = document.createElement("button");
|
||||
continueButton.type = "button";
|
||||
continueButton.className = "umbraco-preview-dialog__continue";
|
||||
continueButton.innerHTML = umbLocalizedVars.returnToPreviewButton;
|
||||
continueButton.addEventListener("click", () => {
|
||||
bodyEl.removeChild(fragment);
|
||||
reenterPreviewMode();
|
||||
hasPreviewDialog = false;
|
||||
});
|
||||
modal.appendChild(continueButton);
|
||||
|
||||
bodyEl.appendChild(fragment);
|
||||
continueButton.focus();
|
||||
|
||||
}
|
||||
}
|
||||
function reenterPreviewMode() {
|
||||
//Re-enter Preview Mode
|
||||
$http({
|
||||
method: 'POST',
|
||||
url: '../preview/enterPreview',
|
||||
params: {
|
||||
id: $scope.pageId
|
||||
}
|
||||
})
|
||||
startPreviewSession();
|
||||
}
|
||||
function getPageURL() {
|
||||
var culture = $location.search().culture || getParameterByName("culture");
|
||||
var relativeUrl = "/" + $scope.pageId;
|
||||
if (culture) {
|
||||
relativeUrl += '?culture=' + culture;
|
||||
}
|
||||
return relativeUrl;
|
||||
}
|
||||
|
||||
function startPreviewSession() {
|
||||
// lets registrer this preview session.
|
||||
var amountOfPreviewSessions = Math.max(localStorage.getItem('UmbPreviewSessionAmount') || 0, 0);
|
||||
amountOfPreviewSessions++;
|
||||
localStorage.setItem('UmbPreviewSessionAmount', amountOfPreviewSessions);
|
||||
}
|
||||
function resetPreviewSessions() {
|
||||
localStorage.setItem('UmbPreviewSessionAmount', 0);
|
||||
}
|
||||
function endPreviewSession() {
|
||||
var amountOfPreviewSessions = localStorage.getItem('UmbPreviewSessionAmount') || 0;
|
||||
amountOfPreviewSessions--;
|
||||
localStorage.setItem('UmbPreviewSessionAmount', amountOfPreviewSessions);
|
||||
|
||||
if(amountOfPreviewSessions <= 0) {
|
||||
// We are good to end preview mode.
|
||||
navigator.sendBeacon("../preview/end");
|
||||
}
|
||||
}
|
||||
startPreviewSession();
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Preview devices */
|
||||
/*****************************************************************************/
|
||||
@@ -192,21 +399,26 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi
|
||||
$scope.previewDevice = device;
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Open website in preview mode */
|
||||
/*****************************************************************************/
|
||||
|
||||
$scope.openInBrowser = function () {
|
||||
setCookie("UMB-WEBSITE-PREVIEW-ACCEPT", "true", 5);
|
||||
window.open(getPageURL(), "_blank");
|
||||
};
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Exit Preview */
|
||||
/*****************************************************************************/
|
||||
|
||||
$scope.exitPreview = function () {
|
||||
|
||||
var culture = $location.search().culture || getParameterByName("culture");
|
||||
var relativeUrl = "/" + $scope.pageId;
|
||||
if (culture) {
|
||||
relativeUrl += '?culture=' + culture;
|
||||
}
|
||||
window.top.location.href = "../preview/end?redir=" + encodeURIComponent(relativeUrl);
|
||||
resetPreviewSessions();
|
||||
window.top.location.href = "../preview/end?redir=" + encodeURIComponent(getPageURL());
|
||||
};
|
||||
|
||||
$scope.onFrameLoaded = function (iframe) {
|
||||
|
||||
$scope.frameLoaded = true;
|
||||
configureSignalR(iframe);
|
||||
|
||||
@@ -260,8 +472,8 @@ var app = angular.module("umbraco.preview", ['umbraco.resources', 'umbraco.servi
|
||||
var vm = this;
|
||||
|
||||
vm.$postLink = function () {
|
||||
var resultFrame = $element.find("#resultFrame");
|
||||
resultFrame.on("load", iframeReady);
|
||||
var resultFrame = $element.find("#resultFrame").get(0);
|
||||
resultFrame.addEventListener("load", iframeReady);
|
||||
};
|
||||
|
||||
function iframeReady() {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
<div ng-if="!vm.denyLocalLogin" ng-show="vm.invitedUser != null" class="umb-login-container">
|
||||
|
||||
<form name="inviteUserPasswordForm" novalidate="" ng-submit="vm.inviteSavePassword()" val-form-manager>
|
||||
<form name="vm.inviteUserPasswordForm" novalidate="" ng-submit="vm.inviteSavePassword()" val-form-manager>
|
||||
<div class="form" ng-if="vm.inviteStep === 1">
|
||||
<h1 style="margin-bottom: 10px; text-align: left;">Hi, {{vm.invitedUser.name}}</h1>
|
||||
<p style="line-height: 1.6; margin-bottom: 25px;">
|
||||
@@ -79,7 +79,7 @@
|
||||
size="xl"
|
||||
unknown-char="+"
|
||||
img-src="{{vm.invitedUser.avatars[3]}}"
|
||||
img-srcset="{{vm.invitedUser.avatars[4]}} 2x, {{invitedUser.avatars[4]}} 3x">
|
||||
img-srcset="{{vm.invitedUser.avatars[4]}} 2x, {{vm.invitedUser.avatars[4]}} 3x">
|
||||
</umb-avatar>
|
||||
</a>
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
|
||||
<div class="__showcase"
|
||||
ng-class="{'--error':vm.elementTypeModel === null}"
|
||||
ng-style="{'background-color':vm.blockConfigModel.backgroundColor, 'background-image': vm.styleBackgroundImage}">
|
||||
<i ng-if="vm.blockConfigModel.thumbnail == null" class="__icon {{ vm.elementTypeModel ? vm.elementTypeModel.icon : 'icon-block' }}" ng-attr-style="{{'color:'+vm.blockConfigModel.iconColor+' !important'}}" aria-hidden="true"></i>
|
||||
ng-style="{'background-color': vm.blockConfigModel ? vm.blockConfigModel.backgroundColor : '', 'background-image': vm.styleBackgroundImage}">
|
||||
<i ng-if="vm.blockConfigModel == null || vm.blockConfigModel.thumbnail == null" class="__icon {{ vm.elementTypeModel ? vm.elementTypeModel.icon : 'icon-block' }}" ng-attr-style="{{'color:'+vm.blockConfigModel.iconColor+' !important'}}" aria-hidden="true"></i>
|
||||
</div>
|
||||
<div class="__info" ng-if="vm.elementTypeModel !== null">
|
||||
<div class="__name" ng-bind="vm.elementTypeModel.name"></div>
|
||||
|
||||
@@ -7,12 +7,13 @@ umb-block-card {
|
||||
background-color: white;
|
||||
border-radius: @doubleBorderRadius;
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,.2);
|
||||
overflow: hidden;
|
||||
|
||||
transition: box-shadow 120ms;
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
.umb-outline();
|
||||
|
||||
&:hover {
|
||||
box-shadow: 0 1px 3px rgba(@ui-action-type-hover, .5);
|
||||
}
|
||||
@@ -60,6 +61,9 @@ umb-block-card {
|
||||
background-size: cover;
|
||||
background-position: 50% 50%;
|
||||
background-repeat: no-repeat;
|
||||
|
||||
border-top-left-radius: @doubleBorderRadius;
|
||||
border-top-right-radius: @doubleBorderRadius;
|
||||
|
||||
&.--error {
|
||||
border: 2px solid @errorBackground;
|
||||
@@ -85,6 +89,8 @@ umb-block-card {
|
||||
background-color: #fff;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 11px;// 10 + 1 to compentiate for the -1 substraction in margin-bottom.
|
||||
border-bottom-left-radius: @doubleBorderRadius;
|
||||
border-bottom-right-radius: @doubleBorderRadius;
|
||||
|
||||
&.--error {
|
||||
background-color: @errorBackground;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
controllerAs: "vm",
|
||||
transclude: true,
|
||||
bindings: {
|
||||
blockConfigModel: "<",
|
||||
blockConfigModel: "<?",
|
||||
elementTypeModel: "<"
|
||||
}
|
||||
});
|
||||
@@ -35,7 +35,7 @@
|
||||
}
|
||||
|
||||
vm.updateThumbnail = function () {
|
||||
if (vm.blockConfigModel.thumbnail == null || vm.blockConfigModel.thumbnail === "") {
|
||||
if (vm.blockConfigModel == null || vm.blockConfigModel.thumbnail == null || vm.blockConfigModel.thumbnail === "") {
|
||||
vm.styleBackgroundImage = "none";
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -138,10 +138,10 @@
|
||||
|
||||
// We need to ensure that the property model value is an object, this is needed for modelObject to recive a reference and keep that updated.
|
||||
if (typeof newVal !== 'object' || newVal === null) {// testing if we have null or undefined value or if the value is set to another type than Object.
|
||||
newVal = {};
|
||||
vm.model.value = newVal = {};
|
||||
}
|
||||
|
||||
modelObject.update(newVal, $scope);
|
||||
modelObject.update(vm.model.value, $scope);
|
||||
onLoaded();
|
||||
}
|
||||
|
||||
@@ -430,12 +430,12 @@
|
||||
if (Array.isArray(item.pasteData)) {
|
||||
var indexIncrementor = 0;
|
||||
item.pasteData.forEach(function (entry) {
|
||||
if (requestPasteFromClipboard(createIndex + indexIncrementor, entry)) {
|
||||
if (requestPasteFromClipboard(createIndex + indexIncrementor, entry, item.type)) {
|
||||
indexIncrementor++;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
requestPasteFromClipboard(createIndex, item.pasteData);
|
||||
requestPasteFromClipboard(createIndex, item.pasteData, item.type);
|
||||
}
|
||||
if(!(mouseEvent.ctrlKey || mouseEvent.metaKey)) {
|
||||
blockPickerModel.close();
|
||||
@@ -470,6 +470,7 @@
|
||||
|
||||
blockPickerModel.clickClearClipboard = function ($event) {
|
||||
clipboardService.clearEntriesOfType(clipboardService.TYPES.ELEMENT_TYPE, vm.availableContentTypesAliases);
|
||||
clipboardService.clearEntriesOfType(clipboardService.TYPES.BLOCK, vm.availableContentTypesAliases);
|
||||
};
|
||||
|
||||
blockPickerModel.clipboardItems = [];
|
||||
@@ -485,10 +486,28 @@
|
||||
icon: entry.icon
|
||||
}
|
||||
}
|
||||
if(Array.isArray(pasteEntry.data) === false) {
|
||||
pasteEntry.blockConfigModel = modelObject.getScaffoldFromAlias(entry.alias);
|
||||
} else {
|
||||
pasteEntry.blockConfigModel = {};
|
||||
if(Array.isArray(entry.data) === false) {
|
||||
var scaffold = modelObject.getScaffoldFromAlias(entry.alias);
|
||||
if(scaffold) {
|
||||
pasteEntry.blockConfigModel = modelObject.getBlockConfiguration(scaffold.contentTypeKey);
|
||||
}
|
||||
}
|
||||
blockPickerModel.clipboardItems.push(pasteEntry);
|
||||
});
|
||||
|
||||
var entriesForPaste = clipboardService.retriveEntriesOfType(clipboardService.TYPES.BLOCK, vm.availableContentTypesAliases);
|
||||
entriesForPaste.forEach(function (entry) {
|
||||
var pasteEntry = {
|
||||
type: clipboardService.TYPES.BLOCK,
|
||||
date: entry.date,
|
||||
pasteData: entry.data,
|
||||
elementTypeModel: {
|
||||
name: entry.label,
|
||||
icon: entry.icon
|
||||
}
|
||||
}
|
||||
if(Array.isArray(entry.data) === false) {
|
||||
pasteEntry.blockConfigModel = modelObject.getBlockConfiguration(entry.data.data.contentTypeKey);
|
||||
}
|
||||
blockPickerModel.clipboardItems.push(pasteEntry);
|
||||
});
|
||||
@@ -504,42 +523,67 @@
|
||||
|
||||
var requestCopyAllBlocks = function() {
|
||||
|
||||
var elementTypesToCopy = vm.layout.filter(entry => entry.$block.config.unsupported !== true).map(entry => entry.$block.content);
|
||||
var aliases = [];
|
||||
|
||||
// list aliases
|
||||
var aliases = elementTypesToCopy.map(content => content.contentTypeAlias);
|
||||
var elementTypesToCopy = vm.layout.filter(entry => entry.$block.config.unsupported !== true).map(
|
||||
(entry) => {
|
||||
|
||||
// remove dublicates
|
||||
aliases.push(entry.$block.content.contentTypeAlias);
|
||||
|
||||
// No need to clone the data as its begin handled by the clipboardService.
|
||||
return {"layout": entry.$block.layout, "data": entry.$block.data, "settingsData":entry.$block.settingsData}
|
||||
}
|
||||
);
|
||||
|
||||
// remove duplicate aliases
|
||||
aliases = aliases.filter((item, index) => aliases.indexOf(item) === index);
|
||||
|
||||
var contentNodeName = "";
|
||||
var contentNodeName = "?";
|
||||
var contentNodeIcon = null;
|
||||
if(vm.umbVariantContent) {
|
||||
contentNodeName = vm.umbVariantContent.editor.content.name;
|
||||
if(vm.umbVariantContentEditors) {
|
||||
contentNodeIcon = vm.umbVariantContentEditors.content.icon.split(" ")[0];
|
||||
} else if (vm.umbElementEditorContent) {
|
||||
contentNodeIcon = vm.umbElementEditorContent.model.documentType.icon.split(" ")[0];
|
||||
}
|
||||
} else if (vm.umbElementEditorContent) {
|
||||
contentNodeName = vm.umbElementEditorContent.model.documentType.name
|
||||
contentNodeName = vm.umbElementEditorContent.model.documentType.name;
|
||||
contentNodeIcon = vm.umbElementEditorContent.model.documentType.icon.split(" ")[0];
|
||||
}
|
||||
|
||||
localizationService.localize("clipboard_labelForArrayOfItemsFrom", [vm.model.label, contentNodeName]).then(function(localizedLabel) {
|
||||
clipboardService.copyArray(clipboardService.TYPES.ELEMENT_TYPE, aliases, elementTypesToCopy, localizedLabel, "icon-thumbnail-list", vm.model.id);
|
||||
clipboardService.copyArray(clipboardService.TYPES.BLOCK, aliases, elementTypesToCopy, localizedLabel, contentNodeIcon || "icon-thumbnail-list", vm.model.id);
|
||||
});
|
||||
}
|
||||
function copyBlock(block) {
|
||||
clipboardService.copy(clipboardService.TYPES.ELEMENT_TYPE, block.content.contentTypeAlias, block.content, block.label);
|
||||
clipboardService.copy(clipboardService.TYPES.BLOCK, block.content.contentTypeAlias, {"layout": block.layout, "data": block.data, "settingsData":block.settingsData}, block.label, block.content.icon, block.content.udi);
|
||||
}
|
||||
function requestPasteFromClipboard(index, pasteEntry) {
|
||||
function requestPasteFromClipboard(index, pasteEntry, pasteType) {
|
||||
|
||||
if (pasteEntry === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var layoutEntry = modelObject.createFromElementType(pasteEntry);
|
||||
var layoutEntry;
|
||||
if (pasteType === clipboardService.TYPES.ELEMENT_TYPE) {
|
||||
layoutEntry = modelObject.createFromElementType(pasteEntry);
|
||||
} else if (pasteType === clipboardService.TYPES.BLOCK) {
|
||||
layoutEntry = modelObject.createFromBlockData(pasteEntry);
|
||||
} else {
|
||||
// Not a supported paste type.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (layoutEntry === null) {
|
||||
// Pasting did not go well.
|
||||
return false;
|
||||
}
|
||||
|
||||
// make block model
|
||||
var blockObject = getBlockObject(layoutEntry);
|
||||
if (blockObject === null) {
|
||||
// Initalization of the Block Object didnt go well, therefor we will fail the paste action.
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -554,6 +598,7 @@
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
function requestDeleteBlock(block) {
|
||||
localizationService.localizeMany(["general_delete", "blockEditor_confirmDeleteBlockMessage", "contentTypeEditor_yesDelete"]).then(function (data) {
|
||||
const overlay = {
|
||||
|
||||
227
src/Umbraco.Web.UI.Client/src/websitepreview/websitepreview.js
Normal file
227
src/Umbraco.Web.UI.Client/src/websitepreview/websitepreview.js
Normal file
@@ -0,0 +1,227 @@
|
||||
|
||||
/*********************************************************************************************************/
|
||||
/* website preview */
|
||||
/*********************************************************************************************************/
|
||||
|
||||
(function() {
|
||||
|
||||
|
||||
if ( window.location !== window.parent.location ) {
|
||||
//we are in an iFrame, so lets skip the dialog.
|
||||
return;
|
||||
}
|
||||
|
||||
const scriptElement = document.currentScript;
|
||||
|
||||
function setCookie(cname, cvalue, exminutes) {
|
||||
var d = new Date();
|
||||
d.setTime(d.getTime() + (exminutes * 60 * 1000));
|
||||
document.cookie = cname + "=" + cvalue + ";expires="+d.toUTCString() + ";path=/";
|
||||
}
|
||||
|
||||
function getCookie(cname) {
|
||||
var name = cname + "=";
|
||||
var ca = document.cookie.split(";");
|
||||
for(var i = 0; i < ca.length; i++) {
|
||||
var c = ca[i];
|
||||
while (c.charAt(0) == " ") {
|
||||
c = c.substring(1);
|
||||
}
|
||||
if (c.indexOf(name) == 0) {
|
||||
return c.substring(name.length, c.length);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
function beforeUnloadHandler(e) {
|
||||
endPreviewSession();
|
||||
}
|
||||
window.addEventListener("beforeunload", beforeUnloadHandler, false);
|
||||
|
||||
function startPreviewSession() {
|
||||
// lets registrer this preview session.
|
||||
var amountOfPreviewSessions = Math.max(localStorage.getItem('UmbPreviewSessionAmount') || 0, 0);
|
||||
amountOfPreviewSessions++;
|
||||
localStorage.setItem('UmbPreviewSessionAmount', amountOfPreviewSessions);
|
||||
}
|
||||
function resetPreviewSessions() {
|
||||
localStorage.setItem('UmbPreviewSessionAmount', 0);
|
||||
}
|
||||
function endPreviewSession() {
|
||||
var amountOfPreviewSessions = localStorage.getItem('UmbPreviewSessionAmount') || 0;
|
||||
amountOfPreviewSessions--;
|
||||
localStorage.setItem('UmbPreviewSessionAmount', amountOfPreviewSessions);
|
||||
|
||||
if(amountOfPreviewSessions <= 0) {
|
||||
// We are good to secretly end preview mode.
|
||||
navigator.sendBeacon(scriptElement.getAttribute("data-umbraco-path")+"/preview/end");
|
||||
}
|
||||
}
|
||||
startPreviewSession();
|
||||
|
||||
function endPreviewMode() {
|
||||
resetPreviewSessions();
|
||||
window.top.location.href = scriptElement.getAttribute("data-umbraco-path")+"/preview/end?redir=" + encodeURIComponent(window.location.pathname+window.location.search);
|
||||
}
|
||||
function continuePreviewMode(minutsToExpire) {
|
||||
setCookie("UMB-WEBSITE-PREVIEW-ACCEPT", "true", minutsToExpire || 4);
|
||||
}
|
||||
|
||||
var user = getCookie("UMB-WEBSITE-PREVIEW-ACCEPT");
|
||||
if (user != "true") {
|
||||
askToViewPublishedVersion();
|
||||
} else {
|
||||
continuePreviewMode();
|
||||
}
|
||||
|
||||
function askToViewPublishedVersion() {
|
||||
|
||||
scriptElement.getAttribute("data-umbraco-path");
|
||||
|
||||
const request = new XMLHttpRequest();
|
||||
request.open("GET", scriptElement.getAttribute("data-umbraco-path") + "/LocalizedText");
|
||||
request.send();
|
||||
|
||||
request.onreadystatechange = (e) => {
|
||||
if (request.readyState == 4 && request.status == 200) {
|
||||
const jsonLocalization = JSON.parse(request.responseText);
|
||||
createAskUserAboutVersionDialog(jsonLocalization);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
function createAskUserAboutVersionDialog(jsonLocalization) {
|
||||
|
||||
const localizeVarsFallback = {
|
||||
"viewPublishedContentHeadline": "Preview content?",
|
||||
"viewPublishedContentDescription":"You have ended preview mode, do you want to continue previewing this content?",
|
||||
"viewPublishedContentAcceptButton":"You have ended preview mode, do you want to continue previewing this content?",
|
||||
"viewPublishedContentDeclineButton":"Preview"
|
||||
};
|
||||
|
||||
const umbLocalizedVars = jsonLocalization || {};
|
||||
umbLocalizedVars.preview = Object.assign(localizeVarsFallback, jsonLocalization.preview);
|
||||
|
||||
|
||||
|
||||
// This modal is also used in preview.js
|
||||
var modelStyles = `
|
||||
/* Webfont: LatoLatin-Bold */
|
||||
@font-face {
|
||||
font-family: 'Lato';
|
||||
src: url('https://fonts.googleapis.com/css2?family=Lato:wght@700&display=swap');
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
|
||||
.umbraco-preview-dialog {
|
||||
position: fixed;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
z-index: 99999999;
|
||||
top:0;
|
||||
bottom:0;
|
||||
left:0;
|
||||
right:0;
|
||||
overflow: auto;
|
||||
background-color: rgba(0,0,0,0.6);
|
||||
}
|
||||
|
||||
.umbraco-preview-dialog__modal {
|
||||
background-color: #fff;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 3px 7px rgba(0,0,0,0.3);
|
||||
margin: auto;
|
||||
padding: 30px 40px;
|
||||
width: 100%;
|
||||
max-width: 540px;
|
||||
font-family: Lato,Helvetica Neue,Helvetica,Arial,sans-serif;
|
||||
font-size: 15px;
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
.umbraco-preview-dialog__headline {
|
||||
font-weight: 700;
|
||||
font-size: 22px;
|
||||
color: #1b264f;
|
||||
margin-top:10px;
|
||||
margin-bottom:20px;
|
||||
}
|
||||
.umbraco-preview-dialog__question {
|
||||
margin-bottom:30px;
|
||||
}
|
||||
.umbraco-preview-dialog__modal > button {
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
padding: 8px 18px;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
border-radius: 3px;
|
||||
border:none;
|
||||
font-family: inherit;
|
||||
font-weight: 700;
|
||||
font-size: 15px;
|
||||
float:right;
|
||||
margin-left:10px;
|
||||
|
||||
color: #1b264f;
|
||||
background-color: #f6f1ef;
|
||||
}
|
||||
.umbraco-preview-dialog__modal > button:hover {
|
||||
color: #2152a3;
|
||||
background-color: #f6f1ef;
|
||||
}
|
||||
.umbraco-preview-dialog__modal > button.umbraco-preview-dialog__continue {
|
||||
color: #fff;
|
||||
background-color: #2bc37c;
|
||||
}
|
||||
.umbraco-preview-dialog__modal > button.umbraco-preview-dialog__continue:hover {
|
||||
background-color: #39d38b;
|
||||
}
|
||||
`;
|
||||
|
||||
var bodyEl = document.getElementsByTagName("BODY")[0];
|
||||
|
||||
var fragment = document.createElement("div");
|
||||
var shadowRoot = fragment.attachShadow({ mode: 'open' });
|
||||
|
||||
var style = document.createElement("style");
|
||||
style.innerHTML = modelStyles;
|
||||
shadowRoot.appendChild(style);
|
||||
|
||||
var con = document.createElement("div");
|
||||
con.className = "umbraco-preview-dialog";
|
||||
shadowRoot.appendChild(con);
|
||||
|
||||
var modal = document.createElement("div");
|
||||
modal.className = "umbraco-preview-dialog__modal";
|
||||
modal.innerHTML = `<div class="umbraco-preview-dialog__headline">${umbLocalizedVars.preview.viewPublishedContentHeadline}</div>
|
||||
<div class="umbraco-preview-dialog__question">${umbLocalizedVars.preview.viewPublishedContentDescription}</div>`;
|
||||
con.appendChild(modal);
|
||||
|
||||
var continueButton = document.createElement("button");
|
||||
continueButton.type = "button";
|
||||
continueButton.className = "umbraco-preview-dialog__continue";
|
||||
continueButton.innerHTML = umbLocalizedVars.preview.viewPublishedContentAcceptButton;
|
||||
continueButton.addEventListener("click", endPreviewMode);
|
||||
modal.appendChild(continueButton);
|
||||
|
||||
var exitButton = document.createElement("button");
|
||||
exitButton.type = "button";
|
||||
exitButton.innerHTML = umbLocalizedVars.preview.viewPublishedContentDeclineButton;
|
||||
exitButton.addEventListener("click", function() {
|
||||
bodyEl.removeChild(fragment);
|
||||
continuePreviewMode(5);
|
||||
});
|
||||
modal.appendChild(exitButton);
|
||||
|
||||
bodyEl.appendChild(fragment);
|
||||
continueButton.focus();
|
||||
}
|
||||
|
||||
})();
|
||||
Reference in New Issue
Block a user