Renormalize
This commit is contained in:
@@ -1,66 +1,66 @@
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Factories
|
||||
{
|
||||
internal static class DictionaryItemFactory
|
||||
{
|
||||
#region Implementation of IEntityFactory<DictionaryItem,DictionaryDto>
|
||||
|
||||
public static IDictionaryItem BuildEntity(DictionaryDto dto)
|
||||
{
|
||||
var item = new DictionaryItem(dto.Parent, dto.Key);
|
||||
|
||||
try
|
||||
{
|
||||
item.DisableChangeTracking();
|
||||
|
||||
item.Id = dto.PrimaryKey;
|
||||
item.Key = dto.UniqueId;
|
||||
|
||||
// reset dirty initial properties (U4-1946)
|
||||
item.ResetDirtyProperties(false);
|
||||
return item;
|
||||
}
|
||||
finally
|
||||
{
|
||||
item.EnableChangeTracking();
|
||||
}
|
||||
}
|
||||
|
||||
public static DictionaryDto BuildDto(IDictionaryItem entity)
|
||||
{
|
||||
return new DictionaryDto
|
||||
{
|
||||
UniqueId = entity.Key,
|
||||
Key = entity.ItemKey,
|
||||
Parent = entity.ParentId,
|
||||
PrimaryKey = entity.Id,
|
||||
LanguageTextDtos = BuildLanguageTextDtos(entity)
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private static List<LanguageTextDto> BuildLanguageTextDtos(IDictionaryItem entity)
|
||||
{
|
||||
var list = new List<LanguageTextDto>();
|
||||
foreach (var translation in entity.Translations)
|
||||
{
|
||||
var text = new LanguageTextDto
|
||||
{
|
||||
LanguageId = translation.LanguageId,
|
||||
UniqueId = translation.Key,
|
||||
Value = translation.Value
|
||||
};
|
||||
|
||||
if (translation.HasIdentity)
|
||||
text.PrimaryKey = translation.Id;
|
||||
|
||||
list.Add(text);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
using System.Collections.Generic;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Factories
|
||||
{
|
||||
internal static class DictionaryItemFactory
|
||||
{
|
||||
#region Implementation of IEntityFactory<DictionaryItem,DictionaryDto>
|
||||
|
||||
public static IDictionaryItem BuildEntity(DictionaryDto dto)
|
||||
{
|
||||
var item = new DictionaryItem(dto.Parent, dto.Key);
|
||||
|
||||
try
|
||||
{
|
||||
item.DisableChangeTracking();
|
||||
|
||||
item.Id = dto.PrimaryKey;
|
||||
item.Key = dto.UniqueId;
|
||||
|
||||
// reset dirty initial properties (U4-1946)
|
||||
item.ResetDirtyProperties(false);
|
||||
return item;
|
||||
}
|
||||
finally
|
||||
{
|
||||
item.EnableChangeTracking();
|
||||
}
|
||||
}
|
||||
|
||||
public static DictionaryDto BuildDto(IDictionaryItem entity)
|
||||
{
|
||||
return new DictionaryDto
|
||||
{
|
||||
UniqueId = entity.Key,
|
||||
Key = entity.ItemKey,
|
||||
Parent = entity.ParentId,
|
||||
PrimaryKey = entity.Id,
|
||||
LanguageTextDtos = BuildLanguageTextDtos(entity)
|
||||
};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private static List<LanguageTextDto> BuildLanguageTextDtos(IDictionaryItem entity)
|
||||
{
|
||||
var list = new List<LanguageTextDto>();
|
||||
foreach (var translation in entity.Translations)
|
||||
{
|
||||
var text = new LanguageTextDto
|
||||
{
|
||||
LanguageId = translation.LanguageId,
|
||||
UniqueId = translation.Key,
|
||||
Value = translation.Value
|
||||
};
|
||||
|
||||
if (translation.HasIdentity)
|
||||
text.PrimaryKey = translation.Id;
|
||||
|
||||
list.Add(text);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,464 +1,464 @@
|
||||
/**
|
||||
* @ngdoc controller
|
||||
* @name Umbraco.Editors.DocumentType.EditController
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* The controller for the content type editor
|
||||
*/
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function DocumentTypesEditController($scope, $routeParams, $injector, contentTypeResource, dataTypeResource, editorState, contentEditingHelper, formHelper, navigationService, iconHelper, contentTypeHelper, notificationsService, $filter, $q, localizationService, overlayHelper, eventsService) {
|
||||
|
||||
var vm = this;
|
||||
var evts = [];
|
||||
|
||||
var disableTemplates = Umbraco.Sys.ServerVariables.features.disabledFeatures.disableTemplates;
|
||||
var documentTypeId = $routeParams.id;
|
||||
var create = $routeParams.create;
|
||||
var noTemplate = $routeParams.notemplate;
|
||||
var infiniteMode = $scope.model && $scope.model.infiniteMode;
|
||||
|
||||
vm.save = save;
|
||||
vm.close = close;
|
||||
|
||||
vm.currentNode = null;
|
||||
vm.contentType = {};
|
||||
vm.labels = {};
|
||||
vm.submitButtonKey = "buttons_save";
|
||||
vm.generateModelsKey = "buttons_saveAndGenerateModels";
|
||||
|
||||
vm.page = {};
|
||||
vm.page.loading = false;
|
||||
vm.page.saveButtonState = "init";
|
||||
vm.page.navigation = [];
|
||||
|
||||
var labelKeys = [
|
||||
"general_design",
|
||||
"general_listView",
|
||||
"general_rights",
|
||||
"treeHeaders_templates",
|
||||
"main_sections",
|
||||
"shortcuts_navigateSections",
|
||||
"shortcuts_addTab",
|
||||
"shortcuts_addProperty",
|
||||
"shortcuts_addEditor",
|
||||
"shortcuts_editDataType",
|
||||
"shortcuts_toggleListView",
|
||||
"shortcuts_toggleAllowAsRoot",
|
||||
"shortcuts_addChildNode",
|
||||
"shortcuts_addTemplate"
|
||||
];
|
||||
|
||||
onInit();
|
||||
|
||||
function onInit() {
|
||||
// get init values from model when in infinite mode
|
||||
if(infiniteMode) {
|
||||
documentTypeId = $scope.model.id;
|
||||
create = $scope.model.create;
|
||||
noTemplate = $scope.model.notemplate;
|
||||
vm.submitButtonKey = "buttons_saveAndClose";
|
||||
vm.generateModelsKey = "buttons_generateModelsAndClose";
|
||||
}
|
||||
}
|
||||
|
||||
localizationService.localizeMany(labelKeys).then(function (values) {
|
||||
// navigation
|
||||
vm.labels.design = values[0];
|
||||
vm.labels.listview = values[1];
|
||||
vm.labels.permissions = values[2];
|
||||
vm.labels.templates = values[3];
|
||||
// keyboard shortcuts
|
||||
vm.labels.sections = values[4];
|
||||
vm.labels.navigateSections = values[5];
|
||||
vm.labels.addTab = values[6];
|
||||
vm.labels.addProperty = values[7];
|
||||
vm.labels.addEditor = values[8];
|
||||
vm.labels.editDataType = values[9];
|
||||
vm.labels.toggleListView = values[10];
|
||||
vm.labels.allowAsRoot = values[11];
|
||||
vm.labels.addChildNode = values[12];
|
||||
vm.labels.addTemplate = values[13];
|
||||
|
||||
var buttons = [
|
||||
{
|
||||
"name": vm.labels.design,
|
||||
"alias": "design",
|
||||
"icon": "icon-document-dashed-line",
|
||||
"view": "views/documenttypes/views/design/design.html",
|
||||
"active": true
|
||||
},
|
||||
{
|
||||
"name": vm.labels.listview,
|
||||
"alias": "listView",
|
||||
"icon": "icon-list",
|
||||
"view": "views/documenttypes/views/listview/listview.html"
|
||||
},
|
||||
{
|
||||
"name": vm.labels.permissions,
|
||||
"alias": "permissions",
|
||||
"icon": "icon-keychain",
|
||||
"view": "views/documenttypes/views/permissions/permissions.html"
|
||||
},
|
||||
{
|
||||
"name": vm.labels.templates,
|
||||
"alias": "templates",
|
||||
"icon": "icon-layout",
|
||||
"view": "views/documenttypes/views/templates/templates.html"
|
||||
}
|
||||
];
|
||||
|
||||
vm.page.keyboardShortcutsOverview = [
|
||||
{
|
||||
"name": vm.labels.sections,
|
||||
"shortcuts": [
|
||||
{
|
||||
"description": vm.labels.navigateSections,
|
||||
"keys": [{ "key": "1" }, { "key": "4" }],
|
||||
"keyRange": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": vm.labels.design,
|
||||
"shortcuts": [
|
||||
{
|
||||
"description": vm.labels.addTab,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "t" }]
|
||||
},
|
||||
{
|
||||
"description": vm.labels.addProperty,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "p" }]
|
||||
},
|
||||
{
|
||||
"description": vm.labels.addEditor,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "e" }]
|
||||
},
|
||||
{
|
||||
"description": vm.labels.editDataType,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "d" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": vm.labels.listview,
|
||||
"shortcuts": [
|
||||
{
|
||||
"description": vm.labels.toggleListView,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "l" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": vm.labels.permissions,
|
||||
"shortcuts": [
|
||||
{
|
||||
"description": vm.labels.allowAsRoot,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "r" }]
|
||||
},
|
||||
{
|
||||
"description": vm.labels.addChildNode,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "c" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": vm.labels.templates,
|
||||
"shortcuts": [
|
||||
{
|
||||
"description": vm.labels.addTemplate,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "t" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
loadButtons(buttons);
|
||||
|
||||
});
|
||||
|
||||
contentTypeHelper.checkModelsBuilderStatus().then(function (result) {
|
||||
vm.page.modelsBuilder = result;
|
||||
if (result) {
|
||||
//Models builder mode:
|
||||
vm.page.defaultButton = {
|
||||
alias: "save",
|
||||
hotKey: "ctrl+s",
|
||||
hotKeyWhenHidden: true,
|
||||
labelKey: vm.submitButtonKey,
|
||||
letter: "S",
|
||||
type: "submit",
|
||||
handler: function () { vm.save(); }
|
||||
};
|
||||
vm.page.subButtons = [{
|
||||
alias: "saveAndGenerateModels",
|
||||
hotKey: "ctrl+g",
|
||||
hotKeyWhenHidden: true,
|
||||
labelKey: vm.generateModelsKey,
|
||||
letter: "G",
|
||||
handler: function () {
|
||||
|
||||
vm.page.saveButtonState = "busy";
|
||||
|
||||
saveInternal().then(function (result) {
|
||||
|
||||
vm.page.saveButtonState = "busy";
|
||||
|
||||
localizationService.localize("modelsBuilder_buildingModels").then(function (headerValue) {
|
||||
localizationService.localize("modelsBuilder_waitingMessage").then(function (msgValue) {
|
||||
notificationsService.info(headerValue, msgValue);
|
||||
});
|
||||
});
|
||||
|
||||
contentTypeHelper.generateModels().then(function (result) {
|
||||
|
||||
// generateModels() returns the dashboard content
|
||||
if (!result.lastError) {
|
||||
|
||||
//re-check model status
|
||||
contentTypeHelper.checkModelsBuilderStatus().then(function (statusResult) {
|
||||
vm.page.modelsBuilder = statusResult;
|
||||
});
|
||||
|
||||
//clear and add success
|
||||
vm.page.saveButtonState = "init";
|
||||
localizationService.localize("modelsBuilder_modelsGenerated").then(function (value) {
|
||||
notificationsService.success(value);
|
||||
});
|
||||
|
||||
} else {
|
||||
vm.page.saveButtonState = "error";
|
||||
localizationService.localize("modelsBuilder_modelsExceptionInUlog").then(function (value) {
|
||||
notificationsService.error(value);
|
||||
});
|
||||
}
|
||||
|
||||
}, function () {
|
||||
vm.page.saveButtonState = "error";
|
||||
localizationService.localize("modelsBuilder_modelsGeneratedError").then(function (value) {
|
||||
notificationsService.error(value);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
});
|
||||
|
||||
if (create) {
|
||||
vm.page.loading = true;
|
||||
|
||||
//we are creating so get an empty data type item
|
||||
contentTypeResource.getScaffold(documentTypeId)
|
||||
.then(function (dt) {
|
||||
init(dt);
|
||||
vm.page.loading = false;
|
||||
});
|
||||
}
|
||||
else {
|
||||
loadDocumentType();
|
||||
}
|
||||
|
||||
function loadDocumentType() {
|
||||
vm.page.loading = true;
|
||||
contentTypeResource.getById(documentTypeId).then(function (dt) {
|
||||
init(dt);
|
||||
// we don't need to sync the tree in infinite mode
|
||||
if(!infiniteMode) {
|
||||
syncTreeNode(vm.contentType, dt.path, true);
|
||||
}
|
||||
vm.page.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
function loadButtons(buttons) {
|
||||
|
||||
angular.forEach(buttons,
|
||||
function (val, index) {
|
||||
|
||||
if (disableTemplates === true && val.alias === "templates") {
|
||||
buttons.splice(index, 1);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
vm.page.navigation = buttons;
|
||||
}
|
||||
|
||||
/* ---------- SAVE ---------- */
|
||||
|
||||
function save() {
|
||||
//return the saveInternal method but catch rejections since this is the upper most caller
|
||||
return saveInternal().catch(angular.noop);
|
||||
}
|
||||
|
||||
/** This internal save method performs the actual saving and returns a promise, not to be bound to any buttons but used by other bound methods */
|
||||
function saveInternal() {
|
||||
|
||||
// only save if there is no overlays open
|
||||
if (overlayHelper.getNumberOfOverlays() === 0) {
|
||||
|
||||
vm.page.saveButtonState = "busy";
|
||||
|
||||
// reformat allowed content types to array if id's
|
||||
vm.contentType.allowedContentTypes = contentTypeHelper.createIdArray(vm.contentType.allowedContentTypes);
|
||||
|
||||
return contentEditingHelper.contentEditorPerformSave({
|
||||
saveMethod: contentTypeResource.save,
|
||||
scope: $scope,
|
||||
content: vm.contentType,
|
||||
//We do not redirect on failure for doc types - this is because it is not possible to actually save the doc
|
||||
// type when server side validation fails - as opposed to content where we are capable of saving the content
|
||||
// item if server side validation fails
|
||||
redirectOnFailure: false,
|
||||
// we need to rebind... the IDs that have been created!
|
||||
rebindCallback: function (origContentType, savedContentType) {
|
||||
vm.contentType.id = savedContentType.id;
|
||||
vm.contentType.groups.forEach(function (group) {
|
||||
if (!group.name) return;
|
||||
var k = 0;
|
||||
while (k < savedContentType.groups.length && savedContentType.groups[k].name != group.name)
|
||||
k++;
|
||||
if (k == savedContentType.groups.length) {
|
||||
group.id = 0;
|
||||
return;
|
||||
}
|
||||
var savedGroup = savedContentType.groups[k];
|
||||
if (!group.id) group.id = savedGroup.id;
|
||||
|
||||
group.properties.forEach(function (property) {
|
||||
if (property.id || !property.alias) return;
|
||||
k = 0;
|
||||
while (k < savedGroup.properties.length && savedGroup.properties[k].alias != property.alias)
|
||||
k++;
|
||||
if (k == savedGroup.properties.length) {
|
||||
property.id = 0;
|
||||
return;
|
||||
}
|
||||
var savedProperty = savedGroup.properties[k];
|
||||
property.id = savedProperty.id;
|
||||
});
|
||||
});
|
||||
}
|
||||
}).then(function (data) {
|
||||
//success
|
||||
// we don't need to sync the tree in infinite mode
|
||||
if(!infiniteMode) {
|
||||
syncTreeNode(vm.contentType, data.path);
|
||||
}
|
||||
|
||||
// emit event
|
||||
var args = { documentType: vm.contentType };
|
||||
eventsService.emit("editors.documentType.saved", args);
|
||||
|
||||
vm.page.saveButtonState = "success";
|
||||
|
||||
if(infiniteMode && $scope.model.submit) {
|
||||
$scope.model.documentTypeAlias = vm.contentType.alias;
|
||||
$scope.model.submit($scope.model);
|
||||
}
|
||||
|
||||
return $q.resolve(data);
|
||||
}, function (err) {
|
||||
//error
|
||||
if (err) {
|
||||
editorState.set($scope.content);
|
||||
}
|
||||
else {
|
||||
localizationService.localize("speechBubbles_validationFailedHeader").then(function (headerValue) {
|
||||
localizationService.localize("speechBubbles_validationFailedMessage").then(function (msgValue) {
|
||||
notificationsService.error(headerValue, msgValue);
|
||||
});
|
||||
});
|
||||
}
|
||||
vm.page.saveButtonState = "error";
|
||||
return $q.reject(err);
|
||||
});
|
||||
}
|
||||
else {
|
||||
return $q.reject();
|
||||
}
|
||||
}
|
||||
|
||||
function init(contentType) {
|
||||
|
||||
// set all tab to inactive
|
||||
if (contentType.groups.length !== 0) {
|
||||
angular.forEach(contentType.groups, function (group) {
|
||||
|
||||
angular.forEach(group.properties, function (property) {
|
||||
// get data type details for each property
|
||||
getDataTypeDetails(property);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
// insert template on new doc types
|
||||
if (!noTemplate && contentType.id === 0) {
|
||||
contentType.defaultTemplate = contentTypeHelper.insertDefaultTemplatePlaceholder(contentType.defaultTemplate);
|
||||
contentType.allowedTemplates = contentTypeHelper.insertTemplatePlaceholder(contentType.allowedTemplates);
|
||||
}
|
||||
|
||||
// convert icons for content type
|
||||
convertLegacyIcons(contentType);
|
||||
|
||||
//set a shared state
|
||||
editorState.set(contentType);
|
||||
|
||||
vm.contentType = contentType;
|
||||
}
|
||||
|
||||
function convertLegacyIcons(contentType) {
|
||||
// make array to store contentType icon
|
||||
var contentTypeArray = [];
|
||||
|
||||
// push icon to array
|
||||
contentTypeArray.push({ "icon": contentType.icon });
|
||||
|
||||
// run through icon method
|
||||
iconHelper.formatContentTypeIcons(contentTypeArray);
|
||||
|
||||
// set icon back on contentType
|
||||
contentType.icon = contentTypeArray[0].icon;
|
||||
}
|
||||
|
||||
function getDataTypeDetails(property) {
|
||||
if (property.propertyState !== "init") {
|
||||
dataTypeResource.getById(property.dataTypeId)
|
||||
.then(function (dataType) {
|
||||
property.dataTypeIcon = dataType.icon;
|
||||
property.dataTypeName = dataType.name;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** Syncs the content type to it's tree node - this occurs on first load and after saving */
|
||||
function syncTreeNode(dt, path, initialLoad) {
|
||||
navigationService.syncTree({ tree: "documenttypes", path: path.split(","), forceReload: initialLoad !== true }).then(function (syncArgs) {
|
||||
vm.currentNode = syncArgs.node;
|
||||
});
|
||||
}
|
||||
|
||||
function close() {
|
||||
if($scope.model.close) {
|
||||
$scope.model.close($scope.model);
|
||||
}
|
||||
}
|
||||
|
||||
evts.push(eventsService.on("app.refreshEditor", function (name, error) {
|
||||
loadDocumentType();
|
||||
}));
|
||||
|
||||
//ensure to unregister from all events!
|
||||
$scope.$on('$destroy', function () {
|
||||
for (var e in evts) {
|
||||
eventsService.unsubscribe(evts[e]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.DocumentTypes.EditController", DocumentTypesEditController);
|
||||
})();
|
||||
/**
|
||||
* @ngdoc controller
|
||||
* @name Umbraco.Editors.DocumentType.EditController
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* The controller for the content type editor
|
||||
*/
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function DocumentTypesEditController($scope, $routeParams, $injector, contentTypeResource, dataTypeResource, editorState, contentEditingHelper, formHelper, navigationService, iconHelper, contentTypeHelper, notificationsService, $filter, $q, localizationService, overlayHelper, eventsService) {
|
||||
|
||||
var vm = this;
|
||||
var evts = [];
|
||||
|
||||
var disableTemplates = Umbraco.Sys.ServerVariables.features.disabledFeatures.disableTemplates;
|
||||
var documentTypeId = $routeParams.id;
|
||||
var create = $routeParams.create;
|
||||
var noTemplate = $routeParams.notemplate;
|
||||
var infiniteMode = $scope.model && $scope.model.infiniteMode;
|
||||
|
||||
vm.save = save;
|
||||
vm.close = close;
|
||||
|
||||
vm.currentNode = null;
|
||||
vm.contentType = {};
|
||||
vm.labels = {};
|
||||
vm.submitButtonKey = "buttons_save";
|
||||
vm.generateModelsKey = "buttons_saveAndGenerateModels";
|
||||
|
||||
vm.page = {};
|
||||
vm.page.loading = false;
|
||||
vm.page.saveButtonState = "init";
|
||||
vm.page.navigation = [];
|
||||
|
||||
var labelKeys = [
|
||||
"general_design",
|
||||
"general_listView",
|
||||
"general_rights",
|
||||
"treeHeaders_templates",
|
||||
"main_sections",
|
||||
"shortcuts_navigateSections",
|
||||
"shortcuts_addTab",
|
||||
"shortcuts_addProperty",
|
||||
"shortcuts_addEditor",
|
||||
"shortcuts_editDataType",
|
||||
"shortcuts_toggleListView",
|
||||
"shortcuts_toggleAllowAsRoot",
|
||||
"shortcuts_addChildNode",
|
||||
"shortcuts_addTemplate"
|
||||
];
|
||||
|
||||
onInit();
|
||||
|
||||
function onInit() {
|
||||
// get init values from model when in infinite mode
|
||||
if(infiniteMode) {
|
||||
documentTypeId = $scope.model.id;
|
||||
create = $scope.model.create;
|
||||
noTemplate = $scope.model.notemplate;
|
||||
vm.submitButtonKey = "buttons_saveAndClose";
|
||||
vm.generateModelsKey = "buttons_generateModelsAndClose";
|
||||
}
|
||||
}
|
||||
|
||||
localizationService.localizeMany(labelKeys).then(function (values) {
|
||||
// navigation
|
||||
vm.labels.design = values[0];
|
||||
vm.labels.listview = values[1];
|
||||
vm.labels.permissions = values[2];
|
||||
vm.labels.templates = values[3];
|
||||
// keyboard shortcuts
|
||||
vm.labels.sections = values[4];
|
||||
vm.labels.navigateSections = values[5];
|
||||
vm.labels.addTab = values[6];
|
||||
vm.labels.addProperty = values[7];
|
||||
vm.labels.addEditor = values[8];
|
||||
vm.labels.editDataType = values[9];
|
||||
vm.labels.toggleListView = values[10];
|
||||
vm.labels.allowAsRoot = values[11];
|
||||
vm.labels.addChildNode = values[12];
|
||||
vm.labels.addTemplate = values[13];
|
||||
|
||||
var buttons = [
|
||||
{
|
||||
"name": vm.labels.design,
|
||||
"alias": "design",
|
||||
"icon": "icon-document-dashed-line",
|
||||
"view": "views/documenttypes/views/design/design.html",
|
||||
"active": true
|
||||
},
|
||||
{
|
||||
"name": vm.labels.listview,
|
||||
"alias": "listView",
|
||||
"icon": "icon-list",
|
||||
"view": "views/documenttypes/views/listview/listview.html"
|
||||
},
|
||||
{
|
||||
"name": vm.labels.permissions,
|
||||
"alias": "permissions",
|
||||
"icon": "icon-keychain",
|
||||
"view": "views/documenttypes/views/permissions/permissions.html"
|
||||
},
|
||||
{
|
||||
"name": vm.labels.templates,
|
||||
"alias": "templates",
|
||||
"icon": "icon-layout",
|
||||
"view": "views/documenttypes/views/templates/templates.html"
|
||||
}
|
||||
];
|
||||
|
||||
vm.page.keyboardShortcutsOverview = [
|
||||
{
|
||||
"name": vm.labels.sections,
|
||||
"shortcuts": [
|
||||
{
|
||||
"description": vm.labels.navigateSections,
|
||||
"keys": [{ "key": "1" }, { "key": "4" }],
|
||||
"keyRange": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": vm.labels.design,
|
||||
"shortcuts": [
|
||||
{
|
||||
"description": vm.labels.addTab,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "t" }]
|
||||
},
|
||||
{
|
||||
"description": vm.labels.addProperty,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "p" }]
|
||||
},
|
||||
{
|
||||
"description": vm.labels.addEditor,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "e" }]
|
||||
},
|
||||
{
|
||||
"description": vm.labels.editDataType,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "d" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": vm.labels.listview,
|
||||
"shortcuts": [
|
||||
{
|
||||
"description": vm.labels.toggleListView,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "l" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": vm.labels.permissions,
|
||||
"shortcuts": [
|
||||
{
|
||||
"description": vm.labels.allowAsRoot,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "r" }]
|
||||
},
|
||||
{
|
||||
"description": vm.labels.addChildNode,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "c" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": vm.labels.templates,
|
||||
"shortcuts": [
|
||||
{
|
||||
"description": vm.labels.addTemplate,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "t" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
loadButtons(buttons);
|
||||
|
||||
});
|
||||
|
||||
contentTypeHelper.checkModelsBuilderStatus().then(function (result) {
|
||||
vm.page.modelsBuilder = result;
|
||||
if (result) {
|
||||
//Models builder mode:
|
||||
vm.page.defaultButton = {
|
||||
alias: "save",
|
||||
hotKey: "ctrl+s",
|
||||
hotKeyWhenHidden: true,
|
||||
labelKey: vm.submitButtonKey,
|
||||
letter: "S",
|
||||
type: "submit",
|
||||
handler: function () { vm.save(); }
|
||||
};
|
||||
vm.page.subButtons = [{
|
||||
alias: "saveAndGenerateModels",
|
||||
hotKey: "ctrl+g",
|
||||
hotKeyWhenHidden: true,
|
||||
labelKey: vm.generateModelsKey,
|
||||
letter: "G",
|
||||
handler: function () {
|
||||
|
||||
vm.page.saveButtonState = "busy";
|
||||
|
||||
saveInternal().then(function (result) {
|
||||
|
||||
vm.page.saveButtonState = "busy";
|
||||
|
||||
localizationService.localize("modelsBuilder_buildingModels").then(function (headerValue) {
|
||||
localizationService.localize("modelsBuilder_waitingMessage").then(function (msgValue) {
|
||||
notificationsService.info(headerValue, msgValue);
|
||||
});
|
||||
});
|
||||
|
||||
contentTypeHelper.generateModels().then(function (result) {
|
||||
|
||||
// generateModels() returns the dashboard content
|
||||
if (!result.lastError) {
|
||||
|
||||
//re-check model status
|
||||
contentTypeHelper.checkModelsBuilderStatus().then(function (statusResult) {
|
||||
vm.page.modelsBuilder = statusResult;
|
||||
});
|
||||
|
||||
//clear and add success
|
||||
vm.page.saveButtonState = "init";
|
||||
localizationService.localize("modelsBuilder_modelsGenerated").then(function (value) {
|
||||
notificationsService.success(value);
|
||||
});
|
||||
|
||||
} else {
|
||||
vm.page.saveButtonState = "error";
|
||||
localizationService.localize("modelsBuilder_modelsExceptionInUlog").then(function (value) {
|
||||
notificationsService.error(value);
|
||||
});
|
||||
}
|
||||
|
||||
}, function () {
|
||||
vm.page.saveButtonState = "error";
|
||||
localizationService.localize("modelsBuilder_modelsGeneratedError").then(function (value) {
|
||||
notificationsService.error(value);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
});
|
||||
|
||||
if (create) {
|
||||
vm.page.loading = true;
|
||||
|
||||
//we are creating so get an empty data type item
|
||||
contentTypeResource.getScaffold(documentTypeId)
|
||||
.then(function (dt) {
|
||||
init(dt);
|
||||
vm.page.loading = false;
|
||||
});
|
||||
}
|
||||
else {
|
||||
loadDocumentType();
|
||||
}
|
||||
|
||||
function loadDocumentType() {
|
||||
vm.page.loading = true;
|
||||
contentTypeResource.getById(documentTypeId).then(function (dt) {
|
||||
init(dt);
|
||||
// we don't need to sync the tree in infinite mode
|
||||
if(!infiniteMode) {
|
||||
syncTreeNode(vm.contentType, dt.path, true);
|
||||
}
|
||||
vm.page.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
function loadButtons(buttons) {
|
||||
|
||||
angular.forEach(buttons,
|
||||
function (val, index) {
|
||||
|
||||
if (disableTemplates === true && val.alias === "templates") {
|
||||
buttons.splice(index, 1);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
vm.page.navigation = buttons;
|
||||
}
|
||||
|
||||
/* ---------- SAVE ---------- */
|
||||
|
||||
function save() {
|
||||
//return the saveInternal method but catch rejections since this is the upper most caller
|
||||
return saveInternal().catch(angular.noop);
|
||||
}
|
||||
|
||||
/** This internal save method performs the actual saving and returns a promise, not to be bound to any buttons but used by other bound methods */
|
||||
function saveInternal() {
|
||||
|
||||
// only save if there is no overlays open
|
||||
if (overlayHelper.getNumberOfOverlays() === 0) {
|
||||
|
||||
vm.page.saveButtonState = "busy";
|
||||
|
||||
// reformat allowed content types to array if id's
|
||||
vm.contentType.allowedContentTypes = contentTypeHelper.createIdArray(vm.contentType.allowedContentTypes);
|
||||
|
||||
return contentEditingHelper.contentEditorPerformSave({
|
||||
saveMethod: contentTypeResource.save,
|
||||
scope: $scope,
|
||||
content: vm.contentType,
|
||||
//We do not redirect on failure for doc types - this is because it is not possible to actually save the doc
|
||||
// type when server side validation fails - as opposed to content where we are capable of saving the content
|
||||
// item if server side validation fails
|
||||
redirectOnFailure: false,
|
||||
// we need to rebind... the IDs that have been created!
|
||||
rebindCallback: function (origContentType, savedContentType) {
|
||||
vm.contentType.id = savedContentType.id;
|
||||
vm.contentType.groups.forEach(function (group) {
|
||||
if (!group.name) return;
|
||||
var k = 0;
|
||||
while (k < savedContentType.groups.length && savedContentType.groups[k].name != group.name)
|
||||
k++;
|
||||
if (k == savedContentType.groups.length) {
|
||||
group.id = 0;
|
||||
return;
|
||||
}
|
||||
var savedGroup = savedContentType.groups[k];
|
||||
if (!group.id) group.id = savedGroup.id;
|
||||
|
||||
group.properties.forEach(function (property) {
|
||||
if (property.id || !property.alias) return;
|
||||
k = 0;
|
||||
while (k < savedGroup.properties.length && savedGroup.properties[k].alias != property.alias)
|
||||
k++;
|
||||
if (k == savedGroup.properties.length) {
|
||||
property.id = 0;
|
||||
return;
|
||||
}
|
||||
var savedProperty = savedGroup.properties[k];
|
||||
property.id = savedProperty.id;
|
||||
});
|
||||
});
|
||||
}
|
||||
}).then(function (data) {
|
||||
//success
|
||||
// we don't need to sync the tree in infinite mode
|
||||
if(!infiniteMode) {
|
||||
syncTreeNode(vm.contentType, data.path);
|
||||
}
|
||||
|
||||
// emit event
|
||||
var args = { documentType: vm.contentType };
|
||||
eventsService.emit("editors.documentType.saved", args);
|
||||
|
||||
vm.page.saveButtonState = "success";
|
||||
|
||||
if(infiniteMode && $scope.model.submit) {
|
||||
$scope.model.documentTypeAlias = vm.contentType.alias;
|
||||
$scope.model.submit($scope.model);
|
||||
}
|
||||
|
||||
return $q.resolve(data);
|
||||
}, function (err) {
|
||||
//error
|
||||
if (err) {
|
||||
editorState.set($scope.content);
|
||||
}
|
||||
else {
|
||||
localizationService.localize("speechBubbles_validationFailedHeader").then(function (headerValue) {
|
||||
localizationService.localize("speechBubbles_validationFailedMessage").then(function (msgValue) {
|
||||
notificationsService.error(headerValue, msgValue);
|
||||
});
|
||||
});
|
||||
}
|
||||
vm.page.saveButtonState = "error";
|
||||
return $q.reject(err);
|
||||
});
|
||||
}
|
||||
else {
|
||||
return $q.reject();
|
||||
}
|
||||
}
|
||||
|
||||
function init(contentType) {
|
||||
|
||||
// set all tab to inactive
|
||||
if (contentType.groups.length !== 0) {
|
||||
angular.forEach(contentType.groups, function (group) {
|
||||
|
||||
angular.forEach(group.properties, function (property) {
|
||||
// get data type details for each property
|
||||
getDataTypeDetails(property);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
// insert template on new doc types
|
||||
if (!noTemplate && contentType.id === 0) {
|
||||
contentType.defaultTemplate = contentTypeHelper.insertDefaultTemplatePlaceholder(contentType.defaultTemplate);
|
||||
contentType.allowedTemplates = contentTypeHelper.insertTemplatePlaceholder(contentType.allowedTemplates);
|
||||
}
|
||||
|
||||
// convert icons for content type
|
||||
convertLegacyIcons(contentType);
|
||||
|
||||
//set a shared state
|
||||
editorState.set(contentType);
|
||||
|
||||
vm.contentType = contentType;
|
||||
}
|
||||
|
||||
function convertLegacyIcons(contentType) {
|
||||
// make array to store contentType icon
|
||||
var contentTypeArray = [];
|
||||
|
||||
// push icon to array
|
||||
contentTypeArray.push({ "icon": contentType.icon });
|
||||
|
||||
// run through icon method
|
||||
iconHelper.formatContentTypeIcons(contentTypeArray);
|
||||
|
||||
// set icon back on contentType
|
||||
contentType.icon = contentTypeArray[0].icon;
|
||||
}
|
||||
|
||||
function getDataTypeDetails(property) {
|
||||
if (property.propertyState !== "init") {
|
||||
dataTypeResource.getById(property.dataTypeId)
|
||||
.then(function (dataType) {
|
||||
property.dataTypeIcon = dataType.icon;
|
||||
property.dataTypeName = dataType.name;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** Syncs the content type to it's tree node - this occurs on first load and after saving */
|
||||
function syncTreeNode(dt, path, initialLoad) {
|
||||
navigationService.syncTree({ tree: "documenttypes", path: path.split(","), forceReload: initialLoad !== true }).then(function (syncArgs) {
|
||||
vm.currentNode = syncArgs.node;
|
||||
});
|
||||
}
|
||||
|
||||
function close() {
|
||||
if($scope.model.close) {
|
||||
$scope.model.close($scope.model);
|
||||
}
|
||||
}
|
||||
|
||||
evts.push(eventsService.on("app.refreshEditor", function (name, error) {
|
||||
loadDocumentType();
|
||||
}));
|
||||
|
||||
//ensure to unregister from all events!
|
||||
$scope.$on('$destroy', function () {
|
||||
for (var e in evts) {
|
||||
eventsService.unsubscribe(evts[e]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.DocumentTypes.EditController", DocumentTypesEditController);
|
||||
})();
|
||||
|
||||
@@ -1,272 +1,272 @@
|
||||
/**
|
||||
* @ngdoc controller
|
||||
* @name Umbraco.Editors.Media.EditController
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* The controller for the media editor
|
||||
*/
|
||||
function mediaEditController($scope, $routeParams, $q, appState, mediaResource, entityResource, navigationService, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, fileManager, treeService, formHelper, umbModelMapper, editorState, umbRequestHelper, $http, eventsService) {
|
||||
|
||||
var evts = [];
|
||||
var nodeId = null;
|
||||
var create = false;
|
||||
var infiniteMode = $scope.model && $scope.model.infiniteMode;
|
||||
|
||||
// when opening the editor through infinite editing get the
|
||||
// node id from the model instead of the route param
|
||||
if(infiniteMode && $scope.model.id) {
|
||||
nodeId = $scope.model.id;
|
||||
} else {
|
||||
nodeId = $routeParams.id;
|
||||
}
|
||||
|
||||
// when opening the editor through infinite editing get the
|
||||
// create option from the model instead of the route param
|
||||
if(infiniteMode) {
|
||||
create = $scope.model.create;
|
||||
} else {
|
||||
create = $routeParams.create;
|
||||
}
|
||||
|
||||
//setup scope vars
|
||||
$scope.currentSection = appState.getSectionState("currentSection");
|
||||
$scope.currentNode = null; //the editors affiliated node
|
||||
|
||||
$scope.page = {};
|
||||
$scope.page.loading = false;
|
||||
$scope.page.menu = {};
|
||||
$scope.page.menu.currentSection = appState.getSectionState("currentSection");
|
||||
$scope.page.menu.currentNode = null; //the editors affiliated node
|
||||
$scope.page.listViewPath = null;
|
||||
$scope.page.saveButtonState = "init";
|
||||
$scope.page.submitButtonLabel = "Save";
|
||||
|
||||
/** Syncs the content item to it's tree node - this occurs on first load and after saving */
|
||||
function syncTreeNode(content, path, initialLoad) {
|
||||
|
||||
if (!$scope.content.isChildOfListView) {
|
||||
navigationService.syncTree({ tree: "media", path: path.split(","), forceReload: initialLoad !== true }).then(function (syncArgs) {
|
||||
$scope.page.menu.currentNode = syncArgs.node;
|
||||
});
|
||||
}
|
||||
else if (initialLoad === true) {
|
||||
|
||||
//it's a child item, just sync the ui node to the parent
|
||||
navigationService.syncTree({ tree: "media", path: path.substring(0, path.lastIndexOf(",")).split(","), forceReload: initialLoad !== true });
|
||||
|
||||
//if this is a child of a list view and it's the initial load of the editor, we need to get the tree node
|
||||
// from the server so that we can load in the actions menu.
|
||||
umbRequestHelper.resourcePromise(
|
||||
$http.get(content.treeNodeUrl),
|
||||
'Failed to retrieve data for child node ' + content.id).then(function (node) {
|
||||
$scope.page.menu.currentNode = node;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (create) {
|
||||
|
||||
$scope.page.loading = true;
|
||||
|
||||
mediaResource.getScaffold(nodeId, $routeParams.doctype)
|
||||
.then(function (data) {
|
||||
$scope.content = data;
|
||||
|
||||
editorState.set($scope.content);
|
||||
|
||||
// We don't get the info tab from the server from version 7.8 so we need to manually add it
|
||||
//contentEditingHelper.addInfoTab($scope.content.tabs);
|
||||
|
||||
init($scope.content);
|
||||
|
||||
$scope.page.loading = false;
|
||||
|
||||
});
|
||||
}
|
||||
else {
|
||||
$scope.page.loading = true;
|
||||
loadMedia()
|
||||
.then(function(){
|
||||
$scope.page.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
function init(content) {
|
||||
|
||||
// prototype content and info apps
|
||||
var contentApp = {
|
||||
"name": "Content",
|
||||
"alias": "content",
|
||||
"icon": "icon-document",
|
||||
"view": "views/media/apps/content/content.html"
|
||||
};
|
||||
|
||||
var infoApp = {
|
||||
"name": "Info",
|
||||
"alias": "info",
|
||||
"icon": "icon-info",
|
||||
"view": "views/media/apps/info/info.html"
|
||||
};
|
||||
|
||||
var listview = {
|
||||
"name": "Child items",
|
||||
"alias": "childItems",
|
||||
"icon": "icon-list",
|
||||
"view": "views/media/apps/listview/listview.html"
|
||||
};
|
||||
|
||||
$scope.content.apps = [];
|
||||
|
||||
if($scope.content.contentTypeAlias === "Folder") {
|
||||
// add list view app
|
||||
$scope.content.apps.push(listview);
|
||||
|
||||
// remove the list view tab
|
||||
angular.forEach($scope.content.tabs, function(tab, index){
|
||||
if(tab.alias === "Contents") {
|
||||
tab.hide = true;
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
$scope.content.apps.push(contentApp);
|
||||
}
|
||||
|
||||
$scope.content.apps.push(infoApp);
|
||||
|
||||
// set first app to active
|
||||
$scope.content.apps[0].active = true;
|
||||
|
||||
// setup infinite mode
|
||||
if(infiniteMode) {
|
||||
$scope.page.submitButtonLabel = "Save and Close";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$scope.save = function () {
|
||||
|
||||
if (!$scope.busy && formHelper.submitForm({ scope: $scope })) {
|
||||
|
||||
$scope.busy = true;
|
||||
$scope.page.saveButtonState = "busy";
|
||||
|
||||
mediaResource.save($scope.content, create, fileManager.getFiles())
|
||||
.then(function(data) {
|
||||
|
||||
formHelper.resetForm({ scope: $scope });
|
||||
|
||||
contentEditingHelper.handleSuccessfulSave({
|
||||
scope: $scope,
|
||||
savedContent: data,
|
||||
redirectOnSuccess: !infiniteMode,
|
||||
rebindCallback: contentEditingHelper.reBindChangedProperties($scope.content, data)
|
||||
});
|
||||
|
||||
editorState.set($scope.content);
|
||||
$scope.busy = false;
|
||||
|
||||
// when don't want to sync the tree when the editor is open in infinite mode
|
||||
if(!infiniteMode) {
|
||||
syncTreeNode($scope.content, data.path);
|
||||
}
|
||||
|
||||
init($scope.content);
|
||||
|
||||
$scope.page.saveButtonState = "success";
|
||||
|
||||
// close the editor if it's infinite mode
|
||||
if(infiniteMode && $scope.model.submit) {
|
||||
$scope.model.mediaNode = $scope.content;
|
||||
$scope.model.submit($scope.model);
|
||||
}
|
||||
|
||||
}, function(err) {
|
||||
|
||||
contentEditingHelper.handleSaveError({
|
||||
err: err,
|
||||
redirectOnError: !infiniteMode,
|
||||
rebindCallback: contentEditingHelper.reBindChangedProperties($scope.content, err.data)
|
||||
});
|
||||
|
||||
editorState.set($scope.content);
|
||||
$scope.busy = false;
|
||||
$scope.page.saveButtonState = "error";
|
||||
|
||||
});
|
||||
}else{
|
||||
$scope.busy = false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
function loadMedia() {
|
||||
|
||||
return mediaResource.getById(nodeId)
|
||||
.then(function (data) {
|
||||
|
||||
$scope.content = data;
|
||||
|
||||
if (data.isChildOfListView && data.trashed === false) {
|
||||
$scope.page.listViewPath = ($routeParams.page)
|
||||
? "/media/media/edit/" + data.parentId + "?page=" + $routeParams.page
|
||||
: "/media/media/edit/" + data.parentId;
|
||||
}
|
||||
|
||||
editorState.set($scope.content);
|
||||
|
||||
//in one particular special case, after we've created a new item we redirect back to the edit
|
||||
// route but there might be server validation errors in the collection which we need to display
|
||||
// after the redirect, so we will bind all subscriptions which will show the server validation errors
|
||||
// if there are any and then clear them so the collection no longer persists them.
|
||||
serverValidationManager.executeAndClearAllSubscriptions();
|
||||
|
||||
if(!infiniteMode) {
|
||||
syncTreeNode($scope.content, data.path, true);
|
||||
}
|
||||
|
||||
if ($scope.content.parentId && $scope.content.parentId != -1) {
|
||||
//We fetch all ancestors of the node to generate the footer breadcrump navigation
|
||||
entityResource.getAncestors(nodeId, "media")
|
||||
.then(function (anc) {
|
||||
$scope.ancestors = anc;
|
||||
});
|
||||
}
|
||||
|
||||
// We don't get the info tab from the server from version 7.8 so we need to manually add it
|
||||
//contentEditingHelper.addInfoTab($scope.content.tabs);
|
||||
|
||||
init($scope.content);
|
||||
|
||||
$scope.page.loading = false;
|
||||
|
||||
$q.resolve($scope.content);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
$scope.close = function() {
|
||||
if($scope.model.close) {
|
||||
$scope.model.close($scope.model);
|
||||
}
|
||||
};
|
||||
|
||||
evts.push(eventsService.on("editors.mediaType.saved", function(name, args) {
|
||||
// if this media item uses the updated media type we need to reload the media item
|
||||
if(args && args.mediaType && args.mediaType.key === $scope.content.contentType.key) {
|
||||
loadMedia();
|
||||
}
|
||||
}));
|
||||
|
||||
//ensure to unregister from all events!
|
||||
$scope.$on('$destroy', function () {
|
||||
for (var e in evts) {
|
||||
eventsService.unsubscribe(evts[e]);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.Media.EditController", mediaEditController);
|
||||
/**
|
||||
* @ngdoc controller
|
||||
* @name Umbraco.Editors.Media.EditController
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* The controller for the media editor
|
||||
*/
|
||||
function mediaEditController($scope, $routeParams, $q, appState, mediaResource, entityResource, navigationService, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, fileManager, treeService, formHelper, umbModelMapper, editorState, umbRequestHelper, $http, eventsService) {
|
||||
|
||||
var evts = [];
|
||||
var nodeId = null;
|
||||
var create = false;
|
||||
var infiniteMode = $scope.model && $scope.model.infiniteMode;
|
||||
|
||||
// when opening the editor through infinite editing get the
|
||||
// node id from the model instead of the route param
|
||||
if(infiniteMode && $scope.model.id) {
|
||||
nodeId = $scope.model.id;
|
||||
} else {
|
||||
nodeId = $routeParams.id;
|
||||
}
|
||||
|
||||
// when opening the editor through infinite editing get the
|
||||
// create option from the model instead of the route param
|
||||
if(infiniteMode) {
|
||||
create = $scope.model.create;
|
||||
} else {
|
||||
create = $routeParams.create;
|
||||
}
|
||||
|
||||
//setup scope vars
|
||||
$scope.currentSection = appState.getSectionState("currentSection");
|
||||
$scope.currentNode = null; //the editors affiliated node
|
||||
|
||||
$scope.page = {};
|
||||
$scope.page.loading = false;
|
||||
$scope.page.menu = {};
|
||||
$scope.page.menu.currentSection = appState.getSectionState("currentSection");
|
||||
$scope.page.menu.currentNode = null; //the editors affiliated node
|
||||
$scope.page.listViewPath = null;
|
||||
$scope.page.saveButtonState = "init";
|
||||
$scope.page.submitButtonLabel = "Save";
|
||||
|
||||
/** Syncs the content item to it's tree node - this occurs on first load and after saving */
|
||||
function syncTreeNode(content, path, initialLoad) {
|
||||
|
||||
if (!$scope.content.isChildOfListView) {
|
||||
navigationService.syncTree({ tree: "media", path: path.split(","), forceReload: initialLoad !== true }).then(function (syncArgs) {
|
||||
$scope.page.menu.currentNode = syncArgs.node;
|
||||
});
|
||||
}
|
||||
else if (initialLoad === true) {
|
||||
|
||||
//it's a child item, just sync the ui node to the parent
|
||||
navigationService.syncTree({ tree: "media", path: path.substring(0, path.lastIndexOf(",")).split(","), forceReload: initialLoad !== true });
|
||||
|
||||
//if this is a child of a list view and it's the initial load of the editor, we need to get the tree node
|
||||
// from the server so that we can load in the actions menu.
|
||||
umbRequestHelper.resourcePromise(
|
||||
$http.get(content.treeNodeUrl),
|
||||
'Failed to retrieve data for child node ' + content.id).then(function (node) {
|
||||
$scope.page.menu.currentNode = node;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (create) {
|
||||
|
||||
$scope.page.loading = true;
|
||||
|
||||
mediaResource.getScaffold(nodeId, $routeParams.doctype)
|
||||
.then(function (data) {
|
||||
$scope.content = data;
|
||||
|
||||
editorState.set($scope.content);
|
||||
|
||||
// We don't get the info tab from the server from version 7.8 so we need to manually add it
|
||||
//contentEditingHelper.addInfoTab($scope.content.tabs);
|
||||
|
||||
init($scope.content);
|
||||
|
||||
$scope.page.loading = false;
|
||||
|
||||
});
|
||||
}
|
||||
else {
|
||||
$scope.page.loading = true;
|
||||
loadMedia()
|
||||
.then(function(){
|
||||
$scope.page.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
function init(content) {
|
||||
|
||||
// prototype content and info apps
|
||||
var contentApp = {
|
||||
"name": "Content",
|
||||
"alias": "content",
|
||||
"icon": "icon-document",
|
||||
"view": "views/media/apps/content/content.html"
|
||||
};
|
||||
|
||||
var infoApp = {
|
||||
"name": "Info",
|
||||
"alias": "info",
|
||||
"icon": "icon-info",
|
||||
"view": "views/media/apps/info/info.html"
|
||||
};
|
||||
|
||||
var listview = {
|
||||
"name": "Child items",
|
||||
"alias": "childItems",
|
||||
"icon": "icon-list",
|
||||
"view": "views/media/apps/listview/listview.html"
|
||||
};
|
||||
|
||||
$scope.content.apps = [];
|
||||
|
||||
if($scope.content.contentTypeAlias === "Folder") {
|
||||
// add list view app
|
||||
$scope.content.apps.push(listview);
|
||||
|
||||
// remove the list view tab
|
||||
angular.forEach($scope.content.tabs, function(tab, index){
|
||||
if(tab.alias === "Contents") {
|
||||
tab.hide = true;
|
||||
}
|
||||
});
|
||||
|
||||
} else {
|
||||
$scope.content.apps.push(contentApp);
|
||||
}
|
||||
|
||||
$scope.content.apps.push(infoApp);
|
||||
|
||||
// set first app to active
|
||||
$scope.content.apps[0].active = true;
|
||||
|
||||
// setup infinite mode
|
||||
if(infiniteMode) {
|
||||
$scope.page.submitButtonLabel = "Save and Close";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
$scope.save = function () {
|
||||
|
||||
if (!$scope.busy && formHelper.submitForm({ scope: $scope })) {
|
||||
|
||||
$scope.busy = true;
|
||||
$scope.page.saveButtonState = "busy";
|
||||
|
||||
mediaResource.save($scope.content, create, fileManager.getFiles())
|
||||
.then(function(data) {
|
||||
|
||||
formHelper.resetForm({ scope: $scope });
|
||||
|
||||
contentEditingHelper.handleSuccessfulSave({
|
||||
scope: $scope,
|
||||
savedContent: data,
|
||||
redirectOnSuccess: !infiniteMode,
|
||||
rebindCallback: contentEditingHelper.reBindChangedProperties($scope.content, data)
|
||||
});
|
||||
|
||||
editorState.set($scope.content);
|
||||
$scope.busy = false;
|
||||
|
||||
// when don't want to sync the tree when the editor is open in infinite mode
|
||||
if(!infiniteMode) {
|
||||
syncTreeNode($scope.content, data.path);
|
||||
}
|
||||
|
||||
init($scope.content);
|
||||
|
||||
$scope.page.saveButtonState = "success";
|
||||
|
||||
// close the editor if it's infinite mode
|
||||
if(infiniteMode && $scope.model.submit) {
|
||||
$scope.model.mediaNode = $scope.content;
|
||||
$scope.model.submit($scope.model);
|
||||
}
|
||||
|
||||
}, function(err) {
|
||||
|
||||
contentEditingHelper.handleSaveError({
|
||||
err: err,
|
||||
redirectOnError: !infiniteMode,
|
||||
rebindCallback: contentEditingHelper.reBindChangedProperties($scope.content, err.data)
|
||||
});
|
||||
|
||||
editorState.set($scope.content);
|
||||
$scope.busy = false;
|
||||
$scope.page.saveButtonState = "error";
|
||||
|
||||
});
|
||||
}else{
|
||||
$scope.busy = false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
function loadMedia() {
|
||||
|
||||
return mediaResource.getById(nodeId)
|
||||
.then(function (data) {
|
||||
|
||||
$scope.content = data;
|
||||
|
||||
if (data.isChildOfListView && data.trashed === false) {
|
||||
$scope.page.listViewPath = ($routeParams.page)
|
||||
? "/media/media/edit/" + data.parentId + "?page=" + $routeParams.page
|
||||
: "/media/media/edit/" + data.parentId;
|
||||
}
|
||||
|
||||
editorState.set($scope.content);
|
||||
|
||||
//in one particular special case, after we've created a new item we redirect back to the edit
|
||||
// route but there might be server validation errors in the collection which we need to display
|
||||
// after the redirect, so we will bind all subscriptions which will show the server validation errors
|
||||
// if there are any and then clear them so the collection no longer persists them.
|
||||
serverValidationManager.executeAndClearAllSubscriptions();
|
||||
|
||||
if(!infiniteMode) {
|
||||
syncTreeNode($scope.content, data.path, true);
|
||||
}
|
||||
|
||||
if ($scope.content.parentId && $scope.content.parentId != -1) {
|
||||
//We fetch all ancestors of the node to generate the footer breadcrump navigation
|
||||
entityResource.getAncestors(nodeId, "media")
|
||||
.then(function (anc) {
|
||||
$scope.ancestors = anc;
|
||||
});
|
||||
}
|
||||
|
||||
// We don't get the info tab from the server from version 7.8 so we need to manually add it
|
||||
//contentEditingHelper.addInfoTab($scope.content.tabs);
|
||||
|
||||
init($scope.content);
|
||||
|
||||
$scope.page.loading = false;
|
||||
|
||||
$q.resolve($scope.content);
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
$scope.close = function() {
|
||||
if($scope.model.close) {
|
||||
$scope.model.close($scope.model);
|
||||
}
|
||||
};
|
||||
|
||||
evts.push(eventsService.on("editors.mediaType.saved", function(name, args) {
|
||||
// if this media item uses the updated media type we need to reload the media item
|
||||
if(args && args.mediaType && args.mediaType.key === $scope.content.contentType.key) {
|
||||
loadMedia();
|
||||
}
|
||||
}));
|
||||
|
||||
//ensure to unregister from all events!
|
||||
$scope.$on('$destroy', function () {
|
||||
for (var e in evts) {
|
||||
eventsService.unsubscribe(evts[e]);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.Media.EditController", mediaEditController);
|
||||
|
||||
@@ -1,419 +1,419 @@
|
||||
/**
|
||||
* @ngdoc controller
|
||||
* @name Umbraco.Editors.MediaType.EditController
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* The controller for the media type editor
|
||||
*/
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function MediaTypesEditController($scope, $routeParams, mediaTypeResource, dataTypeResource, editorState, contentEditingHelper, formHelper, navigationService, iconHelper, contentTypeHelper, notificationsService, $filter, $q, localizationService, overlayHelper, eventsService) {
|
||||
|
||||
var vm = this;
|
||||
var evts = [];
|
||||
var mediaTypeId = $routeParams.id;
|
||||
var create = $routeParams.create;
|
||||
var infiniteMode = $scope.model && $scope.model.infiniteMode;
|
||||
|
||||
vm.save = save;
|
||||
vm.close = close;
|
||||
|
||||
vm.currentNode = null;
|
||||
vm.contentType = {};
|
||||
vm.page = {};
|
||||
vm.page.loading = false;
|
||||
vm.page.saveButtonState = "init";
|
||||
vm.labels = {};
|
||||
vm.saveButtonKey = "buttons_save";
|
||||
vm.generateModelsKey = "buttons_saveAndGenerateModels";
|
||||
|
||||
onInit();
|
||||
|
||||
function onInit() {
|
||||
// get init values from model when in infinite mode
|
||||
if(infiniteMode) {
|
||||
mediaTypeId = $scope.model.id;
|
||||
create = $scope.model.create;
|
||||
vm.saveButtonKey = "buttons_saveAndClose";
|
||||
vm.generateModelsKey = "buttons_generateModelsAndClose";
|
||||
}
|
||||
}
|
||||
|
||||
var labelKeys = [
|
||||
"general_design",
|
||||
"general_listView",
|
||||
"general_rights",
|
||||
|
||||
"main_sections",
|
||||
"shortcuts_navigateSections",
|
||||
"shortcuts_addTab",
|
||||
"shortcuts_addProperty",
|
||||
"shortcuts_addEditor",
|
||||
"shortcuts_editDataType",
|
||||
"shortcuts_toggleListView",
|
||||
"shortcuts_toggleAllowAsRoot",
|
||||
"shortcuts_addChildNode"
|
||||
];
|
||||
|
||||
localizationService.localizeMany(labelKeys).then(function (values) {
|
||||
// navigation
|
||||
vm.labels.design = values[0];
|
||||
vm.labels.listview = values[1];
|
||||
vm.labels.permissions = values[2];
|
||||
// keyboard shortcuts
|
||||
vm.labels.sections = values[3];
|
||||
vm.labels.navigateSections = values[4];
|
||||
vm.labels.addTab = values[5];
|
||||
vm.labels.addProperty = values[6];
|
||||
vm.labels.addEditor = values[7];
|
||||
vm.labels.editDataType = values[8];
|
||||
vm.labels.toggleListView = values[9];
|
||||
vm.labels.allowAsRoot = values[10];
|
||||
vm.labels.addChildNode = values[11];
|
||||
|
||||
vm.page.navigation = [
|
||||
{
|
||||
"name": vm.labels.design,
|
||||
"icon": "icon-document-dashed-line",
|
||||
"view": "views/mediatypes/views/design/design.html",
|
||||
"active": true
|
||||
},
|
||||
{
|
||||
"name": vm.labels.listview,
|
||||
"icon": "icon-list",
|
||||
"view": "views/mediatypes/views/listview/listview.html"
|
||||
},
|
||||
{
|
||||
"name": vm.labels.permissions,
|
||||
"icon": "icon-keychain",
|
||||
"view": "views/mediatypes/views/permissions/permissions.html"
|
||||
}
|
||||
];
|
||||
|
||||
vm.page.keyboardShortcutsOverview = [
|
||||
{
|
||||
"name": vm.labels.sections,
|
||||
"shortcuts": [
|
||||
{
|
||||
"description": vm.labels.navigateSections,
|
||||
"keys": [{ "key": "1" }, { "key": "3" }],
|
||||
"keyRange": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": vm.labels.design,
|
||||
"shortcuts": [
|
||||
{
|
||||
"description": vm.labels.addTab,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "t" }]
|
||||
},
|
||||
{
|
||||
"description": vm.labels.addProperty,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "p" }]
|
||||
},
|
||||
{
|
||||
"description": vm.labels.addEditor,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "e" }]
|
||||
},
|
||||
{
|
||||
"description": vm.labels.editDataType,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "d" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": vm.labels.listview,
|
||||
"shortcuts": [
|
||||
{
|
||||
"description": vm.labels.toggleListView,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "l" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": vm.labels.permissions,
|
||||
"shortcuts": [
|
||||
{
|
||||
"description": vm.labels.allowAsRoot,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "r" }]
|
||||
},
|
||||
{
|
||||
"description": vm.labels.addChildNode,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "c" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
contentTypeHelper.checkModelsBuilderStatus().then(function (result) {
|
||||
vm.page.modelsBuilder = result;
|
||||
if (result) {
|
||||
//Models builder mode:
|
||||
vm.page.defaultButton = {
|
||||
hotKey: "ctrl+s",
|
||||
hotKeyWhenHidden: true,
|
||||
labelKey: vm.saveButtonKey,
|
||||
letter: "S",
|
||||
type: "submit",
|
||||
handler: function () { vm.save(); }
|
||||
};
|
||||
vm.page.subButtons = [{
|
||||
hotKey: "ctrl+g",
|
||||
hotKeyWhenHidden: true,
|
||||
labelKey: vm.generateModelsKey,
|
||||
letter: "G",
|
||||
handler: function () {
|
||||
|
||||
vm.page.saveButtonState = "busy";
|
||||
|
||||
vm.save().then(function (result) {
|
||||
|
||||
vm.page.saveButtonState = "busy";
|
||||
|
||||
localizationService.localize("modelsBuilder_buildingModels").then(function (headerValue) {
|
||||
localizationService.localize("modelsBuilder_waitingMessage").then(function(msgValue) {
|
||||
notificationsService.info(headerValue, msgValue);
|
||||
});
|
||||
});
|
||||
|
||||
contentTypeHelper.generateModels().then(function (result) {
|
||||
|
||||
if (result.success) {
|
||||
|
||||
//re-check model status
|
||||
contentTypeHelper.checkModelsBuilderStatus().then(function (statusResult) {
|
||||
vm.page.modelsBuilder = statusResult;
|
||||
});
|
||||
|
||||
//clear and add success
|
||||
vm.page.saveButtonState = "init";
|
||||
localizationService.localize("modelsBuilder_modelsGenerated").then(function(value) {
|
||||
notificationsService.success(value);
|
||||
});
|
||||
|
||||
} else {
|
||||
vm.page.saveButtonState = "error";
|
||||
localizationService.localize("modelsBuilder_modelsExceptionInUlog").then(function(value) {
|
||||
notificationsService.error(value);
|
||||
});
|
||||
}
|
||||
|
||||
}, function () {
|
||||
vm.page.saveButtonState = "error";
|
||||
localizationService.localize("modelsBuilder_modelsGeneratedError").then(function(value) {
|
||||
notificationsService.error(value);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
}];
|
||||
}
|
||||
});
|
||||
|
||||
if (create) {
|
||||
vm.page.loading = true;
|
||||
|
||||
//we are creating so get an empty data type item
|
||||
mediaTypeResource.getScaffold(mediaTypeId)
|
||||
.then(function(dt) {
|
||||
init(dt);
|
||||
|
||||
vm.page.loading = false;
|
||||
});
|
||||
}
|
||||
else {
|
||||
loadMediaType();
|
||||
}
|
||||
|
||||
function loadMediaType() {
|
||||
vm.page.loading = true;
|
||||
|
||||
mediaTypeResource.getById(mediaTypeId).then(function(dt) {
|
||||
init(dt);
|
||||
|
||||
if(!infiniteMode) {
|
||||
syncTreeNode(vm.contentType, dt.path, true);
|
||||
}
|
||||
|
||||
vm.page.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
/* ---------- SAVE ---------- */
|
||||
|
||||
function save() {
|
||||
|
||||
// only save if there is no overlays open
|
||||
if(overlayHelper.getNumberOfOverlays() === 0) {
|
||||
|
||||
var deferred = $q.defer();
|
||||
|
||||
vm.page.saveButtonState = "busy";
|
||||
|
||||
// reformat allowed content types to array if id's
|
||||
vm.contentType.allowedContentTypes = contentTypeHelper.createIdArray(vm.contentType.allowedContentTypes);
|
||||
|
||||
contentEditingHelper.contentEditorPerformSave({
|
||||
saveMethod: mediaTypeResource.save,
|
||||
scope: $scope,
|
||||
content: vm.contentType,
|
||||
//We do not redirect on failure for doc types - this is because it is not possible to actually save the doc
|
||||
// type when server side validation fails - as opposed to content where we are capable of saving the content
|
||||
// item if server side validation fails
|
||||
redirectOnFailure: false,
|
||||
// we need to rebind... the IDs that have been created!
|
||||
rebindCallback: function (origContentType, savedContentType) {
|
||||
vm.contentType.id = savedContentType.id;
|
||||
vm.contentType.groups.forEach(function (group) {
|
||||
if (!group.name) return;
|
||||
|
||||
var k = 0;
|
||||
while (k < savedContentType.groups.length && savedContentType.groups[k].name != group.name)
|
||||
k++;
|
||||
if (k == savedContentType.groups.length) {
|
||||
group.id = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
var savedGroup = savedContentType.groups[k];
|
||||
if (!group.id) group.id = savedGroup.id;
|
||||
|
||||
group.properties.forEach(function (property) {
|
||||
if (property.id || !property.alias) return;
|
||||
|
||||
k = 0;
|
||||
while (k < savedGroup.properties.length && savedGroup.properties[k].alias != property.alias)
|
||||
k++;
|
||||
if (k == savedGroup.properties.length) {
|
||||
property.id = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
var savedProperty = savedGroup.properties[k];
|
||||
property.id = savedProperty.id;
|
||||
});
|
||||
});
|
||||
}
|
||||
}).then(function (data) {
|
||||
//success
|
||||
|
||||
if(!infiniteMode) {
|
||||
syncTreeNode(vm.contentType, data.path);
|
||||
}
|
||||
|
||||
// emit event
|
||||
var args = { mediaType: vm.contentType };
|
||||
eventsService.emit("editors.mediaType.saved", args);
|
||||
|
||||
vm.page.saveButtonState = "success";
|
||||
|
||||
if(infiniteMode && $scope.model.submit) {
|
||||
$scope.model.submit();
|
||||
}
|
||||
|
||||
deferred.resolve(data);
|
||||
|
||||
}, function (err) {
|
||||
//error
|
||||
if (err) {
|
||||
editorState.set($scope.content);
|
||||
}
|
||||
else {
|
||||
localizationService.localize("speechBubbles_validationFailedHeader").then(function (headerValue) {
|
||||
localizationService.localize("speechBubbles_validationFailedMessage").then(function (msgValue) {
|
||||
notificationsService.error(headerValue, msgValue);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
vm.page.saveButtonState = "error";
|
||||
|
||||
deferred.reject(err);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
}
|
||||
|
||||
function init(contentType) {
|
||||
|
||||
// set all tab to inactive
|
||||
if (contentType.groups.length !== 0) {
|
||||
angular.forEach(contentType.groups, function (group) {
|
||||
|
||||
angular.forEach(group.properties, function (property) {
|
||||
// get data type details for each property
|
||||
getDataTypeDetails(property);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
// convert icons for content type
|
||||
convertLegacyIcons(contentType);
|
||||
|
||||
//set a shared state
|
||||
editorState.set(contentType);
|
||||
|
||||
vm.contentType = contentType;
|
||||
}
|
||||
|
||||
function convertLegacyIcons(contentType) {
|
||||
// make array to store contentType icon
|
||||
var contentTypeArray = [];
|
||||
|
||||
// push icon to array
|
||||
contentTypeArray.push({ "icon": contentType.icon });
|
||||
|
||||
// run through icon method
|
||||
iconHelper.formatContentTypeIcons(contentTypeArray);
|
||||
|
||||
// set icon back on contentType
|
||||
contentType.icon = contentTypeArray[0].icon;
|
||||
}
|
||||
|
||||
function getDataTypeDetails(property) {
|
||||
if (property.propertyState !== "init") {
|
||||
|
||||
dataTypeResource.getById(property.dataTypeId)
|
||||
.then(function(dataType) {
|
||||
property.dataTypeIcon = dataType.icon;
|
||||
property.dataTypeName = dataType.name;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Syncs the content type to it's tree node - this occurs on first load and after saving */
|
||||
function syncTreeNode(dt, path, initialLoad) {
|
||||
navigationService.syncTree({ tree: "mediatypes", path: path.split(","), forceReload: initialLoad !== true }).then(function(syncArgs) {
|
||||
vm.currentNode = syncArgs.node;
|
||||
});
|
||||
}
|
||||
|
||||
function close() {
|
||||
if(infiniteMode && $scope.model.close) {
|
||||
$scope.model.close();
|
||||
}
|
||||
}
|
||||
|
||||
evts.push(eventsService.on("app.refreshEditor", function(name, error) {
|
||||
loadMediaType();
|
||||
}));
|
||||
|
||||
//ensure to unregister from all events!
|
||||
$scope.$on('$destroy', function () {
|
||||
for (var e in evts) {
|
||||
eventsService.unsubscribe(evts[e]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.MediaTypes.EditController", MediaTypesEditController);
|
||||
})();
|
||||
/**
|
||||
* @ngdoc controller
|
||||
* @name Umbraco.Editors.MediaType.EditController
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* The controller for the media type editor
|
||||
*/
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function MediaTypesEditController($scope, $routeParams, mediaTypeResource, dataTypeResource, editorState, contentEditingHelper, formHelper, navigationService, iconHelper, contentTypeHelper, notificationsService, $filter, $q, localizationService, overlayHelper, eventsService) {
|
||||
|
||||
var vm = this;
|
||||
var evts = [];
|
||||
var mediaTypeId = $routeParams.id;
|
||||
var create = $routeParams.create;
|
||||
var infiniteMode = $scope.model && $scope.model.infiniteMode;
|
||||
|
||||
vm.save = save;
|
||||
vm.close = close;
|
||||
|
||||
vm.currentNode = null;
|
||||
vm.contentType = {};
|
||||
vm.page = {};
|
||||
vm.page.loading = false;
|
||||
vm.page.saveButtonState = "init";
|
||||
vm.labels = {};
|
||||
vm.saveButtonKey = "buttons_save";
|
||||
vm.generateModelsKey = "buttons_saveAndGenerateModels";
|
||||
|
||||
onInit();
|
||||
|
||||
function onInit() {
|
||||
// get init values from model when in infinite mode
|
||||
if(infiniteMode) {
|
||||
mediaTypeId = $scope.model.id;
|
||||
create = $scope.model.create;
|
||||
vm.saveButtonKey = "buttons_saveAndClose";
|
||||
vm.generateModelsKey = "buttons_generateModelsAndClose";
|
||||
}
|
||||
}
|
||||
|
||||
var labelKeys = [
|
||||
"general_design",
|
||||
"general_listView",
|
||||
"general_rights",
|
||||
|
||||
"main_sections",
|
||||
"shortcuts_navigateSections",
|
||||
"shortcuts_addTab",
|
||||
"shortcuts_addProperty",
|
||||
"shortcuts_addEditor",
|
||||
"shortcuts_editDataType",
|
||||
"shortcuts_toggleListView",
|
||||
"shortcuts_toggleAllowAsRoot",
|
||||
"shortcuts_addChildNode"
|
||||
];
|
||||
|
||||
localizationService.localizeMany(labelKeys).then(function (values) {
|
||||
// navigation
|
||||
vm.labels.design = values[0];
|
||||
vm.labels.listview = values[1];
|
||||
vm.labels.permissions = values[2];
|
||||
// keyboard shortcuts
|
||||
vm.labels.sections = values[3];
|
||||
vm.labels.navigateSections = values[4];
|
||||
vm.labels.addTab = values[5];
|
||||
vm.labels.addProperty = values[6];
|
||||
vm.labels.addEditor = values[7];
|
||||
vm.labels.editDataType = values[8];
|
||||
vm.labels.toggleListView = values[9];
|
||||
vm.labels.allowAsRoot = values[10];
|
||||
vm.labels.addChildNode = values[11];
|
||||
|
||||
vm.page.navigation = [
|
||||
{
|
||||
"name": vm.labels.design,
|
||||
"icon": "icon-document-dashed-line",
|
||||
"view": "views/mediatypes/views/design/design.html",
|
||||
"active": true
|
||||
},
|
||||
{
|
||||
"name": vm.labels.listview,
|
||||
"icon": "icon-list",
|
||||
"view": "views/mediatypes/views/listview/listview.html"
|
||||
},
|
||||
{
|
||||
"name": vm.labels.permissions,
|
||||
"icon": "icon-keychain",
|
||||
"view": "views/mediatypes/views/permissions/permissions.html"
|
||||
}
|
||||
];
|
||||
|
||||
vm.page.keyboardShortcutsOverview = [
|
||||
{
|
||||
"name": vm.labels.sections,
|
||||
"shortcuts": [
|
||||
{
|
||||
"description": vm.labels.navigateSections,
|
||||
"keys": [{ "key": "1" }, { "key": "3" }],
|
||||
"keyRange": true
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": vm.labels.design,
|
||||
"shortcuts": [
|
||||
{
|
||||
"description": vm.labels.addTab,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "t" }]
|
||||
},
|
||||
{
|
||||
"description": vm.labels.addProperty,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "p" }]
|
||||
},
|
||||
{
|
||||
"description": vm.labels.addEditor,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "e" }]
|
||||
},
|
||||
{
|
||||
"description": vm.labels.editDataType,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "d" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": vm.labels.listview,
|
||||
"shortcuts": [
|
||||
{
|
||||
"description": vm.labels.toggleListView,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "l" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": vm.labels.permissions,
|
||||
"shortcuts": [
|
||||
{
|
||||
"description": vm.labels.allowAsRoot,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "r" }]
|
||||
},
|
||||
{
|
||||
"description": vm.labels.addChildNode,
|
||||
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "c" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
});
|
||||
|
||||
contentTypeHelper.checkModelsBuilderStatus().then(function (result) {
|
||||
vm.page.modelsBuilder = result;
|
||||
if (result) {
|
||||
//Models builder mode:
|
||||
vm.page.defaultButton = {
|
||||
hotKey: "ctrl+s",
|
||||
hotKeyWhenHidden: true,
|
||||
labelKey: vm.saveButtonKey,
|
||||
letter: "S",
|
||||
type: "submit",
|
||||
handler: function () { vm.save(); }
|
||||
};
|
||||
vm.page.subButtons = [{
|
||||
hotKey: "ctrl+g",
|
||||
hotKeyWhenHidden: true,
|
||||
labelKey: vm.generateModelsKey,
|
||||
letter: "G",
|
||||
handler: function () {
|
||||
|
||||
vm.page.saveButtonState = "busy";
|
||||
|
||||
vm.save().then(function (result) {
|
||||
|
||||
vm.page.saveButtonState = "busy";
|
||||
|
||||
localizationService.localize("modelsBuilder_buildingModels").then(function (headerValue) {
|
||||
localizationService.localize("modelsBuilder_waitingMessage").then(function(msgValue) {
|
||||
notificationsService.info(headerValue, msgValue);
|
||||
});
|
||||
});
|
||||
|
||||
contentTypeHelper.generateModels().then(function (result) {
|
||||
|
||||
if (result.success) {
|
||||
|
||||
//re-check model status
|
||||
contentTypeHelper.checkModelsBuilderStatus().then(function (statusResult) {
|
||||
vm.page.modelsBuilder = statusResult;
|
||||
});
|
||||
|
||||
//clear and add success
|
||||
vm.page.saveButtonState = "init";
|
||||
localizationService.localize("modelsBuilder_modelsGenerated").then(function(value) {
|
||||
notificationsService.success(value);
|
||||
});
|
||||
|
||||
} else {
|
||||
vm.page.saveButtonState = "error";
|
||||
localizationService.localize("modelsBuilder_modelsExceptionInUlog").then(function(value) {
|
||||
notificationsService.error(value);
|
||||
});
|
||||
}
|
||||
|
||||
}, function () {
|
||||
vm.page.saveButtonState = "error";
|
||||
localizationService.localize("modelsBuilder_modelsGeneratedError").then(function(value) {
|
||||
notificationsService.error(value);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
}];
|
||||
}
|
||||
});
|
||||
|
||||
if (create) {
|
||||
vm.page.loading = true;
|
||||
|
||||
//we are creating so get an empty data type item
|
||||
mediaTypeResource.getScaffold(mediaTypeId)
|
||||
.then(function(dt) {
|
||||
init(dt);
|
||||
|
||||
vm.page.loading = false;
|
||||
});
|
||||
}
|
||||
else {
|
||||
loadMediaType();
|
||||
}
|
||||
|
||||
function loadMediaType() {
|
||||
vm.page.loading = true;
|
||||
|
||||
mediaTypeResource.getById(mediaTypeId).then(function(dt) {
|
||||
init(dt);
|
||||
|
||||
if(!infiniteMode) {
|
||||
syncTreeNode(vm.contentType, dt.path, true);
|
||||
}
|
||||
|
||||
vm.page.loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
/* ---------- SAVE ---------- */
|
||||
|
||||
function save() {
|
||||
|
||||
// only save if there is no overlays open
|
||||
if(overlayHelper.getNumberOfOverlays() === 0) {
|
||||
|
||||
var deferred = $q.defer();
|
||||
|
||||
vm.page.saveButtonState = "busy";
|
||||
|
||||
// reformat allowed content types to array if id's
|
||||
vm.contentType.allowedContentTypes = contentTypeHelper.createIdArray(vm.contentType.allowedContentTypes);
|
||||
|
||||
contentEditingHelper.contentEditorPerformSave({
|
||||
saveMethod: mediaTypeResource.save,
|
||||
scope: $scope,
|
||||
content: vm.contentType,
|
||||
//We do not redirect on failure for doc types - this is because it is not possible to actually save the doc
|
||||
// type when server side validation fails - as opposed to content where we are capable of saving the content
|
||||
// item if server side validation fails
|
||||
redirectOnFailure: false,
|
||||
// we need to rebind... the IDs that have been created!
|
||||
rebindCallback: function (origContentType, savedContentType) {
|
||||
vm.contentType.id = savedContentType.id;
|
||||
vm.contentType.groups.forEach(function (group) {
|
||||
if (!group.name) return;
|
||||
|
||||
var k = 0;
|
||||
while (k < savedContentType.groups.length && savedContentType.groups[k].name != group.name)
|
||||
k++;
|
||||
if (k == savedContentType.groups.length) {
|
||||
group.id = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
var savedGroup = savedContentType.groups[k];
|
||||
if (!group.id) group.id = savedGroup.id;
|
||||
|
||||
group.properties.forEach(function (property) {
|
||||
if (property.id || !property.alias) return;
|
||||
|
||||
k = 0;
|
||||
while (k < savedGroup.properties.length && savedGroup.properties[k].alias != property.alias)
|
||||
k++;
|
||||
if (k == savedGroup.properties.length) {
|
||||
property.id = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
var savedProperty = savedGroup.properties[k];
|
||||
property.id = savedProperty.id;
|
||||
});
|
||||
});
|
||||
}
|
||||
}).then(function (data) {
|
||||
//success
|
||||
|
||||
if(!infiniteMode) {
|
||||
syncTreeNode(vm.contentType, data.path);
|
||||
}
|
||||
|
||||
// emit event
|
||||
var args = { mediaType: vm.contentType };
|
||||
eventsService.emit("editors.mediaType.saved", args);
|
||||
|
||||
vm.page.saveButtonState = "success";
|
||||
|
||||
if(infiniteMode && $scope.model.submit) {
|
||||
$scope.model.submit();
|
||||
}
|
||||
|
||||
deferred.resolve(data);
|
||||
|
||||
}, function (err) {
|
||||
//error
|
||||
if (err) {
|
||||
editorState.set($scope.content);
|
||||
}
|
||||
else {
|
||||
localizationService.localize("speechBubbles_validationFailedHeader").then(function (headerValue) {
|
||||
localizationService.localize("speechBubbles_validationFailedMessage").then(function (msgValue) {
|
||||
notificationsService.error(headerValue, msgValue);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
vm.page.saveButtonState = "error";
|
||||
|
||||
deferred.reject(err);
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
}
|
||||
|
||||
function init(contentType) {
|
||||
|
||||
// set all tab to inactive
|
||||
if (contentType.groups.length !== 0) {
|
||||
angular.forEach(contentType.groups, function (group) {
|
||||
|
||||
angular.forEach(group.properties, function (property) {
|
||||
// get data type details for each property
|
||||
getDataTypeDetails(property);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
// convert icons for content type
|
||||
convertLegacyIcons(contentType);
|
||||
|
||||
//set a shared state
|
||||
editorState.set(contentType);
|
||||
|
||||
vm.contentType = contentType;
|
||||
}
|
||||
|
||||
function convertLegacyIcons(contentType) {
|
||||
// make array to store contentType icon
|
||||
var contentTypeArray = [];
|
||||
|
||||
// push icon to array
|
||||
contentTypeArray.push({ "icon": contentType.icon });
|
||||
|
||||
// run through icon method
|
||||
iconHelper.formatContentTypeIcons(contentTypeArray);
|
||||
|
||||
// set icon back on contentType
|
||||
contentType.icon = contentTypeArray[0].icon;
|
||||
}
|
||||
|
||||
function getDataTypeDetails(property) {
|
||||
if (property.propertyState !== "init") {
|
||||
|
||||
dataTypeResource.getById(property.dataTypeId)
|
||||
.then(function(dataType) {
|
||||
property.dataTypeIcon = dataType.icon;
|
||||
property.dataTypeName = dataType.name;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Syncs the content type to it's tree node - this occurs on first load and after saving */
|
||||
function syncTreeNode(dt, path, initialLoad) {
|
||||
navigationService.syncTree({ tree: "mediatypes", path: path.split(","), forceReload: initialLoad !== true }).then(function(syncArgs) {
|
||||
vm.currentNode = syncArgs.node;
|
||||
});
|
||||
}
|
||||
|
||||
function close() {
|
||||
if(infiniteMode && $scope.model.close) {
|
||||
$scope.model.close();
|
||||
}
|
||||
}
|
||||
|
||||
evts.push(eventsService.on("app.refreshEditor", function(name, error) {
|
||||
loadMediaType();
|
||||
}));
|
||||
|
||||
//ensure to unregister from all events!
|
||||
$scope.$on('$destroy', function () {
|
||||
for (var e in evts) {
|
||||
eventsService.unsubscribe(evts[e]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.MediaTypes.EditController", MediaTypesEditController);
|
||||
})();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user