From 036d62a3319a1c6e11c14984527325b1b9795e5c Mon Sep 17 00:00:00 2001 From: Esha Noronha Date: Tue, 14 Jan 2025 15:24:57 +0100 Subject: [PATCH 1/2] Removed Build a Block editor article --- 10/umbraco-cms/.gitbook.yaml | 2 +- 10/umbraco-cms/SUMMARY.md | 1 - 10/umbraco-cms/extending/property-editors/README.md | 4 ---- 13/umbraco-cms/.gitbook.yaml | 1 + 13/umbraco-cms/SUMMARY.md | 1 - 13/umbraco-cms/extending/property-editors/README.md | 4 ---- 14/umbraco-cms/.gitbook.yaml | 1 + 14/umbraco-cms/SUMMARY.md | 1 - 14/umbraco-cms/customizing/property-editors/README.md | 4 ---- 15/umbraco-cms/.gitbook.yaml | 2 +- 15/umbraco-cms/SUMMARY.md | 1 - 15/umbraco-cms/customizing/property-editors/README.md | 4 ---- 12 files changed, 4 insertions(+), 22 deletions(-) diff --git a/10/umbraco-cms/.gitbook.yaml b/10/umbraco-cms/.gitbook.yaml index 04cd32fccb6..d13210a31a5 100644 --- a/10/umbraco-cms/.gitbook.yaml +++ b/10/umbraco-cms/.gitbook.yaml @@ -7,4 +7,4 @@ root: ./ redirects: tutorials/add-azure-active-directory-authentication: tutorials/add-microsoft-entra-id-authentication.md tutorials/editors-manual/working-with-content/rich-text-editor: tutorials/editors-manual/working-with-content.md - + extending/property-editors/build-a-block-editor: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/README.md diff --git a/10/umbraco-cms/SUMMARY.md b/10/umbraco-cms/SUMMARY.md index 47287d0197c..7589231c5e2 100644 --- a/10/umbraco-cms/SUMMARY.md +++ b/10/umbraco-cms/SUMMARY.md @@ -159,7 +159,6 @@ * [Package Manifest](extending/property-editors/package-manifest.md) * [Property Value Converters](extending/property-editors/property-value-converters.md) * [Property Actions](extending/property-editors/property-actions.md) - * [Build a Block Editor](extending/property-editors/build-a-block-editor.md) * [Tracking References](extending/property-editors/tracking.md) * [Declaring your property editor](extending/property-editors/declaring-your-property-editor.md) * [Content Picker Value Converter Example](extending/property-editors/full-examples-value-converters.md) diff --git a/10/umbraco-cms/extending/property-editors/README.md b/10/umbraco-cms/extending/property-editors/README.md index 9733e9873c9..130e064a753 100644 --- a/10/umbraco-cms/extending/property-editors/README.md +++ b/10/umbraco-cms/extending/property-editors/README.md @@ -25,10 +25,6 @@ Convert the stored property data value to a useful object returned by the Publis Use Property Actions to add additional functionaility to your custom property editors. -## [Build a Block Editor](build-a-block-editor.md) - -Learn how to build your own Block Editors. - ## [Tracking References](tracking.md) Learn how to extend Property editors to track entity references inside the property editor. diff --git a/13/umbraco-cms/.gitbook.yaml b/13/umbraco-cms/.gitbook.yaml index af94e872a1d..3cc439c8298 100644 --- a/13/umbraco-cms/.gitbook.yaml +++ b/13/umbraco-cms/.gitbook.yaml @@ -9,3 +9,4 @@ redirects: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/nested-content: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/block-list-editor tutorials/editors-manual/working-with-content/rich-text-editor: tutorials/editors-manual/working-with-content.md extending/packages/types-of-packages: extending/packages/README.md + extending/property-editors/build-a-block-editor: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/README.md diff --git a/13/umbraco-cms/SUMMARY.md b/13/umbraco-cms/SUMMARY.md index 5fc001e92b9..7e322072c68 100644 --- a/13/umbraco-cms/SUMMARY.md +++ b/13/umbraco-cms/SUMMARY.md @@ -160,7 +160,6 @@ * [Property Editors](extending/property-editors/README.md) * [Property Value Converters](extending/property-editors/property-value-converters.md) * [Property Actions](extending/property-editors/property-actions.md) - * [Build a Block Editor](extending/property-editors/build-a-block-editor.md) * [Tracking References](extending/property-editors/tracking.md) * [Declaring your property editor](extending/property-editors/declaring-your-property-editor.md) * [Content Picker Value Converter Example](extending/property-editors/full-examples-value-converters.md) diff --git a/13/umbraco-cms/extending/property-editors/README.md b/13/umbraco-cms/extending/property-editors/README.md index a09022aed91..930a1cdfff2 100644 --- a/13/umbraco-cms/extending/property-editors/README.md +++ b/13/umbraco-cms/extending/property-editors/README.md @@ -25,10 +25,6 @@ Convert the stored property data value to a useful object returned by the Publis Use Property Actions to add additional functionaility to your custom property editors. -## [Build a Block Editor](build-a-block-editor.md) - -Learn how to build your own Block Editors. - ## [Tracking References](tracking.md) Learn how to extend Property editors to track entity references inside the property editor. diff --git a/14/umbraco-cms/.gitbook.yaml b/14/umbraco-cms/.gitbook.yaml index c7badbfc9c0..d521053f38f 100644 --- a/14/umbraco-cms/.gitbook.yaml +++ b/14/umbraco-cms/.gitbook.yaml @@ -128,3 +128,4 @@ redirects: extending/packages/types-of-packages: extending/packages/README.md fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/listview: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/collection.md fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/label-property-configuration: reference/umbraco-flavored-markdown.md + customizing/property-editors/build-a-block-editor: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/README.md diff --git a/14/umbraco-cms/SUMMARY.md b/14/umbraco-cms/SUMMARY.md index bfead79fc5f..7c3406f2dcb 100644 --- a/14/umbraco-cms/SUMMARY.md +++ b/14/umbraco-cms/SUMMARY.md @@ -198,7 +198,6 @@ * [Property Value Converters](customizing/property-editors/property-value-converters.md) * [Property Actions](customizing/property-editors/property-actions.md) * [Integrate Property Editors](customizing/property-editors/integrate-property-editors.md) - * [Build a Block Editor](customizing/property-editors/build-a-block-editor.md) * [Tracking References](customizing/property-editors/tracking.md) * [Content Picker Value Converter Example](customizing/property-editors/full-examples-value-converters.md) * [Property Dataset](customizing/property-editors/property-dataset.md) diff --git a/14/umbraco-cms/customizing/property-editors/README.md b/14/umbraco-cms/customizing/property-editors/README.md index 333a7214232..b38eab37472 100644 --- a/14/umbraco-cms/customizing/property-editors/README.md +++ b/14/umbraco-cms/customizing/property-editors/README.md @@ -30,10 +30,6 @@ Convert the stored property data value to a useful object returned by the Publis Use Property Actions to add additional functionaility to your custom property editors. -## [Build a Block Editor](build-a-block-editor.md) - -Learn how to build your own Block Editors. - ## [Tracking References](broken-reference) Learn how to extend Property editors to track entity references inside the property editor. diff --git a/15/umbraco-cms/.gitbook.yaml b/15/umbraco-cms/.gitbook.yaml index a86c8cb290c..fa2cb9c154f 100644 --- a/15/umbraco-cms/.gitbook.yaml +++ b/15/umbraco-cms/.gitbook.yaml @@ -110,4 +110,4 @@ redirects: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/rte-plugins: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/plugins.md fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/rte-blocks: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/rich-text-editor/blocks.md fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/label-property-configuration: reference/umbraco-flavored-markdown.md - \ No newline at end of file + customizing/property-editors/build-a-block-editor: fundamentals/backoffice/property-editors/built-in-umbraco-property-editors/block-editor/README.md diff --git a/15/umbraco-cms/SUMMARY.md b/15/umbraco-cms/SUMMARY.md index e39e51421f3..ac5ad4aa02f 100644 --- a/15/umbraco-cms/SUMMARY.md +++ b/15/umbraco-cms/SUMMARY.md @@ -210,7 +210,6 @@ * [Property Value Converters](customizing/property-editors/property-value-converters.md) * [Property Actions](customizing/property-editors/property-actions.md) * [Integrate Property Editors](customizing/property-editors/integrate-property-editors.md) - * [Build a Block Editor](customizing/property-editors/build-a-block-editor.md) * [Tracking References](customizing/property-editors/tracking.md) * [Content Picker Value Converter Example](customizing/property-editors/full-examples-value-converters.md) * [Property Dataset](customizing/property-editors/property-dataset.md) diff --git a/15/umbraco-cms/customizing/property-editors/README.md b/15/umbraco-cms/customizing/property-editors/README.md index 333a7214232..b38eab37472 100644 --- a/15/umbraco-cms/customizing/property-editors/README.md +++ b/15/umbraco-cms/customizing/property-editors/README.md @@ -30,10 +30,6 @@ Convert the stored property data value to a useful object returned by the Publis Use Property Actions to add additional functionaility to your custom property editors. -## [Build a Block Editor](build-a-block-editor.md) - -Learn how to build your own Block Editors. - ## [Tracking References](broken-reference) Learn how to extend Property editors to track entity references inside the property editor. From d2757f68b989efd453237550b423357bcf696aa2 Mon Sep 17 00:00:00 2001 From: Esha Noronha Date: Wed, 15 Jan 2025 09:10:47 +0100 Subject: [PATCH 2/2] Deleted the articles --- .../property-editors/build-a-block-editor.md | 349 ------------------ .../property-editors/build-a-block-editor.md | 294 --------------- .../property-editors/build-a-block-editor.md | 311 ---------------- .../property-editors/build-a-block-editor.md | 311 ---------------- 4 files changed, 1265 deletions(-) delete mode 100644 10/umbraco-cms/extending/property-editors/build-a-block-editor.md delete mode 100644 13/umbraco-cms/extending/property-editors/build-a-block-editor.md delete mode 100644 14/umbraco-cms/customizing/property-editors/build-a-block-editor.md delete mode 100644 15/umbraco-cms/customizing/property-editors/build-a-block-editor.md diff --git a/10/umbraco-cms/extending/property-editors/build-a-block-editor.md b/10/umbraco-cms/extending/property-editors/build-a-block-editor.md deleted file mode 100644 index c1951b835cf..00000000000 --- a/10/umbraco-cms/extending/property-editors/build-a-block-editor.md +++ /dev/null @@ -1,349 +0,0 @@ -# Build a Block Editor - -{% hint style="warning" %} -This guide is currently being re-evaluated, as it might not work as intended. -{% endhint %} - -Before reading this document we highly recommend that you familiarise yourself with the [basics of developing a custom Property Editor for Umbraco](../../tutorials/creating-a-property-editor/). - -{% hint style="info" %} -[Click here for an overview with a working example and references back to the relevant documention.](https://umbraco.com/blog/deep-dive-the-block-list-editor/) -{% endhint %} - -## Setup your Property Editor as a Block Property Editor - -In order for your editor to become a Block Editor you must setup your property editor through C#. The constructor of the class can be auto generated by your Integrated Development Environment (IDE). - -{% tabs %} -{% tab title="Latest version" %} -```csharp -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Cms.Core.WebAssets; -using Umbraco.Cms.Infrastructure.WebAssets; - -namespace MyNamespace -{ - [DataEditor( - "MyOwn.UnicornBlocksEditor", - "Unicorn Blocks", - "unicornblocks", - ValueType = ValueTypes.Json, - Group = Constants.PropertyEditors.Groups.Lists, - Icon = "icon-thumbnail-list")] - [PropertyEditorAsset(AssetType.Javascript, "/App_Plugins/UnicornBlocks/UnicornBlocks.controller.js")] - public class UnicornBlocksPropertyEditor : BlockEditorPropertyEditor - { - public UnicornBlocksPropertyEditor(IDataValueEditorFactory dataValueEditorFactory, PropertyEditorCollection propertyEditors) - : base(dataValueEditorFactory, propertyEditors) - { - } - } - -} -``` -{% endtab %} - -{% tab title="Umbraco 9" %} -```csharp -using System; -using Microsoft.Extensions.Logging; -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Cms.Core.Serialization; -using Umbraco.Cms.Core.Services; -using Umbraco.Cms.Core.Strings; -using Umbraco.Cms.Core.WebAssets; -using Umbraco.Cms.Infrastructure.WebAssets; - -namespace MyNamespace -{ - [DataEditor( - "MyOwn.UnicornBlocksEditor", - "Unicorn Blocks", - "unicornblocks", - ValueType = ValueTypes.Json, - Group = Constants.PropertyEditors.Groups.Lists, - Icon = "icon-thumbnail-list")] - [PropertyEditorAsset(AssetType.Javascript, "/App_Plugins/UnicornBlocks/UnicornBlocks.controller.js")] - public class UnicornBlocksPropertyEditor : BlockEditorPropertyEditor - { - public UnicornBlocksPropertyEditor( - ILoggerFactory loggerFactory, - Lazy propertyEditors, - IDataTypeService dataTypeService, - IContentTypeService contentTypeService, - ILocalizedTextService localizedTextService, - ILocalizationService localizationService, - IShortStringHelper shortStringHelper, - IJsonSerializer jsonSerializer) - : base(loggerFactory, - propertyEditors, - dataTypeService, - contentTypeService, - localizedTextService, - localizationService, - shortStringHelper, - jsonSerializer) - { - } - } - -} -``` -{% endtab %} -{% endtabs %} - -Notice how the `PropertyEditorAsset` attribute is used to load the `UnicornBlocks.controller.js` JavaScript file. - -Your Property Editor will need a `PropertyValueConverter`. Read more about [Property Value Converters](property-value-converters.md). - -## Data structure of Block Editors - -The Block Editor data structure consists of three main parts: - -**Layout**: The Layout defines Blocks that each will reference (by UDI) a content item in the list of data. The Layout object pairs keys with Property Editor aliases and their value type varies based on setup. - -**ContentData**: A list of content items based on ElementTypes (IPublishedElement). - -**SettingsData**: A list of content items based on ElementTypes (IPublishedElement). - -In the following example the layout object "MyOwn.UnicornBlocksEditor" is of type Array. - -```json -{ - "layout": { - "MyOwn.UnicornBlocksEditor": [ - { - "contentUdi": "umb://element/fffba547615b4e9ab4ab2a7674845bc9" - }, - { - "contentUdi": "umb://element/e7dba547615b4e9ab4ab2a7674845bc9", - "settingsUdi": "umb://element/a47667bcba54845b15b4e9ab4ab2a7c8" - } - ] - }, - "contentData": [ - { - "udi": "umb://element/fffba547615b4e9ab4ab2a7674845bc9", - "contentTypeKey": "09876595489865786897", - "__yourPropertyAlias__": "Hello world" - }, - { - "udi": "umb://element/e7dba547615b4e9ab4ab2a7674845bc9", - "contentTypeKey": "123456789097654323456", - "__yourPropertyAlias1__": "Hello world", - "__yourPropertyAlias2__": "Hello world", - "__yourPropertyAlias3__": "Hello world" - } - ], - "settingsData": [ - { - "udi": "umb://element/a47667bcba54845b15b4e9ab4ab2a7c8", - "contentTypeKey": "09876595489865786897", - "__yourPropertyAlias__": "Hello world" - } - ] -} -``` - -## Client side code - -### Basic knowledge for understanding how to work with Block Editor data - -We created the BlockEditorModelObject to aid in managing the presented Data Structure in the Block Editor. - -To get a better understanding of what the Model Object does for you, we need to look at some usages of the Model Object. - -### Maintain and work with the Layout of a Block Editor - -The `layout` of a Block Editor can be any structure. Therefore the Model Object (BlockEditorModelObject) cannot maintain this data. Our usage of the Model Object becomes complex. We give it a reference to a `layout` entry and perform an action that may need to reflect changes back to the `layout`. - -Since the origin of blocks is in the `layout` the Model Object only can serve as a helper to maintain and create data. Therefore the Property Editor code will be using the `layout` as origin, using the Model Object to help manage specific parts. - -This is explained in more detail below. - -### The basic setup for a Block Editor - -Instantiate a Model Object and load dependencies. Provide the basic structure for the `layout` property when receiving the reference to it: - -```js -// We must get a scope that exists in all the lifetime of this data. Across variants and split-view. -var scopeOfExistence = $scope; -// Setup your component to require umbVariantContentEditors and vm.umbElementEditorContent. If one of them is avaiable use the method getScope to retrieve a shared scope for multiple editors of this content. -if(vm.umbVariantContentEditors && vm.umbVariantContentEditors.getScope) { - scopeOfExistence = vm.umbVariantContentEditors.getScope(); -} else if(vm.umbElementEditorContent && vm.umbElementEditorContent.getScope) { - scopeOfExistence = vm.umbElementEditorContent.getScope(); -} -// Define variables for layout and modelObject as you will be using these throughout your property editor. -vm.layout; -var modelObject; - -// When we are ready we can instantiate the Model Object and load any dependencies. -vm.$onInit = function() { - modelObject = blockEditorService.createModelObject(vm.model.value, vm.model.editor, vm.model.config.blocks, scopeOfExistence); - modelObject.load().then(onLoaded); -} -function onLoaded() { - // Define the default layout, this is used when there is no data stored for this property. - var defaultLayout = []; - // We store a reference to layout as we have to maintain this. - // The getLayout method gives us a reference to the layout-object based on the property-editor alias. The defaultLayout will be initialized if it does not exist. - vm.layout = modelObject.getLayout(defaultLayout); -} -``` - -### Create a Block - -Use the Model Object to create a Block and append the returned layout-entry to the `layout`. - -In the following example we will create a new block and append it at the appropriate location in the 'layout' object: - -```js -// continuing from previous example. - -// Creates a block and returns a layout entry. The layout entry is not part of layout yet as its not managed by the Model Object. -var layoutEntry = modelObject.create(contentTypeKey); -if (layoutEntry === null) { - // The creation was not successful, therefore exit and without appending anything to our 'layout' object. - return false; -} -// If we reach this line, we are good to add the layoutEntry to layout model. -// In this example our layout is an array and we would like to append the new block as the last entry. -vm.layout.push(layoutEntry); -``` - -### Working with Blocks - -The layout-entries alone do not provide much value when displaying or editing Blocks. - -Our Model Object allows obtaining a Block Object by parsing a block's layout-entry for a specific Block. - -The Block Object provides data of interest. The most important of these properties are: Block configuration, a label and the Block content in the Element Type Data Model format. This Content-model is useful for building the UI for editing the Content of a Block. - -This example uses the Model Object to retrive a Block Object for outputting its label in the console. - -```js -// continuing from the basic setup example. - -if (vm.layout.length > 0) { - // Get first entry of from the layout, which is an array in this example. - var firstLayoutEntry = vm.layout[0]; - - // Create a Block Object for that entry. - var block = modelObject.getBlockObject(firstLayoutEntry); - - // Check if the Block Object creation went well. (If a block is supported by the configuration of the Property Editor) - if (block !== null) { - console.log(block.label); - } -} -``` - -This similar example uses the Block Object for setting a value on the first property in the Blocks Content. - -```js -// continuing from the basic setup example. - -if (vm.layout.length > 0) { - // Get first entry of from the layout, which is an array in this example. - var firstLayoutEntry = vm.layout[0]; - - // Create a Block Object for that entry. - var block = modelObject.getBlockObject(firstLayoutEntry); - - // Check if the Block Object creation went well. (If a block is supported by the configuration of the Property Editor) - if (block !== null) { - - // This line edits the value of 'myProp' directly, available by 'block.data': - block.data.myProp = "Hello world"; - - // Alternatively you can use this line, which edits the data throught the Element Type data model avaiable in 'block.content': - block.content.variants[0].tabs[0].properties[0].value = "Hello world"; // This value will automatically be synced to the Property Editors Data Model, ´block.data.myProp´ - } -} -``` - -See [blockEditorModelObject](https://apidocs.umbraco.com/v10/csharp/api/Umbraco.Cms.Core.Models.Blocks.html) for the getBlockObject method for more information on the properties avaiable on a Block Object. - -## Remove a Block - -Removing a Block and destroying its data is done by calling the `removeDataAndDestroyModel` method of the Model Object, which allows us to maintain the 'layout' object. - -Your code will be based on working with Block Objects and therefore removal of a Block is be done by referring to a Block Object. - -This example shows how to remove the first Block of our imaginary Block Editor and remove the block from our layout. - -```js -// continuing from the basic setup example. - -if (vm.layout.length > 0) { - // Get first entry of from the layout, which is an array in this sample. - var firstLayoutEntry = vm.layout[0]; - - // Create a Block Object for that entry. - var block = modelObject.getBlockObject(firstLayoutEntry); - - // Check if the Block Object creation went well. (If a block isnt supported by the configuration of the Property Editor) - if(block !== null) { - - modelObject.removeDataAndDestroyModel(block);// Removing the data of our block and destroying the Block Object for performance reasons. - - // We need to maintain the 'layout' object, so therefor its up to our code to remove the block from the 'layout' object. - const index = array.indexOf(5); - if (index > -1) { - vm.layout.splice(index, 1); - } - } -} -``` - -## Manage Block Objects for general use through out your Property Editor - -Block Objects are used extensively and should be available throughout your Block Editor's runtime, rather than created for each action. - -You probably want to use BlockObjects for your property-editor view. We append them to layout entries, so you can access them as properties from the layout object. - -```js -// continuing from the basic setup example. - -var invalidLayoutItems = []; - -// Append the blockObjects to our layout. -vm.layout.forEach(entry => { - -// As we might have the same property-editor displayed multiple times on screen (splitview) we only need to initialize a BlockObject if its not already in place. - - // $block must have the 'data' property to be a valid BlockObject, if not it is considered a destroyed blockObject. - if (entry.$block === undefined || entry.$block === null || entry.$block.data === undefined) { - var block = modelObject.getBlockObject(entry); - - // If this entry was not supported by our property-editor it would return 'null'. - if (block !== null) { - entry.$block = block; - } else { - // We didnt succeed initializing this Block, therefore we need to filter this out of 'layout'. This only happens if the content data of the block couldn't be found. - invalidLayoutItems.push(entry); - } - } -}); - -// remove the ones that are invalid -invalidLayoutItems.forEach(entry => { - var index = vm.layout.findIndex(x => x === entry); - if (index >= 0) { - vm.layout.splice(index, 1); - } -}); -``` - -The following example loops through a layout array to display the contentUdi of each block: - -```html -
- -

- -
-``` diff --git a/13/umbraco-cms/extending/property-editors/build-a-block-editor.md b/13/umbraco-cms/extending/property-editors/build-a-block-editor.md deleted file mode 100644 index 3bcfb91fcd6..00000000000 --- a/13/umbraco-cms/extending/property-editors/build-a-block-editor.md +++ /dev/null @@ -1,294 +0,0 @@ -# Build a Block Editor - -{% hint style="warning" %} -This guide is currently being re-evaluated, as it might not work as intended. -{% endhint %} - -Before reading this document we highly recommend that you familiarise yourself with[ the basics of developing a custom Property Editor for Umbraco](../../tutorials/creating-a-property-editor/). - -{% hint style="info" %} -[Click here for an overview with a working example and references back to the relevant documention.](https://umbraco.com/blog/deep-dive-the-block-list-editor/) -{% endhint %} - -## Setup your Property Editor as a Block Property Editor - -In order for your editor to become a Block Editor you must setup your property editor through C#. The constructor of the class can be auto generated by your Integrated Development Environment (IDE). - -```csharp -using Umbraco.Cms.Core; -using Umbraco.Cms.Core.PropertyEditors; -using Umbraco.Cms.Core.WebAssets; -using Umbraco.Cms.Infrastructure.WebAssets; - -namespace MyNamespace; - -[DataEditor( - "MyOwn.UnicornBlocksEditor", - "Unicorn Blocks", - "unicornblocks", - ValueType = ValueTypes.Json, - Group = Constants.PropertyEditors.Groups.Lists, - Icon = "icon-thumbnail-list")] -[PropertyEditorAsset(AssetType.Javascript, "/App_Plugins/UnicornBlocks/UnicornBlocks.controller.js")] -public class UnicornBlocksPropertyEditor : BlockEditorPropertyEditor -{ - public UnicornBlocksPropertyEditor(IDataValueEditorFactory dataValueEditorFactory, PropertyEditorCollection propertyEditors) - : base(dataValueEditorFactory, propertyEditors) - { - } -} -``` - -Notice how the `PropertyEditorAsset` attribute is used to load the `UnicornBlocks.controller.js` JavaScript file. - -Your Property Editor will need a `PropertyValueConverter`. Read more about [Property Value Converters](property-value-converters.md). - -## Data structure of Block Editors - -The Block Editor data structure consists of three main parts: - -**Layout**: The Layout defines Blocks that each will reference (by UDI) a content item in the list of data. The Layout object pairs keys with Property Editor aliases and their value type varies based on setup. - -**ContentData**: A list of content items based on ElementTypes (IPublishedElement). - -**SettingsData**: A list of content items based on ElementTypes (IPublishedElement). - -In the following example the layout object "MyOwn.UnicornBlocksEditor" is of type Array. - -```json -{ - "layout": { - "MyOwn.UnicornBlocksEditor": [ - { - "contentUdi": "umb://element/fffba547615b4e9ab4ab2a7674845bc9" - }, - { - "contentUdi": "umb://element/e7dba547615b4e9ab4ab2a7674845bc9", - "settingsUdi": "umb://element/a47667bcba54845b15b4e9ab4ab2a7c8" - } - ] - }, - "contentData": [ - { - "udi": "umb://element/fffba547615b4e9ab4ab2a7674845bc9", - "contentTypeKey": "09876595489865786897", - "__yourPropertyAlias__": "Hello world" - }, - { - "udi": "umb://element/e7dba547615b4e9ab4ab2a7674845bc9", - "contentTypeKey": "123456789097654323456", - "__yourPropertyAlias1__": "Hello world", - "__yourPropertyAlias2__": "Hello world", - "__yourPropertyAlias3__": "Hello world" - } - ], - "settingsData": [ - { - "udi": "umb://element/a47667bcba54845b15b4e9ab4ab2a7c8", - "contentTypeKey": "09876595489865786897", - "__yourPropertyAlias__": "Hello world" - } - ] -} -``` - -## Client side code - -### Basic knowledge for understanding how to work with Block Editor data - -We created the BlockEditorModelObject to aid in managing the presented Data Structure in the Block Editor. - -To get a better understanding of what the Model Object does for you, we need to look at some usages of the Model Object. - -### Maintain and work with the Layout of a Block Editor - -The `layout` of a Block Editor can be any structure. Therefore the Model Object (BlockEditorModelObject) cannot maintain this data. Our usage of the Model Object becomes complex. We give it a reference to a `layout` entry and perform an action that may need to reflect changes back to the `layout`. - -Since the origin of blocks is in the `layout` the Model Object only can serve as a helper to maintain and create data. Therefore the Property Editor code will be using the `layout` as origin, using the Model Object to help manage specific parts. - -This is explained in more detail below. - -### The basic setup for a Block Editor - -Instantiate a Model Object and load dependencies. Provide the basic structure for the `layout` property when receiving the reference to it: - -```js -// We must get a scope that exists in all the lifetime of this data. Across variants and split-view. -var scopeOfExistence = $scope; -// Setup your component to require umbVariantContentEditors and vm.umbElementEditorContent. If one of them is avaiable use the method getScope to retrieve a shared scope for multiple editors of this content. -if(vm.umbVariantContentEditors && vm.umbVariantContentEditors.getScope) { - scopeOfExistence = vm.umbVariantContentEditors.getScope(); -} else if(vm.umbElementEditorContent && vm.umbElementEditorContent.getScope) { - scopeOfExistence = vm.umbElementEditorContent.getScope(); -} -// Define variables for layout and modelObject as you will be using these throughout your property editor. -vm.layout; -var modelObject; - -// When we are ready we can instantiate the Model Object and load any dependencies. -vm.$onInit = function() { - modelObject = blockEditorService.createModelObject(vm.model.value, vm.model.editor, vm.model.config.blocks, scopeOfExistence); - modelObject.load().then(onLoaded); -} -function onLoaded() { - // Define the default layout, this is used when there is no data stored for this property. - var defaultLayout = []; - // We store a reference to layout as we have to maintain this. - // The getLayout method gives us a reference to the layout-object based on the property-editor alias. The defaultLayout will be initialized if it does not exist. - vm.layout = modelObject.getLayout(defaultLayout); -} -``` - -### Create a Block - -Use the Model Object to create a Block and append the returned layout-entry to the `layout`. - -In the following example we will create a new block and append it at the appropriate location in the 'layout' object: - -```js -// continuing from previous example. - -// Creates a block and returns a layout entry. The layout entry is not part of layout yet as its not managed by the Model Object. -var layoutEntry = modelObject.create(contentTypeKey); -if (layoutEntry === null) { - // The creation was not successful, therefore exit and without appending anything to our 'layout' object. - return false; -} -// If we reach this line, we are good to add the layoutEntry to layout model. -// In this example our layout is an array and we would like to append the new block as the last entry. -vm.layout.push(layoutEntry); -``` - -### Working with Blocks - -The layout-entries alone do not provide much value when displaying or editing Blocks. - -Our Model Object allows obtaining a Block Object by parsing a block's layout-entry for a specific Block. - -The Block Object provides data of interest. The most important of these properties are: Block configuration, a label and the Block content in the Element Type Data Model format. This Content-model is useful for building the UI for editing the Content of a Block. - -This example uses the Model Object to retrive a Block Object for outputting its label in the console. - -```js -// continuing from the basic setup example. - -if (vm.layout.length > 0) { - // Get first entry of from the layout, which is an array in this example. - var firstLayoutEntry = vm.layout[0]; - - // Create a Block Object for that entry. - var block = modelObject.getBlockObject(firstLayoutEntry); - - // Check if the Block Object creation went well. (If a block is supported by the configuration of the Property Editor) - if (block !== null) { - console.log(block.label); - } -} -``` - -This similar example uses the Block Object for setting a value on the first property in the Blocks Content. - -```js -// continuing from the basic setup example. - -if (vm.layout.length > 0) { - // Get first entry of from the layout, which is an array in this example. - var firstLayoutEntry = vm.layout[0]; - - // Create a Block Object for that entry. - var block = modelObject.getBlockObject(firstLayoutEntry); - - // Check if the Block Object creation went well. (If a block is supported by the configuration of the Property Editor) - if (block !== null) { - - // This line edits the value of 'myProp' directly, available by 'block.data': - block.data.myProp = "Hello world"; - - // Alternatively you can use this line, which edits the data throught the Element Type data model avaiable in 'block.content': - block.content.variants[0].tabs[0].properties[0].value = "Hello world"; // This value will automatically be synced to the Property Editors Data Model, ´block.data.myProp´ - } -} -``` - -See [blockEditorModelObject](https://our.umbraco.com/apidocs/v8/ui/#/api/umbraco.services.blockEditorModelObject#methods\_getBlockObject) for the getBlockObject method for more information on the properties avaiable on a Block Object. - -## Remove a Block - -Removing a Block and destroying its data is done by calling the `removeDataAndDestroyModel` method of the Model Object, which allows us to maintain the 'layout' object. - -Your code will be based on working with Block Objects and therefore removal of a Block is be done by referring to a Block Object. - -This example shows how to remove the first Block of our imaginary Block Editor and remove the block from our layout. - -```js -// continuing from the basic setup example. - -if (vm.layout.length > 0) { - // Get first entry of from the layout, which is an array in this sample. - var firstLayoutEntry = vm.layout[0]; - - // Create a Block Object for that entry. - var block = modelObject.getBlockObject(firstLayoutEntry); - - // Check if the Block Object creation went well. (If a block isnt supported by the configuration of the Property Editor) - if(block !== null) { - - modelObject.removeDataAndDestroyModel(block);// Removing the data of our block and destroying the Block Object for performance reasons. - - // We need to maintain the 'layout' object, so therefor its up to our code to remove the block from the 'layout' object. - const index = array.indexOf(5); - if (index > -1) { - vm.layout.splice(index, 1); - } - } -} -``` - -## Manage Block Objects for general use through out your Property Editor - -Block Objects are used extensively and should be available throughout your Block Editor's runtime, rather than created for each action. - -You probably want to use BlockObjects for your property-editor view. We append them to layout entries, so you can access them as properties from the layout object. - -```js -// continuing from the basic setup example. - -var invalidLayoutItems = []; - -// Append the blockObjects to our layout. -vm.layout.forEach(entry => { - -// As we might have the same property-editor displayed multiple times on screen (splitview) we only need to initialize a BlockObject if its not already in place. - - // $block must have the 'data' property to be a valid BlockObject, if not it is considered a destroyed blockObject. - if (entry.$block === undefined || entry.$block === null || entry.$block.data === undefined) { - var block = modelObject.getBlockObject(entry); - - // If this entry was not supported by our property-editor it would return 'null'. - if (block !== null) { - entry.$block = block; - } else { - // We didnt succeed initializing this Block, therefore we need to filter this out of 'layout'. This only happens if the content data of the block couldn't be found. - invalidLayoutItems.push(entry); - } - } -}); - -// remove the ones that are invalid -invalidLayoutItems.forEach(entry => { - var index = vm.layout.findIndex(x => x === entry); - if (index >= 0) { - vm.layout.splice(index, 1); - } -}); -``` - -The following example loops through a layout array to display the contentUdi of each block: - -```html -
- -

- -
-``` diff --git a/14/umbraco-cms/customizing/property-editors/build-a-block-editor.md b/14/umbraco-cms/customizing/property-editors/build-a-block-editor.md deleted file mode 100644 index 8a8133dd14f..00000000000 --- a/14/umbraco-cms/customizing/property-editors/build-a-block-editor.md +++ /dev/null @@ -1,311 +0,0 @@ -# Build a Block Editor - -{% hint style="warning" %} -This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. -{% endhint %} - -Before reading this document we highly recommend that you familiarise yourself with [the basics of developing a custom Property Editor for Umbraco](../../tutorials/creating-a-property-editor/). - -## Setup your Property Editor as a Block Property Editor - -In order for your editor to become a Block Editor, you must first declare it using C#: - -{% code title="UnicornBlocksPropertyEditor.cs" %} -```csharp -using Umbraco.Cms.Core.IO; -using Umbraco.Cms.Core.Serialization; -using Umbraco.Cms.Core.PropertyEditors; - -namespace UmbracoDocs.Samples; - -[DataEditor("MyOwn.UnicornBlocksEditor", ValueType = ValueTypes.Json, ValueEditorIsReusable = false)] -public class UnicornBlocksPropertyEditor : BlockListPropertyEditorBase -{ - private readonly IIOHelper _ioHelper; - - public UnicornBlocksPropertyEditor( - IDataValueEditorFactory dataValueEditorFactory, - IBlockValuePropertyIndexValueFactory blockValuePropertyIndexValueFactory, - IJsonSerializer jsonSerializer, - IOHelper ioHelper) - : base(dataValueEditorFactory, blockValuePropertyIndexValueFactory, jsonSerializer) - => _ioHelper = ioHelper; - - protected override IConfigurationEditor CreateConfigurationEditor() => - new UnicornBlocksConfigurationEditor(_ioHelper); -} -``` -{% endcode %} - -{% code title="UnicornBlocksConfigurationEditor.cs" %} -```csharp -using Umbraco.Cms.Core.IO; -using Umbraco.Cms.Core.PropertyEditors; - -namespace UmbracoDocs.Samples; - -public class UnicornBlocksConfigurationEditor : ConfigurationEditor -{ - public UnicornBlocksConfigurationEditor(IIOHelper ioHelper) - : base(ioHelper) - { - } -} -``` -{% endcode %} - -{% hint style="info" %} -It is not strictly necessary to define your own property editor in C#. As outlined in the [Composition](composition/) article, all Umbraco core property editors can be reused. - -The code sample above inherits all functionality from Block List and adds no new functionality. If this is sufficient, you can use the Block List property editor alias `"Umbraco.BlockList"` as Property Editor Schema in your [package manifest](../umbraco-package.md). - -It is, however, recommended to declare your own Block Editors in C#. As you will see in the following, the property editor alias (`"MyOwn.UnicornBlocksEditor"`) will be part of the data structure. For any eventual future extensibility, it is good to have the correct alias in the content structure from the beginning. -{% endhint %} - -## Data structure of Block Editors - -The Block Editor data structure consists of three main parts: - -**Layout**: The Layout defines Blocks that each will reference (by UDI) a content item in the list of data. The Layout object pairs keys with Property Editor aliases and their value type varies based on setup. - -**ContentData**: A list of content items based on ElementTypes (IPublishedElement). - -**SettingsData**: A list of content items based on ElementTypes (IPublishedElement). - -In the following example the layout object "MyOwn.UnicornBlocksEditor" is of type Array. - -```json -{ - "layout": { - "MyOwn.UnicornBlocksEditor": [ - { - "contentUdi": "umb://element/fffba547615b4e9ab4ab2a7674845bc9" - }, - { - "contentUdi": "umb://element/e7dba547615b4e9ab4ab2a7674845bc9", - "settingsUdi": "umb://element/a47667bcba54845b15b4e9ab4ab2a7c8" - } - ] - }, - "contentData": [ - { - "udi": "umb://element/fffba547615b4e9ab4ab2a7674845bc9", - "contentTypeKey": "09876595489865786897", - "__yourPropertyAlias__": "Hello world" - }, - { - "udi": "umb://element/e7dba547615b4e9ab4ab2a7674845bc9", - "contentTypeKey": "123456789097654323456", - "__yourPropertyAlias1__": "Hello world", - "__yourPropertyAlias2__": "Hello world", - "__yourPropertyAlias3__": "Hello world" - } - ], - "settingsData": [ - { - "udi": "umb://element/a47667bcba54845b15b4e9ab4ab2a7c8", - "contentTypeKey": "09876595489865786897", - "__yourPropertyAlias__": "Hello world" - } - ] -} -``` - -## Client side code - -### Basic knowledge for understanding how to work with Block Editor data - -We created the BlockEditorModelObject to aid in managing the presented Data Structure in the Block Editor. - -To get a better understanding of what the Model Object does for you, we need to look at some usages of the Model Object. - -### Maintain and work with the Layout of a Block Editor - -The `layout` of a Block Editor can be any structure. Therefore the Model Object (BlockEditorModelObject) cannot maintain this data. Our usage of the Model Object becomes complex. We give it a reference to a `layout` entry and perform an action that may need to reflect changes back to the `layout`. - -Since the origin of blocks is in the `layout` the Model Object only can serve as a helper to maintain and create data. Therefore the Property Editor code will be using the `layout` as origin, using the Model Object to help manage specific parts. - -This is explained in more detail below. - -### The basic setup for a Block Editor - -Instantiate a Model Object and load dependencies. Provide the basic structure for the `layout` property when receiving the reference to it: - -```js -// We must get a scope that exists in all the lifetime of this data. Across variants and split-view. -var scopeOfExistence = $scope; -// Setup your component to require umbVariantContentEditors and vm.umbElementEditorContent. If one of them is avaiable use the method getScope to retrieve a shared scope for multiple editors of this content. -if(vm.umbVariantContentEditors && vm.umbVariantContentEditors.getScope) { - scopeOfExistence = vm.umbVariantContentEditors.getScope(); -} else if(vm.umbElementEditorContent && vm.umbElementEditorContent.getScope) { - scopeOfExistence = vm.umbElementEditorContent.getScope(); -} -// Define variables for layout and modelObject as you will be using these throughout your property editor. -vm.layout; -var modelObject; - -// When we are ready we can instantiate the Model Object and load any dependencies. -vm.$onInit = function() { - modelObject = blockEditorService.createModelObject(vm.model.value, vm.model.editor, vm.model.config.blocks, scopeOfExistence); - modelObject.load().then(onLoaded); -} -function onLoaded() { - // Define the default layout, this is used when there is no data stored for this property. - var defaultLayout = []; - // We store a reference to layout as we have to maintain this. - // The getLayout method gives us a reference to the layout-object based on the property-editor alias. The defaultLayout will be initialized if it does not exist. - vm.layout = modelObject.getLayout(defaultLayout); -} -``` - -### Create a Block - -Use the Model Object to create a Block and append the returned layout-entry to the `layout`. - -In the following example we will create a new block and append it at the appropriate location in the 'layout' object: - -```js -// continuing from previous example. - -// Creates a block and returns a layout entry. The layout entry is not part of layout yet as its not managed by the Model Object. -var layoutEntry = modelObject.create(contentTypeKey); -if (layoutEntry === null) { - // The creation was not successful, therefore exit and without appending anything to our 'layout' object. - return false; -} -// If we reach this line, we are good to add the layoutEntry to layout model. -// In this example our layout is an array and we would like to append the new block as the last entry. -vm.layout.push(layoutEntry); -``` - -### Working with Blocks - -The layout-entries alone do not provide much value when displaying or editing Blocks. - -Our Model Object allows obtaining a Block Object by parsing a block's layout-entry for a specific Block. - -The Block Object provides data of interest. The most important of these properties are: Block configuration, a label and the Block content in the Element Type Data Model format. This Content-model is useful for building the UI for editing the Content of a Block. - -This example uses the Model Object to retrive a Block Object for outputting its label in the console. - -```js -// continuing from the basic setup example. - -if (vm.layout.length > 0) { - // Get first entry of from the layout, which is an array in this example. - var firstLayoutEntry = vm.layout[0]; - - // Create a Block Object for that entry. - var block = modelObject.getBlockObject(firstLayoutEntry); - - // Check if the Block Object creation went well. (If a block is supported by the configuration of the Property Editor) - if (block !== null) { - console.log(block.label); - } -} -``` - -This similar example uses the Block Object for setting a value on the first property in the Blocks Content. - -```js -// continuing from the basic setup example. - -if (vm.layout.length > 0) { - // Get first entry of from the layout, which is an array in this example. - var firstLayoutEntry = vm.layout[0]; - - // Create a Block Object for that entry. - var block = modelObject.getBlockObject(firstLayoutEntry); - - // Check if the Block Object creation went well. (If a block is supported by the configuration of the Property Editor) - if (block !== null) { - - // This line edits the value of 'myProp' directly, available by 'block.data': - block.data.myProp = "Hello world"; - - // Alternatively you can use this line, which edits the data throught the Element Type data model avaiable in 'block.content': - block.content.variants[0].tabs[0].properties[0].value = "Hello world"; // This value will automatically be synced to the Property Editors Data Model, ´block.data.myProp´ - } -} -``` - -## Remove a Block - -Removing a Block and destroying its data is done by calling the `removeDataAndDestroyModel` method of the Model Object, which allows us to maintain the 'layout' object. - -Your code will be based on working with Block Objects and therefore removal of a Block is be done by referring to a Block Object. - -This example shows how to remove the first Block of our imaginary Block Editor and remove the block from our layout. - -```js -// continuing from the basic setup example. - -if (vm.layout.length > 0) { - // Get first entry of from the layout, which is an array in this sample. - var firstLayoutEntry = vm.layout[0]; - - // Create a Block Object for that entry. - var block = modelObject.getBlockObject(firstLayoutEntry); - - // Check if the Block Object creation went well. (If a block isnt supported by the configuration of the Property Editor) - if(block !== null) { - - modelObject.removeDataAndDestroyModel(block);// Removing the data of our block and destroying the Block Object for performance reasons. - - // We need to maintain the 'layout' object, so therefor its up to our code to remove the block from the 'layout' object. - const index = array.indexOf(5); - if (index > -1) { - vm.layout.splice(index, 1); - } - } -} -``` - -## Manage Block Objects for general use through out your Property Editor - -Block Objects are used extensively and should be available throughout your Block Editor's runtime, rather than created for each action. - -You probably want to use BlockObjects for your property-editor view. We append them to layout entries, so you can access them as properties from the layout object. - -```js -// continuing from the basic setup example. - -var invalidLayoutItems = []; - -// Append the blockObjects to our layout. -vm.layout.forEach(entry => { - -// As we might have the same property-editor displayed multiple times on screen (splitview) we only need to initialize a BlockObject if its not already in place. - - // $block must have the 'data' property to be a valid BlockObject, if not it is considered a destroyed blockObject. - if (entry.$block === undefined || entry.$block === null || entry.$block.data === undefined) { - var block = modelObject.getBlockObject(entry); - - // If this entry was not supported by our property-editor it would return 'null'. - if (block !== null) { - entry.$block = block; - } else { - // We didnt succeed initializing this Block, therefore we need to filter this out of 'layout'. This only happens if the content data of the block couldn't be found. - invalidLayoutItems.push(entry); - } - } -}); - -// remove the ones that are invalid -invalidLayoutItems.forEach(entry => { - var index = vm.layout.findIndex(x => x === entry); - if (index >= 0) { - vm.layout.splice(index, 1); - } -}); -``` - -The following example loops through a layout array to display the contentUdi of each block: - -```html -
- -

- -
-``` diff --git a/15/umbraco-cms/customizing/property-editors/build-a-block-editor.md b/15/umbraco-cms/customizing/property-editors/build-a-block-editor.md deleted file mode 100644 index 8a8133dd14f..00000000000 --- a/15/umbraco-cms/customizing/property-editors/build-a-block-editor.md +++ /dev/null @@ -1,311 +0,0 @@ -# Build a Block Editor - -{% hint style="warning" %} -This page is a work in progress and may undergo further revisions, updates, or amendments. The information contained herein is subject to change without notice. -{% endhint %} - -Before reading this document we highly recommend that you familiarise yourself with [the basics of developing a custom Property Editor for Umbraco](../../tutorials/creating-a-property-editor/). - -## Setup your Property Editor as a Block Property Editor - -In order for your editor to become a Block Editor, you must first declare it using C#: - -{% code title="UnicornBlocksPropertyEditor.cs" %} -```csharp -using Umbraco.Cms.Core.IO; -using Umbraco.Cms.Core.Serialization; -using Umbraco.Cms.Core.PropertyEditors; - -namespace UmbracoDocs.Samples; - -[DataEditor("MyOwn.UnicornBlocksEditor", ValueType = ValueTypes.Json, ValueEditorIsReusable = false)] -public class UnicornBlocksPropertyEditor : BlockListPropertyEditorBase -{ - private readonly IIOHelper _ioHelper; - - public UnicornBlocksPropertyEditor( - IDataValueEditorFactory dataValueEditorFactory, - IBlockValuePropertyIndexValueFactory blockValuePropertyIndexValueFactory, - IJsonSerializer jsonSerializer, - IOHelper ioHelper) - : base(dataValueEditorFactory, blockValuePropertyIndexValueFactory, jsonSerializer) - => _ioHelper = ioHelper; - - protected override IConfigurationEditor CreateConfigurationEditor() => - new UnicornBlocksConfigurationEditor(_ioHelper); -} -``` -{% endcode %} - -{% code title="UnicornBlocksConfigurationEditor.cs" %} -```csharp -using Umbraco.Cms.Core.IO; -using Umbraco.Cms.Core.PropertyEditors; - -namespace UmbracoDocs.Samples; - -public class UnicornBlocksConfigurationEditor : ConfigurationEditor -{ - public UnicornBlocksConfigurationEditor(IIOHelper ioHelper) - : base(ioHelper) - { - } -} -``` -{% endcode %} - -{% hint style="info" %} -It is not strictly necessary to define your own property editor in C#. As outlined in the [Composition](composition/) article, all Umbraco core property editors can be reused. - -The code sample above inherits all functionality from Block List and adds no new functionality. If this is sufficient, you can use the Block List property editor alias `"Umbraco.BlockList"` as Property Editor Schema in your [package manifest](../umbraco-package.md). - -It is, however, recommended to declare your own Block Editors in C#. As you will see in the following, the property editor alias (`"MyOwn.UnicornBlocksEditor"`) will be part of the data structure. For any eventual future extensibility, it is good to have the correct alias in the content structure from the beginning. -{% endhint %} - -## Data structure of Block Editors - -The Block Editor data structure consists of three main parts: - -**Layout**: The Layout defines Blocks that each will reference (by UDI) a content item in the list of data. The Layout object pairs keys with Property Editor aliases and their value type varies based on setup. - -**ContentData**: A list of content items based on ElementTypes (IPublishedElement). - -**SettingsData**: A list of content items based on ElementTypes (IPublishedElement). - -In the following example the layout object "MyOwn.UnicornBlocksEditor" is of type Array. - -```json -{ - "layout": { - "MyOwn.UnicornBlocksEditor": [ - { - "contentUdi": "umb://element/fffba547615b4e9ab4ab2a7674845bc9" - }, - { - "contentUdi": "umb://element/e7dba547615b4e9ab4ab2a7674845bc9", - "settingsUdi": "umb://element/a47667bcba54845b15b4e9ab4ab2a7c8" - } - ] - }, - "contentData": [ - { - "udi": "umb://element/fffba547615b4e9ab4ab2a7674845bc9", - "contentTypeKey": "09876595489865786897", - "__yourPropertyAlias__": "Hello world" - }, - { - "udi": "umb://element/e7dba547615b4e9ab4ab2a7674845bc9", - "contentTypeKey": "123456789097654323456", - "__yourPropertyAlias1__": "Hello world", - "__yourPropertyAlias2__": "Hello world", - "__yourPropertyAlias3__": "Hello world" - } - ], - "settingsData": [ - { - "udi": "umb://element/a47667bcba54845b15b4e9ab4ab2a7c8", - "contentTypeKey": "09876595489865786897", - "__yourPropertyAlias__": "Hello world" - } - ] -} -``` - -## Client side code - -### Basic knowledge for understanding how to work with Block Editor data - -We created the BlockEditorModelObject to aid in managing the presented Data Structure in the Block Editor. - -To get a better understanding of what the Model Object does for you, we need to look at some usages of the Model Object. - -### Maintain and work with the Layout of a Block Editor - -The `layout` of a Block Editor can be any structure. Therefore the Model Object (BlockEditorModelObject) cannot maintain this data. Our usage of the Model Object becomes complex. We give it a reference to a `layout` entry and perform an action that may need to reflect changes back to the `layout`. - -Since the origin of blocks is in the `layout` the Model Object only can serve as a helper to maintain and create data. Therefore the Property Editor code will be using the `layout` as origin, using the Model Object to help manage specific parts. - -This is explained in more detail below. - -### The basic setup for a Block Editor - -Instantiate a Model Object and load dependencies. Provide the basic structure for the `layout` property when receiving the reference to it: - -```js -// We must get a scope that exists in all the lifetime of this data. Across variants and split-view. -var scopeOfExistence = $scope; -// Setup your component to require umbVariantContentEditors and vm.umbElementEditorContent. If one of them is avaiable use the method getScope to retrieve a shared scope for multiple editors of this content. -if(vm.umbVariantContentEditors && vm.umbVariantContentEditors.getScope) { - scopeOfExistence = vm.umbVariantContentEditors.getScope(); -} else if(vm.umbElementEditorContent && vm.umbElementEditorContent.getScope) { - scopeOfExistence = vm.umbElementEditorContent.getScope(); -} -// Define variables for layout and modelObject as you will be using these throughout your property editor. -vm.layout; -var modelObject; - -// When we are ready we can instantiate the Model Object and load any dependencies. -vm.$onInit = function() { - modelObject = blockEditorService.createModelObject(vm.model.value, vm.model.editor, vm.model.config.blocks, scopeOfExistence); - modelObject.load().then(onLoaded); -} -function onLoaded() { - // Define the default layout, this is used when there is no data stored for this property. - var defaultLayout = []; - // We store a reference to layout as we have to maintain this. - // The getLayout method gives us a reference to the layout-object based on the property-editor alias. The defaultLayout will be initialized if it does not exist. - vm.layout = modelObject.getLayout(defaultLayout); -} -``` - -### Create a Block - -Use the Model Object to create a Block and append the returned layout-entry to the `layout`. - -In the following example we will create a new block and append it at the appropriate location in the 'layout' object: - -```js -// continuing from previous example. - -// Creates a block and returns a layout entry. The layout entry is not part of layout yet as its not managed by the Model Object. -var layoutEntry = modelObject.create(contentTypeKey); -if (layoutEntry === null) { - // The creation was not successful, therefore exit and without appending anything to our 'layout' object. - return false; -} -// If we reach this line, we are good to add the layoutEntry to layout model. -// In this example our layout is an array and we would like to append the new block as the last entry. -vm.layout.push(layoutEntry); -``` - -### Working with Blocks - -The layout-entries alone do not provide much value when displaying or editing Blocks. - -Our Model Object allows obtaining a Block Object by parsing a block's layout-entry for a specific Block. - -The Block Object provides data of interest. The most important of these properties are: Block configuration, a label and the Block content in the Element Type Data Model format. This Content-model is useful for building the UI for editing the Content of a Block. - -This example uses the Model Object to retrive a Block Object for outputting its label in the console. - -```js -// continuing from the basic setup example. - -if (vm.layout.length > 0) { - // Get first entry of from the layout, which is an array in this example. - var firstLayoutEntry = vm.layout[0]; - - // Create a Block Object for that entry. - var block = modelObject.getBlockObject(firstLayoutEntry); - - // Check if the Block Object creation went well. (If a block is supported by the configuration of the Property Editor) - if (block !== null) { - console.log(block.label); - } -} -``` - -This similar example uses the Block Object for setting a value on the first property in the Blocks Content. - -```js -// continuing from the basic setup example. - -if (vm.layout.length > 0) { - // Get first entry of from the layout, which is an array in this example. - var firstLayoutEntry = vm.layout[0]; - - // Create a Block Object for that entry. - var block = modelObject.getBlockObject(firstLayoutEntry); - - // Check if the Block Object creation went well. (If a block is supported by the configuration of the Property Editor) - if (block !== null) { - - // This line edits the value of 'myProp' directly, available by 'block.data': - block.data.myProp = "Hello world"; - - // Alternatively you can use this line, which edits the data throught the Element Type data model avaiable in 'block.content': - block.content.variants[0].tabs[0].properties[0].value = "Hello world"; // This value will automatically be synced to the Property Editors Data Model, ´block.data.myProp´ - } -} -``` - -## Remove a Block - -Removing a Block and destroying its data is done by calling the `removeDataAndDestroyModel` method of the Model Object, which allows us to maintain the 'layout' object. - -Your code will be based on working with Block Objects and therefore removal of a Block is be done by referring to a Block Object. - -This example shows how to remove the first Block of our imaginary Block Editor and remove the block from our layout. - -```js -// continuing from the basic setup example. - -if (vm.layout.length > 0) { - // Get first entry of from the layout, which is an array in this sample. - var firstLayoutEntry = vm.layout[0]; - - // Create a Block Object for that entry. - var block = modelObject.getBlockObject(firstLayoutEntry); - - // Check if the Block Object creation went well. (If a block isnt supported by the configuration of the Property Editor) - if(block !== null) { - - modelObject.removeDataAndDestroyModel(block);// Removing the data of our block and destroying the Block Object for performance reasons. - - // We need to maintain the 'layout' object, so therefor its up to our code to remove the block from the 'layout' object. - const index = array.indexOf(5); - if (index > -1) { - vm.layout.splice(index, 1); - } - } -} -``` - -## Manage Block Objects for general use through out your Property Editor - -Block Objects are used extensively and should be available throughout your Block Editor's runtime, rather than created for each action. - -You probably want to use BlockObjects for your property-editor view. We append them to layout entries, so you can access them as properties from the layout object. - -```js -// continuing from the basic setup example. - -var invalidLayoutItems = []; - -// Append the blockObjects to our layout. -vm.layout.forEach(entry => { - -// As we might have the same property-editor displayed multiple times on screen (splitview) we only need to initialize a BlockObject if its not already in place. - - // $block must have the 'data' property to be a valid BlockObject, if not it is considered a destroyed blockObject. - if (entry.$block === undefined || entry.$block === null || entry.$block.data === undefined) { - var block = modelObject.getBlockObject(entry); - - // If this entry was not supported by our property-editor it would return 'null'. - if (block !== null) { - entry.$block = block; - } else { - // We didnt succeed initializing this Block, therefore we need to filter this out of 'layout'. This only happens if the content data of the block couldn't be found. - invalidLayoutItems.push(entry); - } - } -}); - -// remove the ones that are invalid -invalidLayoutItems.forEach(entry => { - var index = vm.layout.findIndex(x => x === entry); - if (index >= 0) { - vm.layout.splice(index, 1); - } -}); -``` - -The following example loops through a layout array to display the contentUdi of each block: - -```html -
- -

- -
-```