diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/elementtype.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/elementtype.resource.js new file mode 100644 index 0000000000..680b75ac78 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/resources/elementtype.resource.js @@ -0,0 +1,32 @@ +/** + * @ngdoc service + * @name umbraco.resources.elementTypeResource + * @description Loads in data for element types + **/ +function elementTypeResource($q, $http, umbRequestHelper) { + + return { + + getAll: function () { + + // TODO: Change this into a real api (ElementTypeApi). This is a temporary fix to get data. + var url = Umbraco.Sys.ServerVariables.umbracoSettings.umbracoPath + "/backoffice/UmbracoApi/NestedContent/GetContentTypes"; + return umbRequestHelper.resourcePromise( + $http.get(url), + 'Failed to retrieve content types' + ); + + /* + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "elementTypeApiBaseUrl", + "GetAll")), + "Failed to retrieve data"); + */ + } + + }; +} + +angular.module("umbraco.resources").factory("elementTypeResource", elementTypeResource); diff --git a/src/Umbraco.Web.UI.Client/src/less/belle.less b/src/Umbraco.Web.UI.Client/src/less/belle.less index f264038e93..9b9d10b965 100644 --- a/src/Umbraco.Web.UI.Client/src/less/belle.less +++ b/src/Umbraco.Web.UI.Client/src/less/belle.less @@ -199,6 +199,7 @@ // Property Editors @import "../views/propertyeditors/blocklist/blocklist.component.less"; +@import "../views/propertyeditors/blocklist/prevalue/blocklist.elementtypepicker.less"; // Utilities diff --git a/src/Umbraco.Web.UI.Client/src/views/common/overlays/itempicker/itempicker.html b/src/Umbraco.Web.UI.Client/src/views/common/overlays/itempicker/itempicker.html index 715dc12a07..eec87246c0 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/overlays/itempicker/itempicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/overlays/itempicker/itempicker.html @@ -42,5 +42,13 @@ +
  • + +
  • diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/prevalue/blocklist.elementtypepicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/prevalue/blocklist.elementtypepicker.controller.js new file mode 100644 index 0000000000..13937a0625 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/prevalue/blocklist.elementtypepicker.controller.js @@ -0,0 +1,236 @@ +/** + * @ngdoc controller + * @name Umbraco.Editors.PropertySettingsController + * @function + * + * @description + * The controller for the content type editor property settings dialog + */ + +(function () { + "use strict"; + + function ElementTypePickerController($scope, elementTypeResource, overlayService, localizationService, editorService) { + + var vm = this; + + vm.enableAddEntry = true; + + function evaluateStatus() { + + if (!vm.elementTypes) return;// cancel if elementTypes isnt loaded jet. + + vm.enableAddEntry = vm.getAvailableElementTypes().length > 0; + + } + + function onInit() { + + if (!$scope.model.value) { + $scope.model.value = []; + } + + localizationService.localize("content_nestedContentSelectElementTypeModalTitle").then(function (value) { + //selectElementTypeModalTitle = value; + }); + + loadElementTypes(); + + } + + function loadElementTypes() { + return elementTypeResource.getAll().then(function (elementTypes) { + vm.elementTypes = elementTypes; + console.log("vm.elementTypes:", vm.elementTypes) + evaluateStatus(); + }); + } + + vm.removeEntryByIndex = function (index) { + $scope.model.value.splice(index, 1); + }; + + vm.sortableOptions = { + axis: "y", + cursor: "grabbing", + placeholder: 'sortable-placeholder', + forcePlaceholderSize: true + }; + + + vm.getAvailableElementTypes = function () { + return vm.elementTypes.filter(function (type) { + return !$scope.model.value.find(function (entry) { + return type.alias === entry.elementTypeAlias; + }); + }); + }; + + vm.getElementTypeByAlias = function(alias) { + return _.find(vm.elementTypes, function (type) { + return type.alias === alias; + }); + }; + + vm.openAddDialog = function ($event, entry) { + + //we have to add the alias to the objects (they are stored as elementTypeAlias) + var selectedItems = _.each($scope.model.value, function (obj) { + obj.alias = obj.elementTypeAlias; + return obj; + }); + + var availableItems = vm.getAvailableElementTypes() + + var elemTypeSelectorOverlay = { + view: "itempicker", + title: "no title jet", + availableItems: availableItems, + selectedItems: selectedItems, + createNewItem: { + action: function() { + overlayService.close(); + vm.createElementTypeAndAdd(vm.addEntryFromElementTypeAlias); + }, + icon: "icon-add", + name: "Create new" + }, + position: "target", + event: $event, + size: availableItems.length < 7 ? "small" : "medium", + submit: function (overlay) { + vm.addEntryFromElementTypeAlias(overlay.selectedItem.alias); + overlayService.close(); + }, + close: function () { + overlayService.close(); + } + }; + + overlayService.open(elemTypeSelectorOverlay); + }; + + vm.createElementTypeAndAdd = function(callback) { + const editor = { + create: true, + infiniteMode: true, + isElement: true, + submit: function (model) { + console.log(model) + loadElementTypes().then( function () { + callback(model.documentTypeAlias); + }); + editorService.close(); + }, + close: function () { + editorService.close(); + } + }; + editorService.documentTypeEditor(editor); + } + + vm.addEntryFromElementTypeAlias = function(alias) { + + var entry = { + "elementTypeAlias": alias, + "view": null, + "labelTemplate": "", + "settingsElementTypeAlias": null + }; + + $scope.model.value.push(entry); + }; + + vm.removeSettingsForEntry = function(entry) { + entry.settingsElementTypeAlias = null; + }; + + vm.openPickSettingsDialog = function ($event, entry) { + + var elemTypeSelectorOverlay = { + view: "itempicker", + title: "Pick settings (missing translation)", + availableItems: vm.elementTypes, + position: "target", + event: $event, + size: vm.elementTypes.length < 7 ? "small" : "medium", + createNewItem: { + action: function() { + overlayService.close(); + vm.createElementTypeAndAdd((alias) => { + vm.addSettingsAtEntry(entry, alias); + }); + }, + icon: "icon-add", + name: "Create new" + }, + submit: function (overlay) { + vm.addSettingsAtEntry(entry, overlay.selectedItem.alias); + overlayService.close(); + }, + close: function () { + overlayService.close(); + } + }; + + overlayService.open(elemTypeSelectorOverlay); + }; + vm.addSettingsAtEntry = function(entry, alias) { + entry.settingsElementTypeAlias = alias; + }; + + vm.openElementType = function(elementTypeAlias) { + var elementTypeId = vm.getElementTypeByAlias(elementTypeAlias).id; + const editor = { + id: elementTypeId, + submit: function (model) { + loadElementTypes(); + editorService.close(); + }, + close: function () { + editorService.close(); + } + }; + editorService.documentTypeEditor(editor); + } + + vm.removeViewForEntry = function(entry) { + entry.view = null; + }; + vm.addViewForEntry = function(entry) { + const viewPicker = { + title: "Pick view (TODO need translation)", + section: "settings", + treeAlias: "partialView", + entityType: "partialView", + onlyInitialized: false, + filter: function (i) { + if (i.name.indexOf(".cshtml") === -1 && i.name.indexOf(".vbhtml") === -1) { + return true; + } + }, + filterCssClass: "not-allowed", + select: function (node) { + console.log(node); + //entry.view = node.name; + editorService.close(); + }, + close: function () { + editorService.close(); + } + }; + editorService.treePicker(viewPicker); + } + + + onInit(); + + $scope.$watchCollection('model.value', function(newVal, oldVal) { + evaluateStatus(); + }); + + } + + angular.module("umbraco").controller("Umbraco.PropertyEditors.BlockList.ElementTypePickerController", ElementTypePickerController); + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/prevalue/blocklist.elementtypepicker.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/prevalue/blocklist.elementtypepicker.html new file mode 100644 index 0000000000..d40ec19311 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/prevalue/blocklist.elementtypepicker.html @@ -0,0 +1,81 @@ +
    +
    +
    +
    +
    +
    + Custom view +
    +
    + Label + +
    +
    + Custom view +
    +
    + Custom view +
    +
    +
    +
    +
    +
    +
    +
    + {{ contentPreview = vm.getElementTypeByAlias(entry.elementTypeAlias); "" }} + + +
    +
    + +
    +
    +
    + + + + +
    + +
    +
    +
    + {{ settingsPreview = vm.getElementTypeByAlias(entry.settingsElementTypeAlias); "" }} + + + + +
    + +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/prevalue/blocklist.elementtypepicker.less b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/prevalue/blocklist.elementtypepicker.less new file mode 100644 index 0000000000..fb22ea8b46 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/blocklist/prevalue/blocklist.elementtypepicker.less @@ -0,0 +1,114 @@ +.umb-block-list-element-type-picker { + + .block-entry { + cursor: grab; + background-color: white; + border-radius: @baseBorderRadius; + } + + .umb-table-head { + button { + margin-left: 5px; + color: @ui-action-discreet-type; + &:hover { + color: @ui-action-discreet-type-hover; + } + } + } + + .umb-table-cell { + padding-left: 10px; + padding-right: 0; + &.action-cell { + padding-right: 15px; + } + } + + .action-cell { + flex: 0 0 30px; + } + + .text-input { + width: 100%; + } + + .umb-node-preview { + flex-grow: 1; + } + + .cell-btn { + position: relative; + opacity: 0; + color: @ui-action-discreet-type; + height: 30px; + width: 26px; + margin-top: 1px; + &:hover { + color: @ui-action-discreet-type-hover; + } + &:last-of-type { + margin-right: 7px; + } + } + .umb-table-cell:hover, + .umb-table-cell:focus, + .umb-table-cell:focus-within { + .cell-btn { + opacity: 1; + } + } + + .settings-input { + position: relative; + padding: 5px 8px; + color: @ui-action-discreet-type; + border: 1px dashed @ui-action-discreet-border; + width: 100%; + font-weight: bold; + display: flex; + flex-flow: row nowrap; + + localize { + width: 100%; + } + + .umb-node-preview { + padding: 3px 0; + margin-left: 5px; + } + + &.--noValue { + text-align: center; + border-radius: @baseBorderRadius; + &:hover { + color: @ui-action-discreet-type-hover; + border-color: @ui-action-discreet-border-hover; + } + } + + &.--hasValue { + border: 1px solid @inputBorder; + padding: 0; + } + } + + .add-button { + width:100%; + color: @ui-action-discreet-type; + border: 1px dashed @ui-action-discreet-border; + border-radius: @baseBorderRadius; + display: flex; + align-items: center; + justify-content: center; + padding: 5px 15px; + box-sizing: border-box; + margin: 10px 0; + font-weight: bold; + } + + .add-button:hover { + color: @ui-action-discreet-type-hover; + border-color: @ui-action-discreet-border-hover; + } + +} diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml index a85df5714b..a7abf75281 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en.xml @@ -2393,4 +2393,13 @@ To manage your website, simply open the Umbraco back office and start adding con Umbraco Forms Create forms using an intuitive drag and drop interface. From simple contact forms that sends e-mails to advanced questionaires that integrate with CRM systems. Your clients will love it! + + Content model + Label + Custom view + Settings model + Add custom view + Add settings + Overwrite label template + diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml index d14fb03727..e4fb330296 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -2405,4 +2405,13 @@ To manage your website, simply open the Umbraco back office and start adding con Umbraco Forms Create forms using an intuitive drag and drop interface. From simple contact forms that sends e-mails to advanced questionaires that integrate with CRM systems. Your clients will love it! + + Content model + Label + Custom view + Settings model + Add custom view + Add settings + Overwrite label template + diff --git a/src/Umbraco.Web/PropertyEditors/BlockListConfiguration.cs b/src/Umbraco.Web/PropertyEditors/BlockListConfiguration.cs index 95366db486..ebdc39e445 100644 --- a/src/Umbraco.Web/PropertyEditors/BlockListConfiguration.cs +++ b/src/Umbraco.Web/PropertyEditors/BlockListConfiguration.cs @@ -9,16 +9,35 @@ namespace Umbraco.Web.PropertyEditors /// public class BlockListConfiguration { - [ConfigurationField("elementTypes", "Element Types", "views/propertyeditors/blocklist/blocklist.elementtypepicker.html", Description = "Select the Element Types to use as models for the items.")] + + // TODO: rename this to blockDefinitions, cause its not elementTypes, its a dictionary of objects that define blocks, part of a block is the elementType used as content model. + [ConfigurationField("elementTypes", "Available Blocks", "views/propertyeditors/blocklist/prevalue/blocklist.elementtypepicker.html", Description = "Define the available blocks.")] public ElementType[] ElementTypes { get; set; } - // TODO: Fill me in + [ConfigurationField("minNumber", "Minimum amount", "number")] + public int MinNumber { get; set; } + + [ConfigurationField("maxNumber", "Maximum amount", "number")] + public int MaxNumber { get; set; } public class ElementType { + // TODO: rename this to contentElementTypeAlias, I would like this to be specific, since we have the settings. [JsonProperty("elementTypeAlias")] public string Alias { get; set; } + + [JsonProperty("settingsElementTypeAlias")] + public string SettingsElementTypeAlias { get; set; } + + [JsonProperty("view")] + public string View { get; set; } + + [JsonProperty("labelTemplate")] + public string Template { get; set; } } + [ConfigurationField("useAccordionsAsDefault", "Inline editing mode", "boolean", Description = "Use the inline editor as the default block view")] + public bool useInlineEditingAsDefault { get; set; } + } } diff --git a/src/Umbraco.Web/PropertyEditors/BlockListConfigurationEditor.cs b/src/Umbraco.Web/PropertyEditors/BlockListConfigurationEditor.cs new file mode 100644 index 0000000000..3a4e3eae9b --- /dev/null +++ b/src/Umbraco.Web/PropertyEditors/BlockListConfigurationEditor.cs @@ -0,0 +1,20 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text.RegularExpressions; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Umbraco.Core; +using Umbraco.Core.PropertyEditors; + +namespace Umbraco.Web.PropertyEditors +{ + internal class BlockListConfigurationEditor : ConfigurationEditor + { + public BlockListConfigurationEditor() + { + + } + + } +} diff --git a/src/Umbraco.Web/PropertyEditors/BlockListPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/BlockListPropertyEditor.cs index 9c4e2f460f..782122bccd 100644 --- a/src/Umbraco.Web/PropertyEditors/BlockListPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/BlockListPropertyEditor.cs @@ -22,7 +22,8 @@ namespace Umbraco.Web.PropertyEditors { } #region Pre Value Editor - //protected override IConfigurationEditor CreateConfigurationEditor() => new BlockEditorListConfigurationEditor(); + + protected override IConfigurationEditor CreateConfigurationEditor() => new BlockListConfigurationEditor(); #endregion diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj old mode 100755 new mode 100644 index e660108cad..c8812ad9ec --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -235,6 +235,7 @@ +