block editor implementation

This commit is contained in:
Niels Lyngsø
2020-03-03 13:02:13 +01:00
parent 13aa5cf2ba
commit 36dab09cc3
15 changed files with 322 additions and 1012 deletions
@@ -5,24 +5,43 @@
function blockEditorService($interpolate, udiService) {
function applyModelToScaffold(scaffold, contentModel) {
scaffold.key = contentModel.key;
function mapToEditingModel(editingModel, contentModel) {
var variant = scaffold.variants[0];
var variant = editingModel.variants[0];
for (var t = 0; t < variant.tabs.length; t++) {
var tab = variant.tabs[t];
for (var p = 0; p < tab.properties.length; p++) {
var prop = tab.properties[p];
if (contentModel[prop.alias]) {
console.log("mapping:", prop.alias, contentModel[prop.alias])
prop.value = contentModel[prop.alias];
}
}
}
}
function mapToPropertyModel(editingModel, contentModel) {
var variant = editingModel.variants[0];
for (var t = 0; t < variant.tabs.length; t++) {
var tab = variant.tabs[t];
for (var p = 0; p < tab.properties.length; p++) {
var prop = tab.properties[p];
if (contentModel[prop.propertyAlias]) {
prop.value = contentModel[prop.propertyAlias];
if (prop.value) {
contentModel[prop.propertyAlias] = prop.value;
}
}
}
}
function mapValueToPropertyModel(value, alias, contentModel) {
contentModel[alias] = value;
}
/**
* @ngdoc factory
@@ -107,7 +126,9 @@
*/
getEditingModel: function(layoutEntry) {
var contentModel = this.getContentByUdi(layoutEntry.udi);
var udi = layoutEntry.udi;
var contentModel = this.getContentByUdi(udi);
var blockConfiguration = this.getBlockConfiguration(contentModel.contentTypeAlias);
@@ -116,21 +137,44 @@
return null;
}
var model = angular.copy(blockConfiguration);
model.labelInterpolate = $interpolate(model.label);
model.overlaySize = model.overlaySize || "medium";
var editingModel = {};
editingModel.config = angular.copy(blockConfiguration);
editingModel.labelInterpolator = $interpolate(editingModel.config.label);
var scaffold = this.getScaffoldFor(blockConfiguration.contentTypeAlias);
if(scaffold === null) {
return null;
}
model.content = angular.copy(scaffold);
applyModelToScaffold(model.content, contentModel);
// make basics from scaffold
editingModel.content = angular.copy(scaffold);
editingModel.content.udi = udi;
mapToEditingModel(editingModel.content, contentModel);
editingModel.contentModel = contentModel;
editingModel.layoutModel = layoutEntry;
// TODO: settings
return model;
return editingModel;
},
/**
* Retrieve editing model of a layout entry
* @return {Object} Scaffolded Block Content object.
*/
setDataFromEditingModel: function(editingModel) {
var udi = editingModel.content.key;
var contentModel = this.getContentByUdi(udi);
mapToPropertyModel(editingModel.content, contentModel);
// TODO: sync settings to layout entry.
},
@@ -165,7 +209,6 @@
return entry;
},
// private
getContentByUdi: function(udi) {
return this.value.data.find(entry => entry.udi === udi);
},
@@ -198,12 +241,11 @@
createModelObject: function(propertyModelValue, propertyEditorAlias, blockConfigurations) {
return new BlockEditorModelObject(propertyModelValue, propertyEditorAlias, blockConfigurations);
},
getBlockLabel: function(blockModelObject, labelIndex) {
getBlockLabel: function(blockModelObject) {
// TODO: we should do something about this for performance.
var vars = new Object();
vars["$index"] = labelIndex;
var variant = blockModelObject.content.variants[0];
var tab = variant.tabs[0];
@@ -212,8 +254,8 @@
vars[property.alias] = property.value;
}
if(blockModelObject.labelInterpolate) {
return blockModelObject.labelInterpolate(vars);
if(blockModelObject.labelInterpolator) {
return blockModelObject.labelInterpolator(vars);
}
return blockModelObject.contentTypeName;
@@ -22,7 +22,7 @@
* @returns {string} The generated UDI
*/
create: function(entityType) {
return "umb://" + entityType + "/" + String.CreateGuid();
return "umb://" + entityType + "/" + (String.CreateGuid().replace(/-/g, ""));
}
}
}
@@ -1,3 +1,3 @@
<button type="button" class="btn-reset umb-outline blockelement-imageblock-editor blockelement__draggable-element" focus-when="{{moveFocusToBlock === block}}" ng-click="vm.editBlock(block)">
<img src="{{block.content.temp_image}}">
<button type="button" class="btn-reset umb-outline blockelement-imageblock-editor blockelement__draggable-element" focus-when="{{vm.focusThis}}" ng-click="vm.blockEditorApi.editBlock(vm.block)">
<img src="{{vm.block.content.temp_image}}">
</button>
@@ -1,10 +1,10 @@
<div class="blockelement-inlineblock-editor" ng-class="{'--open': bc.isOpen}" ng-controller="Umbraco.PropertyEditors.BlockEditor.InlineBlockEditor as bc">
<button type="button" class="btn-reset umb-outline blockelement__draggable-element" ng-click="bc.openBlock(block)" focus-when="{{moveFocusToBlock === block}}">
<button type="button" class="btn-reset umb-outline blockelement__draggable-element" ng-click="bc.openBlock(block)" focus-when="{{vm.focusThis}}">
<span class="caret"></span>
<i class="icon {{block.content.icon}}"></i>
<span>{{block.label}}</span>
<i class="icon {{vm.block.content.icon}}"></i>
<span>{{vm.block.label}}</span>
</button>
<div class="blockelement-inlineblock-editor__inner" ng-if="bc.isOpen === true">
<umb-element-content-editor content="block.content"></umb-element-content-editor>
<umb-element-content-editor content="vm.block.content"></umb-element-content-editor>
</div>
</div>
@@ -55,6 +55,7 @@
}
.blockelement-inlineblock-editor__inner {
border-top: 1px solid @gray-8;
background-color: @gray-11;
.umb-group-panel {
background-color: transparent;
@@ -1,4 +1,4 @@
<button type="button" class="btn-reset umb-outline blockelement-labelblock-editor blockelement__draggable-element" ng-click="vm.editBlock(block)" focus-when="{{moveFocusToBlock === block}}">
<i class="icon {{block.content.icon}}"></i>
<span>{{block.label}}</span>
<button type="button" class="btn-reset umb-outline blockelement-labelblock-editor blockelement__draggable-element" ng-click="vm.blockEditorApi.editBlock(vm.block)" focus-when="{{vm.focusThis}}">
<i class="icon {{vm.block.content.icon}}"></i>
<span>{{vm.block.label}}</span>
</button>
@@ -2,7 +2,7 @@
<ng-form name="elementTypeContentForm">
<div class="umb-group-panel"
data-element="group-{{group.alias}}"
ng-repeat="group in vm.content.tabs track by group.label">
ng-repeat="group in vm.content.variants[0].tabs track by group.label">
<div class="umb-group-panel__header">
<div id="group-{{group.id}}">{{ group.label }}</div>
@@ -14,8 +14,6 @@
function ElementEditorComponentController() {
const vm = this;
// TODO: we might not need this..
}
@@ -5,9 +5,9 @@ angular.module("umbraco")
var vm = this;
vm.content = $scope.model.block.content;
vm.content = $scope.model.content;
vm.title = $scope.model.block.label;
vm.title = $scope.model.title;
vm.saveAndClose = function() {
if ($scope.model && $scope.model.submit) {
@@ -0,0 +1,20 @@
<div class="umb-block-list__block">
<div class="umb-block-list__block--content" ng-if="vm.block.view" ng-include="vm.block.view">
</div>
<div class="umb-block-list__block--actions">
<button type="button" class="btn-reset action --copy" localize="title" title="general_copy" ng-click="vm.blockEditorApi.requestCopyBlock(vm.block);" ng-if="vm.showCopy">
<i class="icon icon-documents" aria-hidden="true"></i>
<span class="sr-only">
<localize key="general_copy">Copy</localize>
</span>
</button>
<button type="button" class="btn-reset action --delete" localize="title" title="general_delete" ng-click="vm.blockEditorApi.requestDeleteBlock(vm.block);">
<i class="icon icon-trash" aria-hidden="true"></i>
<span class="sr-only">
<localize key="general_delete">Delete</localize>
</span>
</button>
</div>
</div>
@@ -0,0 +1,65 @@
(function () {
"use strict";
angular
.module("umbraco")
.component("blockListPropertyEditorBlock", {
templateUrl: "views/propertyeditors/blocklist/blocklist.block.component.html",
controller: BlockListBlockController,
controllerAs: "vm",
bindings: {
block: "=",
blockEditorApi: "=",
focusThisBlock: "<?"
}
});
function BlockListBlockController($scope, blockEditorService) {
var unsubscribe = [];
var vm = this;
console.log("BlockListBlockController", vm);
vm.$onInit = function() {
// Start watching each property value.
var variant = vm.block.content.variants[0];
for (var t = 0; t < variant.tabs.length; t++) {
var tab = variant.tabs[t];
for (var p = 0; p < tab.properties.length; p++) {
var prop = tab.properties[p];
unsubscribe.push($scope.$watch("vm.block.content.variants[0].tabs["+t+"].properties["+p+"].value", createPropWatcher(prop)));
}
}
}
function createPropWatcher(prop) {
return function() {
// sync data:
console.log(prop.alias, prop.value);
vm.block.contentModel[prop.alias] = prop.value;
// update label:
updateLabel();
}
}
function updateLabel() {
vm.block.label = blockEditorService.getBlockLabel(vm.block);
}
$scope.$on("$destroy", function () {
for (const subscription of unsubscribe) {
subscription();
}
});
}
})();
@@ -5,82 +5,21 @@
<div ui-sortable="vm.sortableOptions" ng-model="vm.blocks">
<div ng-repeat="block in vm.blocks">
<div ng-repeat="blockItem in vm.blocks">
<button
type="button"
class="btn-reset umb-block-list__block--create-button"
ng-click="vm.showCreateDialog($index, $event)"
outcommented-ng-if="vm.quickMenuVisible === false || $index !== vm.quickMenuIndex"
>
</button>
<!--
<div class="umb-block-list__block--create-bar" ng-if="vm.quickMenuVisible === true && $index === vm.quickMenuIndex">
<button type="button"
class="btn-reset"
ng-repeat="type in vm.availableBlockTypes | limitTo:4"
focus-when="{{$index === 0}}"
ng-blur="vm.onCreateOptionsBlur($event)"
ng-click="vm.quickMenuAddNewBlock(type)"
>
<i class="icon {{type.icon}}"></i>
<span>{{type.name}}</span>
</button>
<button type="button"
ng-if="vm.availableBlockTypes.length > 4"
class="btn-reset"
ng-click="vm.showCreateDialog($index, $event)"
>
<i class="icon icon-three-dots"></i>
<span>more</span>
</button>
</div>
-->
<div class="umb-block-list__block">
<!--
<div class="umb-block-list__block--head">
<i class="icon" ng-class="block.icon"></i>
<small>{{block.elementType.label}}</small>
</div>
-->
<div class="umb-block-list__block--content" ng-if="block.editor" ng-include="block.editor">
</div>
<div class="umb-block-list__block--content" ng-if="!block.editor">
<!-- TODO: Move LabelBlock into this, no reason to have that as seperate code, that would make it the default fallback. -->
<h1>No editor</h1>
</div>
<div class="umb-block-list__block--actions">
<button type="button" class="btn-reset action --copy" localize="title" title="general_copy" ng-click="vm.requestCopyBlock(block);" ng-if="vm.showCopy">
<i class="icon icon-documents" aria-hidden="true"></i>
<span class="sr-only">
<localize key="general_copy">Copy</localize>
</span>
</button>
<button type="button" class="btn-reset action --delete" localize="title" title="general_delete" ng-click="vm.requestDeleteBlock(block);">
<i class="icon icon-trash" aria-hidden="true"></i>
<span class="sr-only">
<localize key="general_delete">Delete</localize>
</span>
</button>
</div>
</div>
<block-list-property-editor-block block="blockItem" block-editor-api="vm.blockEditorApi" focus-this-block="false">
</block-list-property-editor-block>
</div>
</div>
<!--
<button
type="button"
class="btn-reset umb-block-list__block--create-button"
ng-click="vm.showCreateDialog(vm.blocks.length, $event)"
ng-if="vm.blocks.length !== 0"
>
</button>
-->
<button
type="button"
class="btn-reset umb-block-list__create-button"
@@ -90,16 +29,14 @@
<localize key="grid_addElement"></localize>
</button>
<input type="hidden" name="minCount" ng-model="vm.blocks" />
<input type="hidden" name="maxCount" ng-model="vm.blocks" />
<div ng-messages="vm.propertyForm.minCount.$error" show-validation-on-submit>
<div class="help text-error" ng-message="minCount">
<localize key="validation_entriesShort" tokens="[vm.validationLimit.min, vm.validationLimit.min - vm.blocks.length]" watch-tokens="true">Minimum %0% entries, needs <strong>%1%</strong> more.</localize>
</div>
</div>
<div ng-if="vm.propertyForm.maxCount.$error === true || vm.blocks.length > vm.validationLimit.max">
<div ng-if="vm.propertyForm.maxCount.$error === true && vm.blocks.length > vm.validationLimit.max">
<div class="help text-error">
<localize key="validation_entriesExceed" tokens="[vm.validationLimit.max, vm.blocks.length - vm.validationLimit.max]" watch-tokens="true">Maximum %0% entries, <strong>%1%</strong> too many.</localize>
</div>
File diff suppressed because it is too large Load Diff
@@ -1 +1 @@
<block-list-property-editor></block-list-property-editor>
<block-list-property-editor property-form="propertyForm" model="model"/>
@@ -42,8 +42,8 @@ namespace Umbraco.Web.PropertyEditors
public string Label { get; set; }
}
[ConfigurationField("useAccordionsAsDefault", "Inline editing mode", "boolean", Description = "Use the inline editor as the default block view")]
public bool useInlineEditingAsDefault { get; set; }
[ConfigurationField("useInlineEditingAsDefault", "Inline editing mode", "boolean", Description = "Use the inline editor as the default block view")]
public bool UseInlineEditingAsDefault { get; set; }
}
}