Merge pull request #4165 from umbraco/temp8-3417-macro-crud
Macro CRUD angularized
This commit is contained in:
@@ -125,6 +125,18 @@ namespace Umbraco.Core.Collections
|
||||
|
||||
}
|
||||
|
||||
public void ReplaceAll(IEnumerable<TValue> values)
|
||||
{
|
||||
if (values == null) throw new ArgumentNullException(nameof(values));
|
||||
|
||||
Clear();
|
||||
|
||||
foreach (var value in values)
|
||||
{
|
||||
Add(value);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Remove(TKey key)
|
||||
{
|
||||
if (!Indecies.ContainsKey(key)) return false;
|
||||
|
||||
@@ -20,14 +20,14 @@ function macroResource($q, $http, umbRequestHelper) {
|
||||
* @param {int} macroId The macro id to get parameters for
|
||||
*
|
||||
*/
|
||||
getMacroParameters: function (macroId) {
|
||||
getMacroParameters: function(macroId) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"macroApiBaseUrl",
|
||||
"GetMacroParameters",
|
||||
[{ macroId: macroId }])),
|
||||
'Failed to retrieve macro parameters for macro with id ' + macroId);
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"macroRenderingApiBaseUrl",
|
||||
"GetMacroParameters",
|
||||
[{ macroId: macroId }])),
|
||||
'Failed to retrieve macro parameters for macro with id ' + macroId);
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -43,13 +43,14 @@ function macroResource($q, $http, umbRequestHelper) {
|
||||
* @param {Array} macroParamDictionary A dictionary of macro parameters
|
||||
*
|
||||
*/
|
||||
getMacroResultAsHtmlForEditor: function (macroAlias, pageId, macroParamDictionary) {
|
||||
getMacroResultAsHtmlForEditor: function(macroAlias, pageId, macroParamDictionary) {
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"macroApiBaseUrl",
|
||||
"GetMacroResultAsHtmlForEditor"), {
|
||||
"macroRenderingApiBaseUrl",
|
||||
"GetMacroResultAsHtmlForEditor"),
|
||||
{
|
||||
macroAlias: macroAlias,
|
||||
pageId: pageId,
|
||||
macroParams: macroParamDictionary
|
||||
@@ -67,17 +68,55 @@ function macroResource($q, $http, umbRequestHelper) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"macroApiBaseUrl",
|
||||
"CreatePartialViewMacroWithFile"), {
|
||||
virtualPath: virtualPath,
|
||||
filename: filename
|
||||
}
|
||||
"macroRenderingApiBaseUrl",
|
||||
"CreatePartialViewMacroWithFile"),
|
||||
{
|
||||
virtualPath: virtualPath,
|
||||
filename: filename
|
||||
}
|
||||
),
|
||||
'Failed to create macro "' + filename + '"'
|
||||
);
|
||||
|
||||
},
|
||||
|
||||
createMacro: function(name) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"macroApiBaseUrl",
|
||||
"Create?name=" + name)
|
||||
),
|
||||
'Failed to create macro "' + name + '"'
|
||||
);
|
||||
},
|
||||
|
||||
getPartialViews: function() {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(umbRequestHelper.getApiUrl("macroApiBaseUrl", "GetPartialViews"),
|
||||
"Failed to get partial views")
|
||||
);
|
||||
},
|
||||
|
||||
getParameterEditors: function() {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(umbRequestHelper.getApiUrl("macroApiBaseUrl", "GetParameterEditors"),
|
||||
"Failed to get parameter editors")
|
||||
);
|
||||
},
|
||||
|
||||
getById: function(id) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(umbRequestHelper.getApiUrl("macroApiBaseUrl", "GetById", { "id": id }), "Failed to get macro")
|
||||
);
|
||||
},
|
||||
|
||||
saveMacro: function(macro) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(umbRequestHelper.getApiUrl("macroApiBaseUrl", "Save"), macro)
|
||||
);
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
angular.module('umbraco.resources').factory('macroResource', macroResource);
|
||||
|
||||
19
src/Umbraco.Web.UI.Client/src/views/macros/create.html
Normal file
19
src/Umbraco.Web.UI.Client/src/views/macros/create.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<div ng-controller="Umbraco.Editors.Macros.CreateController as vm">
|
||||
|
||||
<div class="umb-pane">
|
||||
<h5><localize key="create_createUnder">Create an item under</localize> {{currentNode.name}}</h5>
|
||||
</div>
|
||||
|
||||
<div class="umb-pane">
|
||||
<form name="createDictionaryForm"
|
||||
ng-submit="vm.createItem()"
|
||||
val-form-manager>
|
||||
|
||||
<umb-control-group label="Enter a item-name" hide-label="true">
|
||||
<input type="text" name="itemKey" ng-model="vm.itemKey" class="umb-textstring textstring input-block-level" required />
|
||||
</umb-control-group>
|
||||
|
||||
<button type="submit" class="btn btn-primary"><localize key="general_create">Create</localize></button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
30
src/Umbraco.Web.UI.Client/src/views/macros/edit.html
Normal file
30
src/Umbraco.Web.UI.Client/src/views/macros/edit.html
Normal file
@@ -0,0 +1,30 @@
|
||||
<div data-element="editor-macros" ng-controller="Umbraco.Editors.Macros.EditController as vm">
|
||||
<form name="macroForm" novalidate val-form-manager ng-submit="vm.save()">
|
||||
<umb-load-indicator ng-if="vm.page.loading"></umb-load-indicator>
|
||||
<umb-editor-view ng-if="!vm.page.loading">
|
||||
<umb-editor-header name="vm.macro.name"
|
||||
alias="vm.macro.alias"
|
||||
hide-description="true"
|
||||
hide-icon="true"
|
||||
navigation="vm.page.navigation">
|
||||
</umb-editor-header>
|
||||
|
||||
<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-editor-footer>
|
||||
<umb-editor-footer-content-right>
|
||||
<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,27 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
function ParameterEditorController($scope, formHelper) {
|
||||
|
||||
const vm = this;
|
||||
|
||||
vm.submit = submit;
|
||||
vm.close = close;
|
||||
|
||||
function submit() {
|
||||
if ($scope.model && $scope.model.submit && formHelper.submitForm({scope: $scope})) {
|
||||
$scope.model.submit($scope.model);
|
||||
}
|
||||
}
|
||||
|
||||
function close() {
|
||||
if ($scope.model && $scope.model.close) {
|
||||
$scope.model.close();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.ParameterEditorController", ParameterEditorController);
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,58 @@
|
||||
<div ng-controller="Umbraco.Editors.ParameterEditorController as vm">
|
||||
|
||||
<form novalidate name="parameterForm" val-form-manager>
|
||||
|
||||
<umb-editor-view>
|
||||
|
||||
<umb-editor-header name="model.title"
|
||||
name-locked="true"
|
||||
hide-alias="true"
|
||||
hide-icon="true"
|
||||
hide-description="true">
|
||||
</umb-editor-header>
|
||||
|
||||
<umb-editor-container>
|
||||
|
||||
<umb-box>
|
||||
|
||||
<umb-box-content class="block-form">
|
||||
|
||||
<umb-control-group label="@general_name" description="">
|
||||
<input type="text" ng-model="model.parameter.label" umb-auto-focus required />
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group label="key" description="">
|
||||
<input type="text" ng-model="model.parameter.key" required />
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group label="Editor" description="">
|
||||
<select required class="input-block-level" ng-model="model.parameter.editor" ng-options="i.alias as (i.name) for i in model.editors"></select>
|
||||
</umb-control-group>
|
||||
|
||||
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
|
||||
</umb-editor-container>
|
||||
|
||||
<umb-editor-footer>
|
||||
<umb-editor-footer-content-right>
|
||||
<umb-button type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
action="vm.close()">
|
||||
</umb-button>
|
||||
<umb-button type="button"
|
||||
button-style="success"
|
||||
label-key="general_submit"
|
||||
state="vm.saveButtonState"
|
||||
action="vm.submit(model)">
|
||||
</umb-button>
|
||||
</umb-editor-footer-content-right>
|
||||
</umb-editor-footer>
|
||||
'
|
||||
</umb-editor-view>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* @ngdoc controller
|
||||
* @name Umbraco.Editors.Macros.CreateController
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* The controller for creating macro items
|
||||
*/
|
||||
function MacrosCreateController($scope, $location, macroResource, navigationService, notificationsService, formHelper, appState) {
|
||||
var vm = this;
|
||||
|
||||
vm.itemKey = "";
|
||||
|
||||
function createItem() {
|
||||
|
||||
var node = $scope.currentNode;
|
||||
|
||||
macroResource.createMacro(vm.itemKey).then(function (data) {
|
||||
navigationService.hideMenu();
|
||||
|
||||
// set new item as active in tree
|
||||
var currPath = node.path ? node.path : "-1";
|
||||
navigationService.syncTree({ tree: "macros", path: currPath + "," + data, forceReload: true, activate: true });
|
||||
|
||||
// reset form state
|
||||
formHelper.resetForm({ scope: $scope });
|
||||
|
||||
// navigate to edit view
|
||||
var currentSection = appState.getSectionState("currentSection");
|
||||
$location.path("/" + currentSection + "/macros/edit/" + data);
|
||||
|
||||
|
||||
}, function (err) {
|
||||
if (err.data && err.data.message) {
|
||||
notificationsService.error(err.data.message);
|
||||
navigationService.hideMenu();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
vm.createItem = createItem;
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.Macros.CreateController", MacrosCreateController);
|
||||
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
* @ngdoc controller
|
||||
* @name Umbraco.Editors.Macros.EditController
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* The controller for editing macros.
|
||||
*/
|
||||
function MacrosEditController($scope, $q, $routeParams, macroResource, editorState, navigationService, formHelper, contentEditingHelper, localizationService, angularHelper) {
|
||||
|
||||
var vm = this;
|
||||
|
||||
vm.promises = {};
|
||||
|
||||
vm.page = {};
|
||||
vm.page.loading = false;
|
||||
vm.page.saveButtonState = "init";
|
||||
vm.page.menu = {}
|
||||
|
||||
|
||||
|
||||
function toggleValue(key) {
|
||||
vm.macro[key] = !vm.macro[key];
|
||||
}
|
||||
|
||||
vm.toggle = toggleValue;
|
||||
|
||||
function saveMacro() {
|
||||
|
||||
if (formHelper.submitForm({ scope: $scope, statusMessage: "Saving..." })) {
|
||||
vm.page.saveButtonState = "busy";
|
||||
|
||||
macroResource.saveMacro(vm.macro).then(function (data) {
|
||||
formHelper.resetForm({ scope: $scope, notifications: data.notifications });
|
||||
bindMacro(data);
|
||||
vm.page.saveButtonState = "success";
|
||||
}, function (error) {
|
||||
contentEditingHelper.handleSaveError({
|
||||
redirectOnFailure: false,
|
||||
err: error
|
||||
});
|
||||
|
||||
vm.page.saveButtonState = "error";
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
vm.save = saveMacro;
|
||||
|
||||
function setFormDirty() {
|
||||
var currentForm = angularHelper.getCurrentForm($scope);
|
||||
|
||||
if (currentForm) {
|
||||
|
||||
currentForm.$setDirty();
|
||||
}
|
||||
}
|
||||
|
||||
vm.setDirty = setFormDirty;
|
||||
|
||||
function getPartialViews() {
|
||||
var deferred = $q.defer();
|
||||
|
||||
macroResource.getPartialViews().then(function (data) {
|
||||
deferred.resolve(data);
|
||||
}, function () {
|
||||
deferred.reject();
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function getParameterEditors() {
|
||||
var deferred = $q.defer();
|
||||
|
||||
macroResource.getParameterEditors().then(function (data) {
|
||||
deferred.resolve(data);
|
||||
}, function () {
|
||||
deferred.reject();
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function getMacro() {
|
||||
var deferred = $q.defer();
|
||||
|
||||
macroResource.getById($routeParams.id).then(function (data) {
|
||||
deferred.resolve(data);
|
||||
}, function () {
|
||||
deferred.reject();
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function bindMacro(data) {
|
||||
vm.macro = data;
|
||||
editorState.set(vm.macro);
|
||||
|
||||
navigationService.syncTree({ tree: "macros", path: vm.macro.path, forceReload: true }).then(function (syncArgs) {
|
||||
vm.page.menu.currentNode = syncArgs.node;
|
||||
});
|
||||
}
|
||||
|
||||
function init() {
|
||||
vm.page.loading = true;
|
||||
|
||||
vm.promises['partialViews'] = getPartialViews();
|
||||
vm.promises['parameterEditors'] = getParameterEditors();
|
||||
vm.promises['macro'] = getMacro();
|
||||
|
||||
$q.all(vm.promises).then(function (values) {
|
||||
var keys = Object.keys(values);
|
||||
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
var key = keys[i];
|
||||
|
||||
if (keys[i] === 'partialViews') {
|
||||
vm.views = values[key];
|
||||
}
|
||||
|
||||
if (keys[i] === 'parameterEditors') {
|
||||
vm.parameterEditors = values[key];
|
||||
}
|
||||
|
||||
if (keys[i] === 'macro') {
|
||||
bindMacro(values[key]);
|
||||
}
|
||||
}
|
||||
|
||||
vm.page.loading = false;
|
||||
});
|
||||
|
||||
vm.page.navigation = [
|
||||
{
|
||||
"name": "Settings",
|
||||
"alias": "settings",
|
||||
"icon": "icon-settings",
|
||||
"view": "views/macros/views/settings.html",
|
||||
"active": true
|
||||
},
|
||||
{
|
||||
"name": "Parameters",
|
||||
"alias": "parameters",
|
||||
"icon": "icon-list",
|
||||
"view": "views/macros/views/parameters.html"
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.Macros.EditController", MacrosEditController);
|
||||
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* @ngdoc controller
|
||||
* @name Umbraco.Editors.Macros.ParametersController
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* The controller for editing macros parameters
|
||||
*/
|
||||
function MacrosParametersController($scope, editorService) {
|
||||
|
||||
$scope.sortableOptions = {
|
||||
axis: 'y',
|
||||
containment: 'parent',
|
||||
cursor: 'move',
|
||||
items: 'div.umb-stylesheet-rules__listitem',
|
||||
handle: '.handle',
|
||||
tolerance: 'pointer',
|
||||
update: function (e, ui) {
|
||||
$scope.model.setDirty();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
$scope.remove = function (parameter, evt) {
|
||||
evt.preventDefault();
|
||||
|
||||
$scope.model.macro.parameters = _.without($scope.model.macro.parameters, parameter);
|
||||
$scope.model.setDirty();
|
||||
}
|
||||
|
||||
$scope.add = function (evt) {
|
||||
evt.preventDefault();
|
||||
|
||||
openOverlay({}, 'Add parameter', (newParameter) => {
|
||||
if (!$scope.model.macro.parameters) {
|
||||
$scope.model.macro.parameters = [];
|
||||
}
|
||||
$scope.model.macro.parameters.push(newParameter);
|
||||
$scope.model.setDirty();
|
||||
});
|
||||
}
|
||||
|
||||
$scope.edit = function (parameter, evt) {
|
||||
evt.preventDefault();
|
||||
|
||||
openOverlay(parameter,'Edit parameter', (newParameter) => {
|
||||
parameter.key = newParameter.key;
|
||||
parameter.label = newParameter.label;
|
||||
parameter.editor = newParameter.editor;
|
||||
parameter.editor = newParameter.editor;
|
||||
$scope.model.setDirty();
|
||||
});
|
||||
}
|
||||
|
||||
function openOverlay(parameter, title, onSubmit) {
|
||||
|
||||
const ruleDialog = {
|
||||
title: title,
|
||||
parameter: _.clone(parameter),
|
||||
editors : $scope.model.parameterEditors,
|
||||
view: "views/macros/infiniteeditors/parameter.html",
|
||||
size: "small",
|
||||
submit: function (model) {
|
||||
onSubmit(model.parameter);
|
||||
editorService.close();
|
||||
},
|
||||
close: function () {
|
||||
editorService.close();
|
||||
}
|
||||
};
|
||||
|
||||
editorService.open(ruleDialog);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.Macros.ParametersController", MacrosParametersController);
|
||||
@@ -0,0 +1,32 @@
|
||||
<umb-box>
|
||||
<umb-box-content>
|
||||
<div class="sub-view-columns">
|
||||
<div class="sub-view-column-left">
|
||||
<h5>Parameters</h5>
|
||||
<small>Define the parameters hat should be available when using his macro</small>
|
||||
</div>
|
||||
<div class="sub-view-column-right">
|
||||
<div class="umb-property-editor umb-stylesheet-rules form-horizontal" ng-controller="Umbraco.Editors.Macros.ParametersController" >
|
||||
<div ui-sortable="sortableOptions" ng-model="model.macro.parameters">
|
||||
<div class="umb-stylesheet-rules__listitem" ng-click="edit(parameter, $event)" ng-repeat="parameter in model.macro.parameters">
|
||||
<i class="icon icon-navigation handle"></i>
|
||||
<div class="umb-stylesheet-rules__left">
|
||||
{{parameter.label}}
|
||||
</div>
|
||||
<div class="umb-stylesheet-rules__right">
|
||||
<a class="umb-node-preview__action umb-node-preview__action--red" ng-click="remove(parameter, $event)"><localize key="general_remove">Remove</localize></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<umb-button
|
||||
type="button"
|
||||
button-style="info"
|
||||
action="add($event)"
|
||||
label-key="general_add">
|
||||
</umb-button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
@@ -0,0 +1,43 @@
|
||||
<umb-box>
|
||||
<umb-box-header title="Info"></umb-box-header>
|
||||
<umb-box-content>
|
||||
<umb-control-group label="Id">
|
||||
{{model.macro.id}}<br/>
|
||||
{{model.macro.key}}
|
||||
</umb-control-group>
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
<umb-box>
|
||||
<umb-box-header title="Macro partial view"></umb-box-header>
|
||||
<umb-box-content>
|
||||
<umb-control-group label="Macro partial view">
|
||||
<select class="input-block-level" ng-model="model.macro.view" ng-options="i as i for i in model.views" required>
|
||||
</select>
|
||||
</umb-control-group>
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
<umb-box>
|
||||
<umb-box-header title="Editor settings"></umb-box-header>
|
||||
<umb-box-content>
|
||||
<umb-control-group label="Use in rich text editor and the grid">
|
||||
<umb-toggle checked="model.macro.useInEditor" on-click="model.toggle('useInEditor')" ></umb-toggle>
|
||||
</umb-control-group>
|
||||
<umb-control-group label="Render in rich text editor and the grid" ng-if="model.macro.useInEditor">
|
||||
<umb-toggle checked="model.macro.renderInEditor && model.macro.useInEditor" on-click="model.toggle('renderInEditor')" ></umb-toggle>
|
||||
</umb-control-group>
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
<umb-box>
|
||||
<umb-box-header title="Cache settings"></umb-box-header>
|
||||
<umb-box-content>
|
||||
<umb-control-group label="Cache period">
|
||||
<input type="number" ng-model="model.macro.cachePeriod"/>
|
||||
</umb-control-group>
|
||||
<umb-control-group label="Cache by page">
|
||||
<umb-toggle checked="model.macro.cacheByPage" on-click="model.toggle('cacheByPage')"></umb-toggle>
|
||||
</umb-control-group>
|
||||
<umb-control-group label="Cache personalized">
|
||||
<umb-toggle checked="model.macro.cacheByUser" on-click="model.toggle('cacheByUser')"></umb-toggle>
|
||||
</umb-control-group>
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
@@ -169,9 +169,13 @@ namespace Umbraco.Web.Editors
|
||||
controller => controller.GetAllowedChildren(0))
|
||||
},
|
||||
{
|
||||
"macroApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl<MacroController>(
|
||||
"macroRenderingApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl<MacroRenderingController>(
|
||||
controller => controller.GetMacroParameters(0))
|
||||
},
|
||||
{
|
||||
"macroApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl<MacrosController>(
|
||||
controller => controller.Create(null))
|
||||
},
|
||||
{
|
||||
"authenticationApiBaseUrl", _urlHelper.GetUmbracoApiServiceBaseUrl<AuthenticationController>(
|
||||
controller => controller.PostLogin(null))
|
||||
|
||||
@@ -27,11 +27,11 @@ namespace Umbraco.Web.Editors
|
||||
/// Session, we don't want it to throw null reference exceptions.
|
||||
/// </remarks>
|
||||
[PluginController("UmbracoApi")]
|
||||
public class MacroController : UmbracoAuthorizedJsonController, IRequiresSessionState
|
||||
public class MacroRenderingController : UmbracoAuthorizedJsonController, IRequiresSessionState
|
||||
{
|
||||
private readonly IVariationContextAccessor _variationContextAccessor;
|
||||
|
||||
public MacroController(IVariationContextAccessor variationContextAccessor)
|
||||
public MacroRenderingController(IVariationContextAccessor variationContextAccessor)
|
||||
{
|
||||
_variationContextAccessor = variationContextAccessor;
|
||||
}
|
||||
320
src/Umbraco.Web/Editors/MacrosController.cs
Normal file
320
src/Umbraco.Web/Editors/MacrosController.cs
Normal file
@@ -0,0 +1,320 @@
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Web.Http;
|
||||
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Web.Composing;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.UI;
|
||||
using Umbraco.Web.WebApi;
|
||||
using Umbraco.Web.WebApi.Filters;
|
||||
|
||||
using Constants = Umbraco.Core.Constants;
|
||||
|
||||
/// <summary>
|
||||
/// The API controller used for editing dictionary items
|
||||
/// </summary>
|
||||
[PluginController("UmbracoApi")]
|
||||
[UmbracoTreeAuthorize(Constants.Trees.Macros)]
|
||||
public class MacrosController : BackOfficeNotificationsController
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new macro
|
||||
/// </summary>
|
||||
/// <param name="name">
|
||||
/// The name.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The <see cref="HttpResponseMessage"/>.
|
||||
/// </returns>
|
||||
[HttpPost]
|
||||
public HttpResponseMessage Create(string name)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
return this.ReturnErrorResponse("Name can not be empty");
|
||||
}
|
||||
|
||||
var alias = name.ToSafeAlias();
|
||||
|
||||
if (this.Services.MacroService.GetByAlias(alias) != null)
|
||||
{
|
||||
return this.ReturnErrorResponse("Macro with this alias already exists");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var macro = new Macro
|
||||
{
|
||||
Alias = alias,
|
||||
Name = name,
|
||||
MacroSource = string.Empty,
|
||||
MacroType = MacroTypes.PartialView
|
||||
};
|
||||
|
||||
this.Services.MacroService.Save(macro, this.Security.CurrentUser.Id);
|
||||
|
||||
return this.Request.CreateResponse(HttpStatusCode.OK, macro.Id);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
return this.ReturnErrorResponse("Error creating macro", true, exception);
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public HttpResponseMessage GetById(int id)
|
||||
{
|
||||
var macro = this.Services.MacroService.GetById(id);
|
||||
|
||||
if (macro == null)
|
||||
{
|
||||
return this.ReturnErrorResponse($"Macro with id {id} does not exist");
|
||||
}
|
||||
|
||||
var macroDisplay = new MacroDisplay
|
||||
{
|
||||
Alias = macro.Alias,
|
||||
Id = macro.Id,
|
||||
Key = macro.Key,
|
||||
Name = macro.Name,
|
||||
CacheByPage = macro.CacheByPage,
|
||||
CacheByUser = macro.CacheByMember,
|
||||
CachePeriod = macro.CacheDuration,
|
||||
View = macro.MacroSource,
|
||||
RenderInEditor = !macro.DontRender,
|
||||
UseInEditor = macro.UseInEditor,
|
||||
Path = $"-1,{macro.Id}"
|
||||
};
|
||||
|
||||
var parameters = new List<MacroParameterDisplay>();
|
||||
|
||||
foreach (var param in macro.Properties.Values.OrderBy(x => x.SortOrder))
|
||||
{
|
||||
parameters.Add(new MacroParameterDisplay
|
||||
{
|
||||
Editor = param.EditorAlias,
|
||||
Key = param.Alias,
|
||||
Label = param.Name,
|
||||
Id = param.Id
|
||||
});
|
||||
}
|
||||
|
||||
macroDisplay.Parameters = parameters;
|
||||
|
||||
return this.Request.CreateResponse(HttpStatusCode.OK, macroDisplay);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public HttpResponseMessage Save(MacroDisplay macroDisplay)
|
||||
{
|
||||
if (macroDisplay == null)
|
||||
{
|
||||
return this.ReturnErrorResponse($"No macro data found in request");
|
||||
}
|
||||
|
||||
var macro = this.Services.MacroService.GetById(int.Parse(macroDisplay.Id.ToString()));
|
||||
|
||||
if (macro == null)
|
||||
{
|
||||
return this.ReturnErrorResponse($"Macro with id {macroDisplay.Id} does not exist");
|
||||
}
|
||||
|
||||
if (macroDisplay.Alias != macro.Alias)
|
||||
{
|
||||
var macroByAlias = this.Services.MacroService.GetByAlias(macroDisplay.Alias);
|
||||
|
||||
if (macroByAlias != null)
|
||||
{
|
||||
return this.ReturnErrorResponse("Macro with this alias already exists");
|
||||
}
|
||||
}
|
||||
|
||||
macro.Alias = macroDisplay.Alias;
|
||||
macro.Name = macroDisplay.Name;
|
||||
macro.CacheByMember = macroDisplay.CacheByUser;
|
||||
macro.CacheByPage = macroDisplay.CacheByPage;
|
||||
macro.CacheDuration = macroDisplay.CachePeriod;
|
||||
macro.DontRender = !macroDisplay.RenderInEditor;
|
||||
macro.UseInEditor = macroDisplay.UseInEditor;
|
||||
macro.MacroSource = macroDisplay.View;
|
||||
macro.MacroType = MacroTypes.PartialView;
|
||||
macro.Properties.ReplaceAll(macroDisplay.Parameters.Select((x,i) => new MacroProperty(x.Key, x.Label, i, x.Editor)));
|
||||
|
||||
try
|
||||
{
|
||||
this.Services.MacroService.Save(macro, this.Security.CurrentUser.Id);
|
||||
|
||||
macroDisplay.Notifications.Clear();
|
||||
|
||||
macroDisplay.Notifications.Add(new Models.ContentEditing.Notification("Success", "Macro saved", SpeechBubbleIcon.Success));
|
||||
|
||||
return this.Request.CreateResponse(HttpStatusCode.OK, macroDisplay);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
return this.ReturnErrorResponse("Error creating macro", true, exception);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of available macro partials
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The <see cref="HttpResponseMessage"/>.
|
||||
/// </returns>
|
||||
public HttpResponseMessage GetPartialViews()
|
||||
{
|
||||
var views = new List<string>();
|
||||
|
||||
views.AddRange(this.FindPartialViewsFiles());
|
||||
|
||||
return this.Request.CreateResponse(HttpStatusCode.OK, views);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the available parameter editors
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The <see cref="HttpResponseMessage"/>.
|
||||
/// </returns>
|
||||
public HttpResponseMessage GetParameterEditors()
|
||||
{
|
||||
return this.Request.CreateResponse(HttpStatusCode.OK, Current.ParameterEditors);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a error response and optionally logs it
|
||||
/// </summary>
|
||||
/// <param name="message">
|
||||
/// The error message.
|
||||
/// </param>
|
||||
/// <param name="logError">
|
||||
/// Value to indicate if the error needs to be logged
|
||||
/// </param>
|
||||
/// <param name="exception">
|
||||
/// The exception to log
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The <see cref="HttpResponseMessage"/>.
|
||||
/// </returns>
|
||||
private HttpResponseMessage ReturnErrorResponse(string message, bool logError = false, Exception exception = null)
|
||||
{
|
||||
if (logError && exception != null)
|
||||
{
|
||||
this.Logger.Error<MacrosController>(exception, message);
|
||||
}
|
||||
|
||||
return this.Request.CreateNotificationValidationErrorResponse(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds all the macro partials
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The <see cref="IEnumerable"/>.
|
||||
/// </returns>
|
||||
private IEnumerable<string> FindPartialViewsFiles()
|
||||
{
|
||||
var files = new List<string>();
|
||||
|
||||
files.AddRange(this.FindPartialViewFilesInViewsFolder());
|
||||
files.AddRange(this.FindPartialViewFilesInPluginFolders());
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds all macro partials in the views folder
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The <see cref="IEnumerable"/>.
|
||||
/// </returns>
|
||||
private IEnumerable<string> FindPartialViewFilesInViewsFolder()
|
||||
{
|
||||
var partialsDir = IOHelper.MapPath(SystemDirectories.MacroPartials);
|
||||
|
||||
return this.FindPartialViewFilesInFolder(
|
||||
partialsDir,
|
||||
partialsDir,
|
||||
SystemDirectories.MacroPartials);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds partial view files in app plugin folders.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The <see cref="IEnumerable"/>.
|
||||
/// </returns>
|
||||
private IEnumerable<string> FindPartialViewFilesInPluginFolders()
|
||||
{
|
||||
var files = new List<string>();
|
||||
|
||||
var appPluginsFolder = new DirectoryInfo(IOHelper.MapPath(SystemDirectories.AppPlugins));
|
||||
|
||||
if (!appPluginsFolder.Exists)
|
||||
{
|
||||
return files;
|
||||
}
|
||||
|
||||
foreach (var directory in appPluginsFolder.GetDirectories())
|
||||
{
|
||||
var viewsFolder = directory.GetDirectories("Views");
|
||||
if (viewsFolder.Any())
|
||||
{
|
||||
var macroPartials = viewsFolder.First().GetDirectories("MacroPartials");
|
||||
if (macroPartials.Any())
|
||||
{
|
||||
files.AddRange(this.FindPartialViewFilesInFolder(macroPartials.First().FullName, macroPartials.First().FullName, SystemDirectories.AppPlugins + "/" + directory.Name + "/Views/MacroPartials"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Finds all partial views in a folder and subfolders
|
||||
/// </summary>
|
||||
/// <param name="orgPath">
|
||||
/// The org path.
|
||||
/// </param>
|
||||
/// <param name="path">
|
||||
/// The path.
|
||||
/// </param>
|
||||
/// <param name="prefixVirtualPath">
|
||||
/// The prefix virtual path.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The <see cref="IEnumerable"/>.
|
||||
/// </returns>
|
||||
private IEnumerable<string> FindPartialViewFilesInFolder(string orgPath, string path, string prefixVirtualPath)
|
||||
{
|
||||
var files = new List<string>();
|
||||
var dirInfo = new DirectoryInfo(path);
|
||||
|
||||
foreach (var dir in dirInfo.GetDirectories())
|
||||
{
|
||||
files.AddRange(this.FindPartialViewFilesInFolder(orgPath, path + "/" + dir.Name, prefixVirtualPath));
|
||||
}
|
||||
|
||||
var fileInfo = dirInfo.GetFiles("*.*");
|
||||
|
||||
files.AddRange(
|
||||
fileInfo.Select(file =>
|
||||
prefixVirtualPath.TrimEnd('/') + "/" + (path.Replace(orgPath, string.Empty).Trim('/') + "/" + file.Name).Trim('/')));
|
||||
|
||||
return files;
|
||||
}
|
||||
}
|
||||
}
|
||||
67
src/Umbraco.Web/Models/ContentEditing/MacroDisplay.cs
Normal file
67
src/Umbraco.Web/Models/ContentEditing/MacroDisplay.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Web.Models.ContentEditing
|
||||
{
|
||||
/// <summary>
|
||||
/// The macro display model
|
||||
/// </summary>
|
||||
[DataContract(Name = "dictionary", Namespace = "")]
|
||||
public class MacroDisplay : EntityBasic, INotificationModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MacroDisplay"/> class.
|
||||
/// </summary>
|
||||
public MacroDisplay()
|
||||
{
|
||||
this.Notifications = new List<Notification>();
|
||||
this.Parameters = new List<MacroParameterDisplay>();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
[DataMember(Name = "notifications")]
|
||||
public List<Notification> Notifications { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the macro can be used in a rich text editor.
|
||||
/// </summary>
|
||||
[DataMember(Name = "useInEditor")]
|
||||
public bool UseInEditor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the macro should be rendered a rich text editor.
|
||||
/// </summary>
|
||||
[DataMember(Name = "renderInEditor")]
|
||||
public bool RenderInEditor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the cache period.
|
||||
/// </summary>
|
||||
[DataMember(Name = "cachePeriod")]
|
||||
public int CachePeriod { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the macro should be cached by page
|
||||
/// </summary>
|
||||
[DataMember(Name = "cacheByPage")]
|
||||
public bool CacheByPage { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the macro should be cached by user
|
||||
/// </summary>
|
||||
[DataMember(Name = "cacheByUser")]
|
||||
public bool CacheByUser { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the view.
|
||||
/// </summary>
|
||||
[DataMember(Name = "view")]
|
||||
public string View { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the parameters.
|
||||
/// </summary>
|
||||
[DataMember(Name = "parameters")]
|
||||
public IEnumerable<MacroParameterDisplay> Parameters { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
namespace Umbraco.Web.Models.ContentEditing
|
||||
{
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
/// <summary>
|
||||
/// The macro parameter display.
|
||||
/// </summary>
|
||||
[DataContract(Name = "parameter", Namespace = "")]
|
||||
public class MacroParameterDisplay
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the key.
|
||||
/// </summary>
|
||||
[DataMember(Name = "key")]
|
||||
public string Key { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the label.
|
||||
/// </summary>
|
||||
[DataMember(Name = "label")]
|
||||
public string Label { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the editor.
|
||||
/// </summary>
|
||||
[DataMember(Name = "editor")]
|
||||
public string Editor { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the id.
|
||||
/// </summary>
|
||||
[DataMember(Name = "id")]
|
||||
public int Id { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -39,10 +39,7 @@ namespace Umbraco.Web.Trees
|
||||
queryStrings,
|
||||
macro.Name,
|
||||
"icon-settings-alt",
|
||||
false,
|
||||
//TODO: Rebuild the macro editor in angular, then we dont need to have this at all (which is just a path to the legacy editor)
|
||||
"/" + queryStrings.GetValue<string>("application") + "/framed/" +
|
||||
Uri.EscapeDataString("/umbraco/developer/macros/editMacro.aspx?macroID=" + macro.Id)));
|
||||
false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,11 +53,8 @@ namespace Umbraco.Web.Trees
|
||||
if (id == Constants.System.Root.ToInvariantString())
|
||||
{
|
||||
//Create the normal create action
|
||||
menu.Items.Add<ActionNew>(Services.TextService, opensDialog: true)
|
||||
//Since we haven't implemented anything for macros in angular, this needs to be converted to
|
||||
//use the legacy format
|
||||
.ConvertLegacyMenuItem(null, "initmacros", queryStrings.GetValue<string>("application"));
|
||||
|
||||
menu.Items.Add<ActionNew>(Services.TextService);
|
||||
|
||||
//refresh action
|
||||
menu.Items.Add(new RefreshNode(Services.TextService, true));
|
||||
|
||||
|
||||
@@ -125,6 +125,7 @@
|
||||
<Compile Include="Editors\BackOfficePreviewModel.cs" />
|
||||
<Compile Include="Editors\PackageController.cs" />
|
||||
<Compile Include="Editors\KeepAliveController.cs" />
|
||||
<Compile Include="Editors\MacrosController.cs" />
|
||||
<Compile Include="Editors\RelationTypeController.cs" />
|
||||
<Compile Include="Logging\WebProfiler.cs" />
|
||||
<Compile Include="Logging\WebProfilerComponent.cs" />
|
||||
@@ -166,6 +167,8 @@
|
||||
<Compile Include="Media\TypeDetector\SvgDetector.cs" />
|
||||
<Compile Include="Media\TypeDetector\TIFFDetector.cs" />
|
||||
<Compile Include="Media\UploadAutoFillProperties.cs" />
|
||||
<Compile Include="Models\ContentEditing\MacroDisplay.cs" />
|
||||
<Compile Include="Models\ContentEditing\MacroParameterDisplay.cs" />
|
||||
<Compile Include="Trees\BackOfficeSectionCollectionBuilder.cs" />
|
||||
<Compile Include="Trees\MediaBackOfficeSection.cs" />
|
||||
<Compile Include="Trees\MembersBackOfficeSection.cs" />
|
||||
@@ -779,7 +782,7 @@
|
||||
<Compile Include="Mvc\EnsurePublishedContentRequestAttribute.cs" />
|
||||
<Compile Include="Mvc\UmbracoViewPage.cs" />
|
||||
<Compile Include="Editors\LogController.cs" />
|
||||
<Compile Include="Editors\MacroController.cs" />
|
||||
<Compile Include="Editors\MacroRenderingController.cs" />
|
||||
<Compile Include="Editors\MemberTypeController.cs" />
|
||||
<Compile Include="Editors\UpdateCheckController.cs" />
|
||||
<Compile Include="MembershipProviderExtensions.cs" />
|
||||
|
||||
@@ -102,7 +102,7 @@ namespace umbraco
|
||||
/// Initializes a new instance of the page for a content.
|
||||
/// </summary>
|
||||
/// <param name="content">The content.</param>
|
||||
/// <remarks>This is for <see cref="MacroController"/> usage only.</remarks>
|
||||
/// <remarks>This is for <see cref="MacroRenderingController"/> usage only.</remarks>
|
||||
internal page(IContent content, IVariationContextAccessor variationContextAccessor)
|
||||
: this(new PagePublishedContent(content, variationContextAccessor))
|
||||
{ }
|
||||
|
||||
Reference in New Issue
Block a user