Content app for dictionary items
This commit is contained in:
committed by
Nathan Woulfe
parent
e04efe6067
commit
1d2272f536
32
src/Umbraco.Core/ContentApps/DictionaryContentAppFactory.cs
Normal file
32
src/Umbraco.Core/ContentApps/DictionaryContentAppFactory.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.ContentEditing;
|
||||
using Umbraco.Cms.Core.Models.Membership;
|
||||
|
||||
namespace Umbraco.Cms.Core.ContentApps
|
||||
{
|
||||
internal class DictionaryContentAppFactory : IContentAppFactory
|
||||
{
|
||||
private const int Weight = -100;
|
||||
|
||||
private ContentApp _dictionaryApp;
|
||||
|
||||
public ContentApp GetContentAppFor(object source, IEnumerable<IReadOnlyUserGroup> userGroups)
|
||||
{
|
||||
switch (source)
|
||||
{
|
||||
case IDictionaryItem _:
|
||||
return _dictionaryApp ??= new ContentApp
|
||||
{
|
||||
Alias = "dictionaryContent",
|
||||
Name = "Content",
|
||||
Icon = "icon-document",
|
||||
View = "views/dictionary/views/content/content.html",
|
||||
Weight = Weight
|
||||
};
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,8 @@ namespace Umbraco.Cms.Core.DependencyInjection
|
||||
.Append<ContentTypeDesignContentAppFactory>()
|
||||
.Append<ContentTypeListViewContentAppFactory>()
|
||||
.Append<ContentTypePermissionsContentAppFactory>()
|
||||
.Append<ContentTypeTemplatesContentAppFactory>();
|
||||
.Append<ContentTypeTemplatesContentAppFactory>()
|
||||
.Append<DictionaryContentAppFactory>();
|
||||
|
||||
// all built-in finders in the correct order,
|
||||
// devs can then modify this list on application startup
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
@@ -70,6 +70,10 @@ namespace Umbraco.Cms.Core.Manifest
|
||||
partA = "contentType";
|
||||
partB = contentType.Alias;
|
||||
break;
|
||||
case IDictionaryItem _:
|
||||
partA = "dictionary";
|
||||
partB = "*"; //Not really a different type for dictionary items
|
||||
break;
|
||||
|
||||
default:
|
||||
return null;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
@@ -17,6 +17,7 @@ namespace Umbraco.Cms.Core.Models.ContentEditing
|
||||
{
|
||||
Notifications = new List<BackOfficeNotification>();
|
||||
Translations = new List<DictionaryTranslationDisplay>();
|
||||
ContentApps = new List<ContentApp>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -37,5 +38,11 @@ namespace Umbraco.Cms.Core.Models.ContentEditing
|
||||
/// </summary>
|
||||
[DataMember(Name = "translations")]
|
||||
public List<DictionaryTranslationDisplay> Translations { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Apps for the dictionary item
|
||||
/// </summary>
|
||||
[DataMember(Name = "apps")]
|
||||
public List<ContentApp> ContentApps { get; private set; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Cms.Core.ContentApps;
|
||||
@@ -47,7 +47,7 @@ namespace Umbraco.Cms.Core.Models.Mapping
|
||||
return contentTypeBasic;
|
||||
}
|
||||
|
||||
public IEnumerable<ContentApp> GetContentApps(IUmbracoEntity source)
|
||||
public IEnumerable<ContentApp> GetContentApps(IEntity source)
|
||||
{
|
||||
var apps = _contentAppDefinitions.GetContentAppsFor(source).ToArray();
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
@@ -14,10 +14,12 @@ namespace Umbraco.Cms.Core.Models.Mapping
|
||||
public class DictionaryMapDefinition : IMapDefinition
|
||||
{
|
||||
private readonly ILocalizationService _localizationService;
|
||||
private readonly CommonMapper _commonMapper;
|
||||
|
||||
public DictionaryMapDefinition(ILocalizationService localizationService)
|
||||
public DictionaryMapDefinition(ILocalizationService localizationService, CommonMapper commonMapper)
|
||||
{
|
||||
_localizationService = localizationService;
|
||||
_commonMapper = commonMapper;
|
||||
}
|
||||
|
||||
public void DefineMaps(IUmbracoMapper mapper)
|
||||
@@ -44,6 +46,7 @@ namespace Umbraco.Cms.Core.Models.Mapping
|
||||
target.Name = source.ItemKey;
|
||||
target.ParentId = source.ParentId ?? Guid.Empty;
|
||||
target.Udi = Udi.Create(Constants.UdiEntityType.DictionaryItem, source.Key);
|
||||
target.ContentApps.AddRange(_commonMapper.GetContentApps(source));
|
||||
|
||||
// build up the path to make it possible to set active item in tree
|
||||
// TODO: check if there is a better way
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/**
|
||||
/**
|
||||
* @ngdoc controller
|
||||
* @name Umbraco.Editors.Dictionary.EditController
|
||||
* @function
|
||||
@@ -7,128 +7,131 @@
|
||||
* The controller for editing dictionary items
|
||||
*/
|
||||
function DictionaryEditController($scope, $routeParams, $location, dictionaryResource, navigationService, appState, editorState, contentEditingHelper, formHelper, notificationsService, localizationService) {
|
||||
|
||||
var vm = this;
|
||||
|
||||
//setup scope vars
|
||||
vm.nameDirty = false;
|
||||
vm.header = {};
|
||||
vm.header.editorfor = "template_insertDictionaryItem";
|
||||
vm.header.setPageTitle = true;
|
||||
var vm = this;
|
||||
|
||||
vm.page = {};
|
||||
vm.page.loading = false;
|
||||
vm.page.nameLocked = false;
|
||||
vm.page.menu = {};
|
||||
vm.page.menu.currentSection = appState.getSectionState("currentSection");
|
||||
vm.page.menu.currentNode = null;
|
||||
vm.description = "";
|
||||
vm.showBackButton = true;
|
||||
vm.maxlength = 1000;
|
||||
|
||||
vm.save = saveDictionary;
|
||||
vm.back = back;
|
||||
vm.change = change;
|
||||
|
||||
function loadDictionary() {
|
||||
//setup scope vars
|
||||
vm.nameDirty = false;
|
||||
vm.header = {};
|
||||
vm.header.editorfor = "template_insertDictionaryItem";
|
||||
vm.header.setPageTitle = true;
|
||||
|
||||
vm.page.loading = true;
|
||||
vm.page = {};
|
||||
vm.page.navigation = {};
|
||||
vm.page.loading = false;
|
||||
vm.page.nameLocked = false;
|
||||
vm.page.menu = {};
|
||||
vm.page.menu.currentSection = appState.getSectionState("currentSection");
|
||||
vm.page.menu.currentNode = null;
|
||||
vm.description = "";
|
||||
vm.showBackButton = true;
|
||||
vm.maxlength = 1000;
|
||||
|
||||
//we are editing so get the content item from the server
|
||||
dictionaryResource.getById($routeParams.id)
|
||||
.then(function (data) {
|
||||
bindDictionary(data);
|
||||
vm.page.loading = false;
|
||||
});
|
||||
vm.save = saveDictionary;
|
||||
vm.back = back;
|
||||
vm.change = change;
|
||||
|
||||
function loadDictionary() {
|
||||
|
||||
vm.page.loading = true;
|
||||
|
||||
//we are editing so get the content item from the server
|
||||
dictionaryResource.getById($routeParams.id)
|
||||
.then(function (data) {
|
||||
bindDictionary(data);
|
||||
vm.page.navigation = data.apps;
|
||||
data.apps[0].active = true;
|
||||
vm.page.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
function createTranslationProperty(translation) {
|
||||
return {
|
||||
alias: translation.isoCode,
|
||||
label: translation.displayName,
|
||||
hideLabel: false
|
||||
}
|
||||
}
|
||||
|
||||
function createTranslationProperty(translation) {
|
||||
return {
|
||||
alias: translation.isoCode,
|
||||
label: translation.displayName,
|
||||
hideLabel : false
|
||||
}
|
||||
}
|
||||
|
||||
function bindDictionary(data) {
|
||||
localizationService.localize("dictionaryItem_description").then(function (value) {
|
||||
vm.description = value.replace("%0%", data.name);
|
||||
});
|
||||
|
||||
// create data for umb-property displaying
|
||||
for (var i = 0; i < data.translations.length; i++) {
|
||||
data.translations[i].property = createTranslationProperty(data.translations[i]);
|
||||
change(data.translations[i]);
|
||||
}
|
||||
|
||||
contentEditingHelper.handleSuccessfulSave({
|
||||
scope: $scope,
|
||||
savedContent: data
|
||||
});
|
||||
|
||||
// set content
|
||||
vm.content = data;
|
||||
|
||||
//share state
|
||||
editorState.set(vm.content);
|
||||
|
||||
navigationService.syncTree({ tree: "dictionary", path: data.path, forceReload: true }).then(function (syncArgs) {
|
||||
vm.page.menu.currentNode = syncArgs.node;
|
||||
});
|
||||
}
|
||||
|
||||
function onInit() {
|
||||
loadDictionary();
|
||||
}
|
||||
|
||||
function saveDictionary() {
|
||||
if (formHelper.submitForm({ scope: $scope, statusMessage: "Saving..." })) {
|
||||
|
||||
vm.page.saveButtonState = "busy";
|
||||
|
||||
dictionaryResource.save(vm.content, vm.nameDirty)
|
||||
.then(function (data) {
|
||||
|
||||
formHelper.resetForm({ scope: $scope });
|
||||
|
||||
bindDictionary(data);
|
||||
|
||||
vm.page.saveButtonState = "success";
|
||||
},
|
||||
function (err) {
|
||||
|
||||
formHelper.resetForm({ scope: $scope, hasErrors: true });
|
||||
|
||||
contentEditingHelper.handleSaveError({
|
||||
err: err
|
||||
});
|
||||
|
||||
notificationsService.error(err.data.message);
|
||||
|
||||
vm.page.saveButtonState = "error";
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function back() {
|
||||
$location.path(vm.page.menu.currentSection + "/dictionary/list");
|
||||
}
|
||||
|
||||
function change(translation) {
|
||||
if (translation.translation) {
|
||||
var charsCount = translation.translation.length;
|
||||
translation.nearMaxLimit = charsCount > Math.max(vm.maxlength * .8, vm.maxlength - 50);
|
||||
}
|
||||
}
|
||||
|
||||
$scope.$watch("vm.content.name", function (newVal, oldVal) {
|
||||
//when the value changes, we need to set the name dirty
|
||||
if (newVal && (newVal !== oldVal) && typeof(oldVal) !== "undefined") {
|
||||
vm.nameDirty = true;
|
||||
}
|
||||
function bindDictionary(data) {
|
||||
localizationService.localize("dictionaryItem_description").then(function (value) {
|
||||
vm.description = value.replace("%0%", data.name);
|
||||
});
|
||||
|
||||
onInit();
|
||||
// create data for umb-property displaying
|
||||
for (var i = 0; i < data.translations.length; i++) {
|
||||
data.translations[i].property = createTranslationProperty(data.translations[i]);
|
||||
change(data.translations[i]);
|
||||
}
|
||||
|
||||
contentEditingHelper.handleSuccessfulSave({
|
||||
scope: $scope,
|
||||
savedContent: data
|
||||
});
|
||||
|
||||
// set content
|
||||
vm.content = data;
|
||||
|
||||
//share state
|
||||
editorState.set(vm.content);
|
||||
|
||||
navigationService.syncTree({ tree: "dictionary", path: data.path, forceReload: true }).then(function (syncArgs) {
|
||||
vm.page.menu.currentNode = syncArgs.node;
|
||||
});
|
||||
}
|
||||
|
||||
function onInit() {
|
||||
loadDictionary();
|
||||
}
|
||||
|
||||
function saveDictionary() {
|
||||
if (formHelper.submitForm({ scope: $scope, statusMessage: "Saving..." })) {
|
||||
|
||||
vm.page.saveButtonState = "busy";
|
||||
|
||||
dictionaryResource.save(vm.content, vm.nameDirty)
|
||||
.then(function (data) {
|
||||
|
||||
formHelper.resetForm({ scope: $scope });
|
||||
|
||||
bindDictionary(data);
|
||||
|
||||
vm.page.saveButtonState = "success";
|
||||
},
|
||||
function (err) {
|
||||
|
||||
formHelper.resetForm({ scope: $scope, hasErrors: true });
|
||||
|
||||
contentEditingHelper.handleSaveError({
|
||||
err: err
|
||||
});
|
||||
|
||||
notificationsService.error(err.data.message);
|
||||
|
||||
vm.page.saveButtonState = "error";
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function back() {
|
||||
$location.path(vm.page.menu.currentSection + "/dictionary/list");
|
||||
}
|
||||
|
||||
function change(translation) {
|
||||
if (translation.translation) {
|
||||
var charsCount = translation.translation.length;
|
||||
translation.nearMaxLimit = charsCount > Math.max(vm.maxlength * .8, vm.maxlength - 50);
|
||||
}
|
||||
}
|
||||
|
||||
$scope.$watch("vm.content.name", function (newVal, oldVal) {
|
||||
//when the value changes, we need to set the name dirty
|
||||
if (newVal && (newVal !== oldVal) && typeof (oldVal) !== "undefined") {
|
||||
vm.nameDirty = true;
|
||||
}
|
||||
});
|
||||
|
||||
onInit();
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.Dictionary.EditController", DictionaryEditController);
|
||||
|
||||
@@ -1,63 +1,45 @@
|
||||
<div ng-controller="Umbraco.Editors.Dictionary.EditController as vm">
|
||||
<umb-load-indicator ng-if="vm.page.loading"></umb-load-indicator>
|
||||
|
||||
<form name="contentForm"
|
||||
ng-submit="vm.save()"
|
||||
novalidate
|
||||
val-form-manager>
|
||||
<div ng-controller="Umbraco.Editors.Dictionary.EditController as vm">
|
||||
<umb-load-indicator ng-if="vm.page.loading"></umb-load-indicator>
|
||||
|
||||
<umb-editor-view ng-if="!vm.page.loading">
|
||||
<umb-editor-header
|
||||
name="vm.content.name"
|
||||
name-locked="vm.page.nameLocked"
|
||||
hide-icon="true"
|
||||
hide-description="true"
|
||||
hide-alias="true"
|
||||
on-back="vm.back()"
|
||||
show-back-button="vm.showBackButton"
|
||||
editorfor="vm.header.editorfor"
|
||||
setpagetitle="vm.header.setPageTitle">
|
||||
</umb-editor-header>
|
||||
|
||||
<umb-editor-container class="form-horizontal">
|
||||
<umb-box>
|
||||
<umb-box-content>
|
||||
<p ng-bind-html="vm.description"></p>
|
||||
<umb-property ng-repeat="translation in vm.content.translations | orderBy:'displayName'" property="translation.property">
|
||||
<form name="contentForm"
|
||||
ng-submit="vm.save()"
|
||||
novalidate
|
||||
val-form-manager>
|
||||
|
||||
<textarea rows="2" class="autogrow w-100"
|
||||
id="{{translation.property.alias}}"
|
||||
ng-model="translation.translation"
|
||||
maxlength="1000"
|
||||
ng-keyup="vm.change(translation)"
|
||||
ng-trim="false"></textarea>
|
||||
<div class="help" ng-if="translation.nearMaxLimit">
|
||||
<p tabindex="0">
|
||||
<span class="sr-only">{{ translation.displayName }} </span>
|
||||
<localize key="textbox_characters_left" tokens="[vm.maxlength - translation.translation.length]" watch-tokens="true">%0% characters left.</localize>
|
||||
</p>
|
||||
</div>
|
||||
</umb-property>
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
</umb-editor-container>
|
||||
|
||||
<umb-editor-footer>
|
||||
<umb-editor-view ng-if="!vm.page.loading">
|
||||
<umb-editor-header name="vm.content.name"
|
||||
name-locked="vm.page.nameLocked"
|
||||
hide-icon="true"
|
||||
hide-description="true"
|
||||
hide-alias="true"
|
||||
navigation="vm.page.navigation"
|
||||
on-back="vm.back()"
|
||||
show-back-button="vm.showBackButton"
|
||||
editorfor="vm.header.editorfor"
|
||||
setpagetitle="vm.header.setPageTitle">
|
||||
</umb-editor-header>
|
||||
|
||||
<umb-editor-footer-content-right>
|
||||
<umb-editor-container class="form-horizontal">
|
||||
<umb-editor-sub-views sub-views="vm.page.navigation"
|
||||
model="vm">
|
||||
</umb-editor-sub-views>
|
||||
</umb-editor-container>
|
||||
|
||||
<umb-button
|
||||
type="submit"
|
||||
button-style="success"
|
||||
state="vm.page.saveButtonState"
|
||||
shortcut="ctrl+s"
|
||||
label="Save"
|
||||
label-key="buttons_save">
|
||||
</umb-button>
|
||||
<umb-editor-footer>
|
||||
|
||||
</umb-editor-footer-content-right>
|
||||
<umb-editor-footer-content-right>
|
||||
|
||||
</umb-editor-footer>
|
||||
</umb-editor-view>
|
||||
</form>
|
||||
<umb-button type="submit"
|
||||
button-style="success"
|
||||
state="vm.page.saveButtonState"
|
||||
shortcut="ctrl+s"
|
||||
label="Save"
|
||||
label-key="buttons_save">
|
||||
</umb-button>
|
||||
|
||||
</umb-editor-footer-content-right>
|
||||
|
||||
</umb-editor-footer>
|
||||
</umb-editor-view>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<umb-box>
|
||||
<umb-box-content>
|
||||
<p ng-bind-html="model.description"></p>
|
||||
<umb-property ng-repeat="translation in model.content.translations | orderBy:'displayName'" property="translation.property">
|
||||
|
||||
<textarea rows="2" class="autogrow w-100"
|
||||
id="{{translation.property.alias}}"
|
||||
ng-model="translation.translation"
|
||||
maxlength="1000"
|
||||
ng-keyup="model.change(translation)"
|
||||
ng-trim="false"></textarea>
|
||||
<div class="help" ng-if="translation.nearMaxLimit">
|
||||
<p tabindex="0">
|
||||
<span class="sr-only">{{ translation.displayName }} </span>
|
||||
<localize key="textbox_characters_left" tokens="[model.maxlength - translation.translation.length]" watch-tokens="true">%0% characters left.</localize>
|
||||
</p>
|
||||
</div>
|
||||
</umb-property>
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
Reference in New Issue
Block a user