Merge branch 'dev-v7.6' into temp-U4-9352
# Conflicts: # src/Umbraco.Web.UI.Client/src/views/templates/edit.controller.js
This commit is contained in:
@@ -43,7 +43,8 @@
|
||||
templateUrl: "views/components/tabs/umb-tabs-nav.html",
|
||||
scope: {
|
||||
model: "=",
|
||||
tabdrop: "="
|
||||
tabdrop: "=",
|
||||
idSuffix: "@"
|
||||
},
|
||||
link: link
|
||||
};
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Used on a button to launch a mini content editor editor dialog
|
||||
**/
|
||||
angular.module("umbraco.directives")
|
||||
.directive('umbLaunchMiniEditor', function (dialogService, editorState, fileManager, contentEditingHelper) {
|
||||
.directive('umbLaunchMiniEditor', function (miniEditorHelper) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
replace: false,
|
||||
@@ -16,69 +16,8 @@ angular.module("umbraco.directives")
|
||||
},
|
||||
link: function(scope, element, attrs) {
|
||||
|
||||
var launched = false;
|
||||
|
||||
element.click(function() {
|
||||
|
||||
if (launched === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
launched = true;
|
||||
|
||||
//We need to store the current files selected in the file manager locally because the fileManager
|
||||
// is a singleton and is shared globally. The mini dialog will also be referencing the fileManager
|
||||
// and we don't want it to be sharing the same files as the main editor. So we'll store the current files locally here,
|
||||
// clear them out and then launch the dialog. When the dialog closes, we'll reset the fileManager to it's previous state.
|
||||
var currFiles = _.groupBy(fileManager.getFiles(), "alias");
|
||||
fileManager.clearFiles();
|
||||
|
||||
//We need to store the original editorState entity because it will need to change when the mini editor is loaded so that
|
||||
// any property editors that are working with editorState get given the correct entity, otherwise strange things will
|
||||
// start happening.
|
||||
var currEditorState = editorState.getCurrent();
|
||||
|
||||
dialogService.open({
|
||||
template: "views/common/dialogs/content/edit.html",
|
||||
id: scope.node.id,
|
||||
closeOnSave: true,
|
||||
tabFilter: ["Generic properties"],
|
||||
callback: function (data) {
|
||||
|
||||
//set the node name back
|
||||
scope.node.name = data.name;
|
||||
|
||||
//reset the fileManager to what it was
|
||||
fileManager.clearFiles();
|
||||
_.each(currFiles, function (val, key) {
|
||||
fileManager.setFiles(key, _.map(currFiles['upload'], function (i) { return i.file; }));
|
||||
});
|
||||
|
||||
//reset the editor state
|
||||
editorState.set(currEditorState);
|
||||
|
||||
//Now we need to check if the content item that was edited was actually the same content item
|
||||
// as the main content editor and if so, update all property data
|
||||
if (data.id === currEditorState.id) {
|
||||
var changed = contentEditingHelper.reBindChangedProperties(currEditorState, data);
|
||||
}
|
||||
|
||||
launched = false;
|
||||
},
|
||||
closeCallback: function () {
|
||||
//reset the fileManager to what it was
|
||||
fileManager.clearFiles();
|
||||
_.each(currFiles, function (val, key) {
|
||||
fileManager.setFiles(key, _.map(currFiles['upload'], function (i) { return i.file; }));
|
||||
});
|
||||
|
||||
//reset the editor state
|
||||
editorState.set(currEditorState);
|
||||
|
||||
launched = false;
|
||||
}
|
||||
});
|
||||
|
||||
miniEditorHelper.launchMiniEditor(scope.node);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
@ngdoc directive
|
||||
@name umbraco.directives.directive:umbNodePreview
|
||||
@restrict E
|
||||
@scope
|
||||
|
||||
@description
|
||||
<strong>Added in Umbraco v. 7.6:</strong> Use this directive to render a node preview.
|
||||
|
||||
<h3>Markup example</h3>
|
||||
<pre>
|
||||
<div ng-controller="My.NodePreviewController as vm">
|
||||
|
||||
<div ui-sortable ng-model="vm.nodes">
|
||||
<umb-node-preview
|
||||
ng-repeat="node in vm.nodes"
|
||||
icon="node.icon"
|
||||
name="node.name"
|
||||
published="node.published"
|
||||
description="node.description"
|
||||
sortable="vm.sortable"
|
||||
allow-remove="vm.allowRemove"
|
||||
allow-open="vm.allowOpen"
|
||||
on-remove="vm.remove($index, vm.nodes)"
|
||||
on-open="vm.open(node)">
|
||||
</umb-node-preview>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</pre>
|
||||
|
||||
<h3>Controller example</h3>
|
||||
<pre>
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function Controller() {
|
||||
|
||||
var vm = this;
|
||||
|
||||
vm.allowRemove = true;
|
||||
vm.allowOpen = true;
|
||||
vm.sortable = true;
|
||||
|
||||
vm.nodes = [
|
||||
{
|
||||
"icon": "icon-document",
|
||||
"name": "My node 1",
|
||||
"published": true,
|
||||
"description": "A short description of my node"
|
||||
},
|
||||
{
|
||||
"icon": "icon-document",
|
||||
"name": "My node 2",
|
||||
"published": true,
|
||||
"description": "A short description of my node"
|
||||
}
|
||||
];
|
||||
|
||||
vm.remove = remove;
|
||||
vm.open = open;
|
||||
|
||||
function remove(index, nodes) {
|
||||
alert("remove node");
|
||||
}
|
||||
|
||||
function open(node) {
|
||||
alert("open node");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("My.NodePreviewController", Controller);
|
||||
|
||||
})();
|
||||
</pre>
|
||||
|
||||
@param {string} icon (<code>binding</code>): The node icon.
|
||||
@param {string} name (<code>binding</code>): The node name.
|
||||
@param {boolean} published (<code>binding</code>): The node pusblished state.
|
||||
@param {string} description (<code>binding</code>): A short description.
|
||||
@param {boolean} sortable (<code>binding</code>): Will add a move cursor on the node preview. Can used in combination with ui-sortable.
|
||||
@param {boolean} allowRemove (<code>binding</code>): Show/Hide the remove button.
|
||||
@param {boolean} allowOpen (<code>binding</code>): Show/Hide the open button.
|
||||
@param {function} onRemove (<code>expression</code>): Callback function when the remove button is clicked.
|
||||
@param {function} onOpen (<code>expression</code>): Callback function when the open button is clicked.
|
||||
**/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function NodePreviewDirective() {
|
||||
|
||||
function link(scope, el, attr, ctrl) {
|
||||
|
||||
}
|
||||
|
||||
var directive = {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'views/components/umb-node-preview.html',
|
||||
scope: {
|
||||
icon: "=?",
|
||||
name: "=",
|
||||
description: "=?",
|
||||
published: "=?",
|
||||
sortable: "=?",
|
||||
allowOpen: "=?",
|
||||
allowRemove: "=?",
|
||||
onOpen: "&?",
|
||||
onRemove: "&?"
|
||||
},
|
||||
link: link
|
||||
};
|
||||
|
||||
return directive;
|
||||
|
||||
}
|
||||
|
||||
angular.module('umbraco.directives').directive('umbNodePreview', NodePreviewDirective);
|
||||
|
||||
})();
|
||||
@@ -33,6 +33,15 @@ angular.module('umbraco.mocks').
|
||||
return [200, nodes, null];
|
||||
}
|
||||
|
||||
function returnEntityUrl() {
|
||||
|
||||
if (!mocksUtils.checkAuth()) {
|
||||
return [401, null, null];
|
||||
}
|
||||
|
||||
return [200, "url", null];
|
||||
|
||||
}
|
||||
|
||||
return {
|
||||
register: function () {
|
||||
@@ -48,6 +57,10 @@ angular.module('umbraco.mocks').
|
||||
$httpBackend
|
||||
.whenGET(mocksUtils.urlRegex('/umbraco/UmbracoApi/Entity/GetById?'))
|
||||
.respond(returnEntitybyId);
|
||||
|
||||
$httpBackend
|
||||
.whenGET(mocksUtils.urlRegex('/umbraco/UmbracoApi/Entity/GetUrl?'))
|
||||
.respond(returnEntityUrl);
|
||||
}
|
||||
};
|
||||
}]);
|
||||
@@ -56,7 +56,7 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* entityResource.getPath(id)
|
||||
* entityResource.getPath(id, type)
|
||||
* .then(function(pathArray) {
|
||||
* alert('its here!');
|
||||
* });
|
||||
@@ -77,6 +77,37 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
'Failed to retrieve path for id:' + id);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.entityResource#getUrl
|
||||
* @methodOf umbraco.resources.entityResource
|
||||
*
|
||||
* @description
|
||||
* Returns a url, given a node ID and type
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* entityResource.getUrl(id, type)
|
||||
* .then(function(url) {
|
||||
* alert('its here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {Int} id Id of node to return the public url to
|
||||
* @param {string} type Object type name
|
||||
* @returns {Promise} resourcePromise object containing the url.
|
||||
*
|
||||
*/
|
||||
getUrl: function(id, type) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"entityApiBaseUrl",
|
||||
"GetUrl",
|
||||
[{ id: id }, {type: type }])),
|
||||
'Failed to retrieve url for id:' + id);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.entityResource#getById
|
||||
@@ -140,7 +171,7 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
query += "ids=" + item + "&";
|
||||
});
|
||||
|
||||
// if ids array is empty we need a empty variable in the querystring otherwise the service returns a error
|
||||
// if ids array is empty we need a empty variable in the querystring otherwise the service returns a error
|
||||
if (ids.length === 0) {
|
||||
query += "ids=&";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function miniEditorHelper(dialogService, editorState, fileManager, contentEditingHelper, $q) {
|
||||
|
||||
var launched = false;
|
||||
|
||||
function launchMiniEditor(node) {
|
||||
|
||||
var deferred = $q.defer();
|
||||
|
||||
launched = true;
|
||||
|
||||
//We need to store the current files selected in the file manager locally because the fileManager
|
||||
// is a singleton and is shared globally. The mini dialog will also be referencing the fileManager
|
||||
// and we don't want it to be sharing the same files as the main editor. So we'll store the current files locally here,
|
||||
// clear them out and then launch the dialog. When the dialog closes, we'll reset the fileManager to it's previous state.
|
||||
var currFiles = _.groupBy(fileManager.getFiles(), "alias");
|
||||
fileManager.clearFiles();
|
||||
|
||||
//We need to store the original editorState entity because it will need to change when the mini editor is loaded so that
|
||||
// any property editors that are working with editorState get given the correct entity, otherwise strange things will
|
||||
// start happening.
|
||||
var currEditorState = editorState.getCurrent();
|
||||
|
||||
dialogService.open({
|
||||
template: "views/common/dialogs/content/edit.html",
|
||||
id: node.id,
|
||||
closeOnSave: true,
|
||||
tabFilter: ["Generic properties"],
|
||||
callback: function (data) {
|
||||
|
||||
//set the node name back
|
||||
node.name = data.name;
|
||||
|
||||
//reset the fileManager to what it was
|
||||
fileManager.clearFiles();
|
||||
_.each(currFiles, function (val, key) {
|
||||
fileManager.setFiles(key, _.map(currFiles['upload'], function (i) { return i.file; }));
|
||||
});
|
||||
|
||||
//reset the editor state
|
||||
editorState.set(currEditorState);
|
||||
|
||||
//Now we need to check if the content item that was edited was actually the same content item
|
||||
// as the main content editor and if so, update all property data
|
||||
if (data.id === currEditorState.id) {
|
||||
var changed = contentEditingHelper.reBindChangedProperties(currEditorState, data);
|
||||
}
|
||||
|
||||
launched = false;
|
||||
|
||||
deferred.resolve(data);
|
||||
|
||||
},
|
||||
closeCallback: function () {
|
||||
//reset the fileManager to what it was
|
||||
fileManager.clearFiles();
|
||||
_.each(currFiles, function (val, key) {
|
||||
fileManager.setFiles(key, _.map(currFiles['upload'], function (i) { return i.file; }));
|
||||
});
|
||||
|
||||
//reset the editor state
|
||||
editorState.set(currEditorState);
|
||||
|
||||
launched = false;
|
||||
|
||||
deferred.reject();
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
return deferred.promise;
|
||||
|
||||
}
|
||||
|
||||
var service = {
|
||||
launchMiniEditor: launchMiniEditor
|
||||
};
|
||||
|
||||
return service;
|
||||
|
||||
}
|
||||
|
||||
|
||||
angular.module('umbraco.services').factory('miniEditorHelper', miniEditorHelper);
|
||||
|
||||
|
||||
})();
|
||||
@@ -1,6 +1,6 @@
|
||||
/** Executed when the application starts, binds to events and set global state */
|
||||
app.run(['userService', '$log', '$rootScope', '$location', 'navigationService', 'appState', 'editorState', 'fileManager', 'assetsService', 'eventsService', '$cookies', '$templateCache',
|
||||
function (userService, $log, $rootScope, $location, navigationService, appState, editorState, fileManager, assetsService, eventsService, $cookies, $templateCache) {
|
||||
app.run(['userService', '$log', '$rootScope', '$location', 'navigationService', 'appState', 'editorState', 'fileManager', 'assetsService', 'eventsService', '$cookies', '$templateCache', 'localStorageService',
|
||||
function (userService, $log, $rootScope, $location, navigationService, appState, editorState, fileManager, assetsService, eventsService, $cookies, $templateCache, localStorageService) {
|
||||
|
||||
//This sets the default jquery ajax headers to include our csrf token, we
|
||||
// need to user the beforeSend method because our token changes per user/login so
|
||||
@@ -13,6 +13,11 @@ app.run(['userService', '$log', '$rootScope', '$location', 'navigationService',
|
||||
|
||||
/** Listens for authentication and checks if our required assets are loaded, if/once they are we'll broadcast a ready event */
|
||||
eventsService.on("app.authenticated", function(evt, data) {
|
||||
|
||||
//Removes all stored LocalStorage browser items - that may contain sensitive data
|
||||
//So if a machine or computer is shared and a new user logs in, we clear out the previous persons localStorage items
|
||||
localStorageService.clearAll();
|
||||
|
||||
assetsService._loadInitAssets().then(function() {
|
||||
appState.setGlobalState("isReady", true);
|
||||
|
||||
|
||||
@@ -125,6 +125,8 @@
|
||||
|
||||
@import "components/notifications/umb-notifications.less";
|
||||
@import "components/umb-file-dropzone.less";
|
||||
@import "components/umb-node-preview.less";
|
||||
@import "components/umb-mini-editor.less";
|
||||
|
||||
// Utilities
|
||||
@import "utilities/_flexbox.less";
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
.umb-modal .umb-mini-editor {
|
||||
|
||||
.umb-panel-header {
|
||||
padding: 20px;
|
||||
background: @grayLighter;
|
||||
border-bottom: 1px solid @grayLight;
|
||||
height: 59px;
|
||||
|
||||
.umb-headline {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
margin-bottom: 0;
|
||||
margin-top: 3px;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-panel-body {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.umb-panel-body.with-footer {
|
||||
bottom: 52px;
|
||||
}
|
||||
|
||||
.umb-panel-footer {
|
||||
background: @grayLighter;
|
||||
border-top: 1px solid @grayLight;
|
||||
height: 51px;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
.umb-node-preview {
|
||||
padding: 5px 15px;
|
||||
margin-bottom: 5px;
|
||||
background: @grayLighter;
|
||||
border-radius: 3px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
max-width: 66.6%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.umb-node-preview--sortable {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.umb-node-preview--sortable:hover {
|
||||
border-color: #d9d9d9;
|
||||
}
|
||||
|
||||
.umb-node-preview--unpublished {
|
||||
.umb-node-preview__icon,
|
||||
.umb-node-preview__name,
|
||||
.umb-node-preview__description {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-node-preview__icon {
|
||||
display: flex;
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-size: 20px;
|
||||
margin-right: 10px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.umb-node-preview__content {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
.umb-node-preview__name {
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
color: @black;
|
||||
}
|
||||
|
||||
.umb-node-preview__description {
|
||||
font-size: 11px;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
.umb-node-preview__actions {
|
||||
flex: 0 0 auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.umb-node-preview__action {
|
||||
margin-left: 5px;
|
||||
margin-right: 5px;
|
||||
font-size: 13px;
|
||||
font-weight: bold;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.umb-node-preview__action:hover {
|
||||
color: @blue;
|
||||
text-decoration: none;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.umb-node-preview-add {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px dashed #d9d9d9;
|
||||
color: @blue;
|
||||
font-weight: bold;
|
||||
padding: 5px 15px;
|
||||
max-width: 66.6%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.umb-node-preview-add:hover {
|
||||
color: @blue;
|
||||
}
|
||||
|
||||
.umb-overlay,
|
||||
.umb-modal {
|
||||
.umb-node-preview {
|
||||
max-width: none;
|
||||
}
|
||||
.umb-node-preview-add {
|
||||
max-width: none;
|
||||
}
|
||||
}
|
||||
@@ -190,7 +190,7 @@ input[type="tel"],
|
||||
input[type="color"],
|
||||
.uneditable-input {
|
||||
display: inline-block;
|
||||
height: @baseLineHeight;
|
||||
height: 30px;
|
||||
padding: 4px 6px;
|
||||
margin-bottom: @baseLineHeight / 2;
|
||||
font-size: @baseFontSize;
|
||||
@@ -198,6 +198,7 @@ input[type="color"],
|
||||
color: @gray;
|
||||
.border-radius(@inputBorderRadius);
|
||||
vertical-align: middle;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
input.-full-width-input {
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
ng-controller="Umbraco.Dialogs.Content.EditController"
|
||||
ng-show="loaded"
|
||||
ng-submit="save()"
|
||||
val-form-manager>
|
||||
val-form-manager
|
||||
class="umb-mini-editor">
|
||||
|
||||
<div class="umb-panel">
|
||||
<div class="umb-panel-header">
|
||||
@@ -12,15 +13,33 @@
|
||||
</div>
|
||||
|
||||
<div class="umb-panel-body with-footer">
|
||||
<div id="tab{{tab.id}}" ng-repeat="tab in content.tabs">
|
||||
<div class="umb-pane" ng-if="!tab.hide">
|
||||
<h5>{{tab.label}}</h5>
|
||||
<umb-property property="property"
|
||||
ng-repeat="property in tab.properties">
|
||||
<umb-editor model="property"></umb-editor>
|
||||
</umb-property>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="umb-pane" ng-if="content">
|
||||
|
||||
<umb-tabs-nav
|
||||
model="content.tabs"
|
||||
id-suffix="-mini-editor">
|
||||
</umb-tabs-nav>
|
||||
|
||||
<umb-tabs-content>
|
||||
|
||||
<umb-tab
|
||||
id="tab{{tab.id}}-mini-editor"
|
||||
ng-repeat="tab in content.tabs"
|
||||
rel="{{tab.id}}-mini-editor">
|
||||
|
||||
<umb-property
|
||||
property="property"
|
||||
ng-repeat="property in tab.properties">
|
||||
<umb-editor model="property"></umb-editor>
|
||||
</umb-property>
|
||||
|
||||
</umb-tab>
|
||||
|
||||
</umb-tabs-content>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function InsertOverlayController($scope) {
|
||||
function InsertOverlayController($scope, localizationService) {
|
||||
|
||||
var vm = this;
|
||||
|
||||
if(!$scope.model.title) {
|
||||
$scope.model.title = "Insert";
|
||||
$scope.model.title = localizationService.localize("template_insert");
|
||||
}
|
||||
|
||||
if(!$scope.model.subtitle) {
|
||||
$scope.model.subtitle = "Choose what to insert into your template";
|
||||
$scope.model.subtitle = localizationService.localize("template_insertDesc");
|
||||
}
|
||||
|
||||
vm.openMacroPicker = openMacroPicker;
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
vm.macroPickerOverlay = {
|
||||
view: "macropicker",
|
||||
title: "Insert macro",
|
||||
title: localizationService.localize("template_insertMacro"),
|
||||
dialogData: {},
|
||||
show: true,
|
||||
submit: function(model) {
|
||||
@@ -45,8 +45,8 @@
|
||||
|
||||
function openPageFieldOverlay() {
|
||||
vm.pageFieldOverlay = {
|
||||
title: "Insert value",
|
||||
description: "Select a value from the currentpage",
|
||||
title: localizationService.localize("template_insertPageField"),
|
||||
description: localizationService.localize("template_insertPageFieldDesc"),
|
||||
submitButtonLabel: "Insert",
|
||||
closeButtonlabel: "Cancel",
|
||||
view: "insertfield",
|
||||
@@ -78,7 +78,8 @@
|
||||
treeAlias: "dictionary",
|
||||
entityType: "dictionary",
|
||||
multiPicker: false,
|
||||
title: "Insert dictionary item",
|
||||
title: localizationService.localize("template_insertDictionaryItem"),
|
||||
description: localizationService.localize("template_insertDictionaryItemDesc"),
|
||||
show: true,
|
||||
select: function(node){
|
||||
|
||||
@@ -108,7 +109,7 @@
|
||||
entityType: "partialView",
|
||||
multiPicker: false,
|
||||
show: true,
|
||||
title: "Insert partial view",
|
||||
title: localizationService.localize("template_insertPartialView"),
|
||||
|
||||
select: function(node){
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
</div>
|
||||
<div ng-if="model.allowedTypes.dictionary" class="umb-insert-code-box" ng-click="vm.openDictionaryItemOverlay()">
|
||||
<div class="umb-insert-code-box__title"><localize key="template_insertDictionaryItem" /></div>
|
||||
<div class="umb-insert-code-box__description"><localize key="template_insertDictionaryItem" /></div>
|
||||
<div class="umb-insert-code-box__description"><localize key="template_insertDictionaryItemDesc" /></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -27,12 +27,12 @@
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<umb-empty-state ng-if="nomacros"
|
||||
position="center">
|
||||
<localize key="defaultdialogs_nomacros">
|
||||
<umb-empty-state
|
||||
ng-if="nomacros"
|
||||
position="center">
|
||||
<localize key="defaultdialogs_noMacros">
|
||||
There are no macros available to insert
|
||||
</localize>
|
||||
|
||||
</umb-empty-state>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//used for the media picker dialog
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.Overlays.MediaPickerController",
|
||||
function($scope, mediaResource, umbRequestHelper, entityResource, $log, mediaHelper, mediaTypeHelper, eventsService, treeService, $element, $timeout, $cookies, $cookieStore, localizationService) {
|
||||
function ($scope, mediaResource, umbRequestHelper, entityResource, $log, mediaHelper, mediaTypeHelper, eventsService, treeService, $element, $timeout, $cookies, localStorageService, localizationService) {
|
||||
|
||||
if (!$scope.model.title) {
|
||||
$scope.model.title = localizationService.localize("defaultdialogs_selectMedia");
|
||||
@@ -15,7 +15,7 @@ angular.module("umbraco")
|
||||
$scope.multiPicker = (dialogOptions.multiPicker && dialogOptions.multiPicker !== "0") ? true : false;
|
||||
$scope.startNodeId = dialogOptions.startNodeId ? dialogOptions.startNodeId : -1;
|
||||
$scope.cropSize = dialogOptions.cropSize;
|
||||
$scope.lastOpenedNode = $cookieStore.get("umbLastOpenedMediaNodeId");
|
||||
$scope.lastOpenedNode = localStorageService.get("umbLastOpenedMediaNodeId");
|
||||
if ($scope.onlyImages) {
|
||||
$scope.acceptedFileTypes = mediaHelper
|
||||
.formatFileTypes(Umbraco.Sys.ServerVariables.umbracoSettings.imageFileTypes);
|
||||
@@ -133,8 +133,7 @@ angular.module("umbraco")
|
||||
});
|
||||
$scope.currentFolder = folder;
|
||||
|
||||
// for some reason i cannot set cookies with cookieStore
|
||||
document.cookie = "umbLastOpenedMediaNodeId=" + folder.id;
|
||||
localStorageService.set("umbLastOpenedMediaNodeId", folder.id);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function QueryBuilderOverlayController($scope, templateQueryResource) {
|
||||
function QueryBuilderOverlayController($scope, templateQueryResource, localizationService) {
|
||||
|
||||
var everything = localizationService.localize("template_allContent");
|
||||
var myWebsite = localizationService.localize("template_websiteRoot");
|
||||
|
||||
var ascendingTranslation = localizationService.localize("template_ascending");
|
||||
var descendingTranslation = localizationService.localize("template_descending");
|
||||
|
||||
var vm = this;
|
||||
|
||||
vm.properties = [];
|
||||
@@ -17,10 +23,10 @@
|
||||
|
||||
vm.query = {
|
||||
contentType: {
|
||||
name: "Everything"
|
||||
name: everything
|
||||
},
|
||||
source: {
|
||||
name: "My website"
|
||||
name: myWebsite
|
||||
},
|
||||
filters: [
|
||||
{
|
||||
@@ -33,7 +39,13 @@
|
||||
alias: "",
|
||||
name: "",
|
||||
},
|
||||
direction: "ascending"
|
||||
direction: "ascending", //This is the value for sorting sent to server
|
||||
translation: {
|
||||
currentLabel: ascendingTranslation, //This is the localized UI value in the the dialog
|
||||
ascending: ascendingTranslation,
|
||||
descending: descendingTranslation
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
@@ -74,7 +86,6 @@
|
||||
vm.contentPickerOverlay = {
|
||||
view: "contentpicker",
|
||||
show: true,
|
||||
submitButtonLabel: "Insert",
|
||||
submit: function(model) {
|
||||
|
||||
var selectedNodeId = model.selection[0].id;
|
||||
@@ -83,7 +94,7 @@
|
||||
if (selectedNodeId > 0) {
|
||||
query.source = { id: selectedNodeId, name: selectedNodeName };
|
||||
} else {
|
||||
query.source.name = "My website";
|
||||
query.source.name = myWebsite;
|
||||
delete query.source.id;
|
||||
}
|
||||
|
||||
@@ -113,13 +124,21 @@
|
||||
|
||||
function trashFilter(query) {
|
||||
query.filters.splice(query, 1);
|
||||
|
||||
//if we remove the last one, add a new one to generate ui for it.
|
||||
if (query.filters.length == 0) {
|
||||
query.filters.push({});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function changeSortOrder(query) {
|
||||
if (query.sort.direction === "ascending") {
|
||||
query.sort.direction = "descending";
|
||||
query.sort.translation.currentLabel = query.sort.translation.descending;
|
||||
} else {
|
||||
query.sort.direction = "ascending";
|
||||
query.sort.translation.currentLabel = query.sort.translation.ascending;
|
||||
}
|
||||
throttledFunc();
|
||||
}
|
||||
@@ -128,8 +147,10 @@
|
||||
query.sort.property = property;
|
||||
if (property.type === "datetime") {
|
||||
query.sort.direction = "descending";
|
||||
query.sort.translation.currentLabel = query.sort.translation.descending;
|
||||
} else {
|
||||
query.sort.direction = "ascending";
|
||||
query.sort.translation.currentLabel = query.sort.translation.ascending;
|
||||
}
|
||||
throttledFunc();
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<div class="row">
|
||||
<div class="query-items">
|
||||
|
||||
<span><localize key="template_iWant">I Want</localize></span>
|
||||
<span><localize key="template_iWant">I want</localize></span>
|
||||
|
||||
<div class="btn-group">
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
</div>
|
||||
|
||||
<span><localize key="template_fromt">from</localize></span>
|
||||
<span><localize key="template_from">from</localize></span>
|
||||
|
||||
<a href class="btn btn-link" ng-click="vm.chooseSource(vm.query)">
|
||||
{{vm.query.source.name}}
|
||||
@@ -91,7 +91,7 @@
|
||||
<i class="icon-add"></i>
|
||||
</a>
|
||||
|
||||
<a href ng-if="vm.query.filters.length > 1" ng-click="vm.trashFilter(vm.query)">
|
||||
<a href ng-click="vm.trashFilter(vm.query)">
|
||||
<i class="icon-trash"></i>
|
||||
</a>
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
|
||||
<div class="query-items">
|
||||
|
||||
<span<localize key="template_orderBy">order by</localize></span>
|
||||
<span><localize key="template_orderBy">order by</localize></span>
|
||||
|
||||
<div class="btn-group">
|
||||
<a class="btn btn-link dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
@@ -119,7 +119,7 @@
|
||||
</div>
|
||||
|
||||
<a href class="btn" ng-click="vm.changeSortOrder(vm.query)">
|
||||
{{vm.query.sort.direction}}
|
||||
{{vm.query.sort.translation.currentLabel}}
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,71 +1,59 @@
|
||||
<div ng-controller="Umbraco.Overlays.TemplateSectionsOverlay as vm">
|
||||
|
||||
<div ng-if="!model.hasMaster" class="umb-insert-code-box" ng-click="vm.select('renderBody')">
|
||||
<div class="umb-insert-code-box" ng-click="vm.select('renderBody')">
|
||||
<div class="umb-insert-code-box__check" ng-class="{'umb-insert-code-box__check--checked': model.insertType === 'renderBody' }"><i class="icon icon-check"></i></div>
|
||||
|
||||
<div class="umb-insert-code-box__title">Render child template</div>
|
||||
<div class="umb-insert-code-box__title"><localize key="template_renderBody" /></div>
|
||||
|
||||
<div class="umb-insert-code-box__description">
|
||||
Renders the contents of a child template, by inserting a
|
||||
<code>@RenderBody()</code> placeholder.
|
||||
<localize key="template_renderBodyDesc" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="!model.hasMaster" class="umb-insert-code-box" ng-click="vm.select('renderSection')">
|
||||
<div class="umb-insert-code-box" ng-click="vm.select('renderSection')">
|
||||
|
||||
<div class="umb-insert-code-box__check" ng-class="{'umb-insert-code-box__check--checked': model.insertType === 'renderSection' }"><i class="icon icon-check"></i></div>
|
||||
<div class="umb-insert-code-box__title">Render a named section</div>
|
||||
<div class="umb-insert-code-box__title"><localize key="template_renderSection" /></div>
|
||||
<div class="umb-insert-code-box__description">
|
||||
Renders a named area of a child template, by insert a <code>@RenderSection(name)</code> placeholder.
|
||||
This renders an area of a child template which is wrapped in a corresponding <code>@section [name]{ ... }</code> definition.
|
||||
<localize key="template_renderSectionDesc" />
|
||||
</div>
|
||||
|
||||
<div ng-if="model.insertType === 'renderSection'" style="margin-top: 20px;">
|
||||
<div style="margin-bottom: 20px;">
|
||||
<label class="bold">Section name <span class="red">*</span></label>
|
||||
<label class="bold"><localize key="template_sectionName" /> <span class="red">*</span></label>
|
||||
<input type="text" name="renderSectionName" class="-full-width-input" ng-model="model.renderSectionName" required umb-auto-focus />
|
||||
<small class="red" val-msg-for="renderSectionName" val-toggle-msg="required"><localize key="required" /></small>
|
||||
<div class="umb-insert-code-box__description">
|
||||
Set the name of the section to render in this area of the template
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label>
|
||||
<input type="checkbox" ng-model="model.mandatoryRenderSection" />
|
||||
Make section mandatory
|
||||
<input type="checkbox" ng-model="model.mandatoryRenderSection" /> <localize key="template_sectionMandatory" />
|
||||
</label>
|
||||
|
||||
<div class="umb-insert-code-box__description">
|
||||
If mandatory, the child template must contain a <code>@section</code> definition, otherwise an error is shown.
|
||||
<localize key="template_sectionMandatoryDesc" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div ng-if="model.hasMaster" class="umb-insert-code-box" ng-click="vm.select('addSection')">
|
||||
<div class="umb-insert-code-box" ng-click="vm.select('addSection')">
|
||||
|
||||
<div class="umb-insert-code-box__check" ng-class="{'umb-insert-code-box__check--checked': model.insertType === 'addSection' }"><i class="icon icon-check"></i></div>
|
||||
<div class="umb-insert-code-box__title">Define a named section</div>
|
||||
<div class="umb-insert-code-box__title"><localize key="template_defineSection" /></div>
|
||||
<div class="umb-insert-code-box__description">
|
||||
Defines a part of your template as a named section by wrapping it in
|
||||
a <code>@section { ... }</code>. This can be rendered in a
|
||||
specific area of the master of this template, by using <code>@RenderSection</code>.
|
||||
<localize key="template_defineSectionDesc" />
|
||||
</div>
|
||||
|
||||
<div ng-if="model.insertType === 'addSection'" style="margin-top: 20px;">
|
||||
<div>
|
||||
<label class="bold">Section name <span class="red">*</span></label>
|
||||
<label class="bold"><localize key="template_sectionName" /> <span class="red">*</span></label>
|
||||
<input type="text" name="sectionName" class="-full-width-input" ng-model="model.sectionName" required umb-auto-focus />
|
||||
<small class="red" val-msg-for="sectionName" val-toggle-msg="required"><localize key="required" /></small>
|
||||
<div class="umb-insert-code-box__description">
|
||||
Give the section a name
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
@@ -1,5 +1,5 @@
|
||||
<ul class="nav nav-tabs umb-nav-tabs">
|
||||
<li ng-class="{'tab-error': tabHasError}" ng-repeat="tab in model" val-tab>
|
||||
<a data-toggle="tab" href="#tab{{tab.id}}">{{ tab.label }}</a>
|
||||
<a data-toggle="tab" href="#tab{{tab.id}}{{idSuffix}}">{{ tab.label }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
<div class="umb-node-preview" ng-class="{'umb-node-preview--sortable': sortable, 'umb-node-preview--unpublished': published === false }">
|
||||
<i ng-if="icon" class="umb-node-preview__icon {{ icon }}"></i>
|
||||
<div class="umb-node-preview__content">
|
||||
<div class="umb-node-preview__name">{{ name }}</div>
|
||||
<div ng-if="description" class="umb-node-preview__description">{{ description }}</div>
|
||||
</div>
|
||||
<div class="umb-node-preview__actions">
|
||||
<a class="umb-node-preview__action" title="Open" href="" ng-if="allowOpen" ng-click="onOpen()">Open</a>
|
||||
<a class="umb-node-preview__action" title="Remove" href="" ng-if="allowRemove" ng-click="onRemove()">Remove</i></a>
|
||||
<div>
|
||||
|
||||
</div>
|
||||
@@ -34,18 +34,24 @@
|
||||
fields: {},
|
||||
file: file
|
||||
}).progress(function (evt) {
|
||||
|
||||
// hack: in some browsers the progress event is called after success
|
||||
// this prevents the UI from going back to a uploading state
|
||||
if(vm.zipFile.uploadStatus !== "done" && vm.zipFile.uploadStatus !== "error") {
|
||||
|
||||
// set view state to uploading
|
||||
vm.state = 'uploading';
|
||||
// set view state to uploading
|
||||
vm.state = 'uploading';
|
||||
|
||||
// calculate progress in percentage
|
||||
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total, 10);
|
||||
// calculate progress in percentage
|
||||
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total, 10);
|
||||
|
||||
// set percentage property on file
|
||||
vm.zipFile.uploadProgress = progressPercentage;
|
||||
// set percentage property on file
|
||||
vm.zipFile.uploadProgress = progressPercentage;
|
||||
|
||||
// set uploading status on file
|
||||
vm.zipFile.uploadStatus = "uploading";
|
||||
// set uploading status on file
|
||||
vm.zipFile.uploadStatus = "uploading";
|
||||
|
||||
}
|
||||
|
||||
}).success(function (data, status, headers, config) {
|
||||
|
||||
|
||||
@@ -12,8 +12,8 @@
|
||||
<div class="umb-package-list__item" ng-repeat="installedPackage in vm.installedPackages">
|
||||
|
||||
<div class="umb-package-list__item-icon">
|
||||
<i ng-if="!installedPackage.icon" class="icon-box"></i>
|
||||
<img ng-if="installedPackage.icon" ng-src="{{installedPackage.icon}}" />
|
||||
<i ng-if="!installedPackage.iconUrl" class="icon-box"></i>
|
||||
<img ng-if="installedPackage.iconUrl" ng-src="{{installedPackage.iconUrl}}" />
|
||||
</div>
|
||||
|
||||
<div class="umb-package-list__item-content">
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//this controller simply tells the dialogs service to open a mediaPicker window
|
||||
//with a specified callback, this callback will receive an object with a selection on it
|
||||
|
||||
function contentPickerController($scope, dialogService, entityResource, editorState, $log, iconHelper, $routeParams, fileManager, contentEditingHelper, angularHelper, navigationService, $location) {
|
||||
function contentPickerController($scope, entityResource, editorState, iconHelper, $routeParams, angularHelper, navigationService, $location, miniEditorHelper) {
|
||||
|
||||
function trim(str, chr) {
|
||||
var rgxtrim = (!chr) ? new RegExp('^\\s+|\\s+$', 'g') : new RegExp('^' + chr + '+|' + chr + '+$', 'g');
|
||||
@@ -39,6 +39,9 @@ function contentPickerController($scope, dialogService, entityResource, editorSt
|
||||
else {
|
||||
$scope.contentPickerForm.maxCount.$setValidity("maxCount", true);
|
||||
}
|
||||
|
||||
setSortingState($scope.renderModel);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@@ -59,6 +62,14 @@ function contentPickerController($scope, dialogService, entityResource, editorSt
|
||||
}
|
||||
};
|
||||
|
||||
// sortable options
|
||||
$scope.sortableOptions = {
|
||||
distance: 10,
|
||||
tolerance: "pointer",
|
||||
scroll: true,
|
||||
zIndex: 6000
|
||||
};
|
||||
|
||||
if ($scope.model.config) {
|
||||
//merge the server config on top of the default config, then set the server config to use the result
|
||||
$scope.model.config = angular.extend(defaultConfig, $scope.model.config);
|
||||
@@ -75,8 +86,9 @@ function contentPickerController($scope, dialogService, entityResource, editorSt
|
||||
: $scope.model.config.startNode.type === "media"
|
||||
? "Media"
|
||||
: "Document";
|
||||
$scope.allowOpenButton = entityType === "Document" || entityType === "Media";
|
||||
$scope.allowOpenButton = entityType === "Document";
|
||||
$scope.allowEditButton = entityType === "Document";
|
||||
$scope.allowRemoveButton = true;
|
||||
|
||||
//the dialog options for the picker
|
||||
var dialogOptions = {
|
||||
@@ -192,14 +204,26 @@ function contentPickerController($scope, dialogService, entityResource, editorSt
|
||||
});
|
||||
|
||||
if (currIds.indexOf(item.id) < 0) {
|
||||
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
|
||||
$scope.renderModel.push({ name: item.name, id: item.id, icon: item.icon, path: item.path });
|
||||
setEntityUrl(item);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.clear = function () {
|
||||
$scope.renderModel = [];
|
||||
};
|
||||
|
||||
$scope.openMiniEditor = function(node) {
|
||||
miniEditorHelper.launchMiniEditor(node).then(function(updatedNode){
|
||||
// update the node
|
||||
node.name = updatedNode.name;
|
||||
node.published = updatedNode.hasPublishedVersion;
|
||||
if(entityType !== "Member") {
|
||||
entityResource.getUrl(updatedNode.id, entityType).then(function(data){
|
||||
node.url = data;
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
|
||||
var currIds = _.map($scope.renderModel, function (i) {
|
||||
@@ -215,26 +239,89 @@ function contentPickerController($scope, dialogService, entityResource, editorSt
|
||||
|
||||
//load current data
|
||||
var modelIds = $scope.model.value ? $scope.model.value.split(',') : [];
|
||||
|
||||
entityResource.getByIds(modelIds, entityType).then(function (data) {
|
||||
|
||||
//Ensure we populate the render model in the same order that the ids were stored!
|
||||
_.each(modelIds, function (id, i) {
|
||||
var entity = _.find(data, function (d) {
|
||||
return d.id == id;
|
||||
});
|
||||
|
||||
|
||||
if (entity) {
|
||||
entity.icon = iconHelper.convertFromLegacyIcon(entity.icon);
|
||||
$scope.renderModel.push({ name: entity.name, id: entity.id, icon: entity.icon, path: entity.path });
|
||||
setEntityUrl(entity);
|
||||
}
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
//everything is loaded, start the watch on the model
|
||||
startWatch();
|
||||
|
||||
});
|
||||
|
||||
function setEntityUrl(entity) {
|
||||
|
||||
// get url for content and media items
|
||||
if(entityType !== "Member") {
|
||||
entityResource.getUrl(entity.id, entityType).then(function(data){
|
||||
// update url
|
||||
angular.forEach($scope.renderModel, function(item){
|
||||
if(item.id === entity.id) {
|
||||
item.url = data;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// add the selected item to the renderModel
|
||||
// if it needs to show a url the item will get
|
||||
// updated when the url comes back from server
|
||||
addSelectedItem(entity);
|
||||
|
||||
}
|
||||
|
||||
function addSelectedItem(item) {
|
||||
|
||||
// set icon
|
||||
if(item.icon) {
|
||||
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
|
||||
}
|
||||
|
||||
// set default icon
|
||||
if (!item.icon) {
|
||||
switch (entityType) {
|
||||
case "Document":
|
||||
item.icon = "icon-document";
|
||||
break;
|
||||
case "Media":
|
||||
item.icon = "icon-picture";
|
||||
break;
|
||||
case "Member":
|
||||
item.icon = "icon-user";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$scope.renderModel.push({
|
||||
"name": item.name,
|
||||
"id": item.id,
|
||||
"icon": item.icon,
|
||||
"path": item.path,
|
||||
"url": item.url,
|
||||
"published": (item.metaData && item.metaData.IsPublished === false && entityType === "Document") ? false : true
|
||||
// only content supports published/unpublished content so we set everything else to published so the UI looks correct
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function setSortingState(items) {
|
||||
// disable sorting if the list only consist of one item
|
||||
if(items.length > 1) {
|
||||
$scope.sortableOptions.disabled = false;
|
||||
} else {
|
||||
$scope.sortableOptions.disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
angular.module('umbraco').controller("Umbraco.PropertyEditors.ContentPickerController", contentPickerController);
|
||||
|
||||
@@ -2,32 +2,28 @@
|
||||
|
||||
<ng-form name="contentPickerForm">
|
||||
|
||||
<ul class="unstyled list-icons"
|
||||
ui-sortable
|
||||
ng-model="renderModel">
|
||||
<li ng-repeat="node in renderModel" ng-attr-title="{{model.config.showPathOnHover && 'Path: ' + node.path || undefined}}">
|
||||
<i class="icon icon-navigation handle"></i>
|
||||
<a href="#" prevent-default ng-click="remove($index)">
|
||||
<i class="icon icon-delete red hover-show"></i>
|
||||
<i class="{{node.icon}} hover-hide"></i>
|
||||
{{node.name}}
|
||||
</a>
|
||||
|
||||
<div ng-if="!dialogEditor && ((model.config.showOpenButton && allowOpenButton) || (model.config.showEditButton && allowEditButton))">
|
||||
<small ng-if="model.config.showOpenButton && allowOpenButton"><a href ng-click="showNode($index)"><localize key="open">Open</localize></a></small>
|
||||
<small ng-if="model.config.showEditButton && allowEditButton"><a href umb-launch-mini-editor="node"><localize key="edit">Edit</localize></a></small>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="unstyled list-icons" ng-show="model.config.multiPicker === true || renderModel.length === 0">
|
||||
<li>
|
||||
<i class="icon icon-add blue"></i>
|
||||
<a href="#" ng-click="openContentPicker()" prevent-default>
|
||||
<localize key="general_add">Add</localize>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div ui-sortable="sortableOptions" ng-model="renderModel">
|
||||
<umb-node-preview
|
||||
ng-repeat="node in renderModel"
|
||||
icon="node.icon"
|
||||
name="node.name"
|
||||
published="node.published"
|
||||
description="node.url"
|
||||
sortable="!sortableOptions.disabled"
|
||||
allow-remove="allowRemoveButton"
|
||||
allow-open="model.config.showOpenButton && allowOpenButton && !dialogEditor"
|
||||
on-remove="remove($index)"
|
||||
on-open="openMiniEditor(node)">
|
||||
</umb-node-preview>
|
||||
</div>
|
||||
|
||||
<a ng-show="model.config.multiPicker === true || renderModel.length === 0"
|
||||
class="umb-node-preview-add"
|
||||
href=""
|
||||
ng-click="openContentPicker()"
|
||||
prevent-default>
|
||||
<localize key="general_add">Add</localize>
|
||||
</a>
|
||||
|
||||
<!--These are here because we need ng-form fields to validate against-->
|
||||
<input type="hidden" name="minCount" ng-model="renderModel" />
|
||||
|
||||
@@ -2,7 +2,7 @@ angular.module("umbraco")
|
||||
.controller("Umbraco.PropertyEditors.GoogleMapsController",
|
||||
function ($element, $rootScope, $scope, notificationsService, dialogService, assetsService, $log, $timeout) {
|
||||
|
||||
assetsService.loadJs('http://www.google.com/jsapi')
|
||||
assetsService.loadJs('https://www.google.com/jsapi')
|
||||
.then(function () {
|
||||
google.load("maps", "3",
|
||||
{
|
||||
|
||||
@@ -8,6 +8,7 @@ function memberGroupPicker($scope, dialogService){
|
||||
}
|
||||
|
||||
$scope.renderModel = [];
|
||||
$scope.allowRemove = true;
|
||||
|
||||
if ($scope.model.value) {
|
||||
var modelIds = $scope.model.value.split(',');
|
||||
|
||||
@@ -1,27 +1,22 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.MemberGroupPickerController" class="umb-editor umb-membergrouppicker">
|
||||
|
||||
<div ng-model="renderModel">
|
||||
<umb-node-preview
|
||||
ng-repeat="node in renderModel"
|
||||
icon="node.icon"
|
||||
name="node.name"
|
||||
allow-remove="allowRemove"
|
||||
on-remove="remove($index)">
|
||||
</umb-node-preview>
|
||||
</div>
|
||||
|
||||
<ul class="unstyled"
|
||||
ng-model="renderModel">
|
||||
<li ng-repeat="node in renderModel">
|
||||
|
||||
|
||||
|
||||
<a href="#" prevent-default ng-click="remove($index)">
|
||||
<i class="icon icon-delete red hover-show"></i>
|
||||
<i class="{{node.icon}} hover-hide"></i>
|
||||
{{node.name}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="unstyled">
|
||||
<li>
|
||||
<a href="#" ng-click="openMemberGroupPicker()" prevent-default>
|
||||
<i class="icon icon-add blue"></i> <localize key="general_add">Add</localize>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<a
|
||||
class="umb-node-preview-add"
|
||||
href="#"
|
||||
ng-click="openMemberGroupPicker()"
|
||||
prevent-default>
|
||||
<localize key="general_add">Add</localize>
|
||||
</a>
|
||||
|
||||
<umb-overlay
|
||||
ng-if="memberGroupPicker.show"
|
||||
|
||||
@@ -8,6 +8,7 @@ function memberPickerController($scope, dialogService, entityResource, $log, ico
|
||||
}
|
||||
|
||||
$scope.renderModel = [];
|
||||
$scope.allowRemove = true;
|
||||
|
||||
var dialogOptions = {
|
||||
multiPicker: false,
|
||||
@@ -96,7 +97,8 @@ function memberPickerController($scope, dialogService, entityResource, $log, ico
|
||||
var modelIds = $scope.model.value ? $scope.model.value.split(',') : [];
|
||||
entityResource.getByIds(modelIds, "Member").then(function (data) {
|
||||
_.each(data, function (item, i) {
|
||||
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
|
||||
// set default icon if it's missing
|
||||
item.icon = (item.icon) ? iconHelper.convertFromLegacyIcon(item.icon) : "icon-user";
|
||||
$scope.renderModel.push({ name: item.name, id: item.id, icon: item.icon });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,27 +1,22 @@
|
||||
<div ng-controller="Umbraco.PropertyEditors.MemberPickerController" class="umb-editor umb-memberpicker">
|
||||
|
||||
<ul class="unstyled list-icons"
|
||||
ng-model="renderModel">
|
||||
<li ng-repeat="node in renderModel">
|
||||
<div>
|
||||
<umb-node-preview
|
||||
ng-repeat="node in renderModel"
|
||||
icon="node.icon"
|
||||
name="node.name"
|
||||
allow-remove="allowRemove"
|
||||
on-remove="remove($index)">
|
||||
</umb-node-preview>
|
||||
</div>
|
||||
|
||||
<i class="icon icon-navigation handle"></i>
|
||||
|
||||
<a href="#" prevent-default ng-click="remove($index)">
|
||||
<i class="icon icon-delete red hover-show"></i>
|
||||
<i class="{{node.icon}} hover-hide"></i>
|
||||
{{node.name}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul class="unstyled list-icons" ng-show="model.config.multiPicker === true || renderModel.length === 0">
|
||||
<li>
|
||||
<i class="icon icon-add blue"></i>
|
||||
<a href="#" ng-click="openMemberPicker()" prevent-default>
|
||||
<localize key="general_add">Add</localize>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<a ng-show="model.config.multiPicker === true || renderModel.length === 0"
|
||||
class="umb-node-preview-add"
|
||||
href="#"
|
||||
ng-click="openMemberPicker()"
|
||||
prevent-default>
|
||||
<localize key="general_add">Add</localize>
|
||||
</a>
|
||||
|
||||
<umb-overlay
|
||||
ng-if="memberPickerOverlay.show"
|
||||
|
||||
@@ -229,7 +229,7 @@
|
||||
view: "macropicker",
|
||||
dialogData: {},
|
||||
show: true,
|
||||
title: "Insert macro",
|
||||
title: localizationService.localize("template_insertMacro"),
|
||||
submit: function (model) {
|
||||
|
||||
var macroObject = macroService.collectValueData(model.selectedMacro, model.macroParams, "Mvc");
|
||||
@@ -256,6 +256,7 @@
|
||||
closeButtonlabel: "Cancel",
|
||||
view: "insertfield",
|
||||
show: true,
|
||||
title: localizationService.localize("template_insertPageField"),
|
||||
submit: function (model) {
|
||||
insert(model.umbracoField);
|
||||
vm.pageFieldOverlay.show = false;
|
||||
@@ -280,7 +281,7 @@
|
||||
entityType: "dictionary",
|
||||
multiPicker: false,
|
||||
show: true,
|
||||
title: "Insert dictionary item",
|
||||
title: localizationService.localize("template_insertDictionaryItem"),
|
||||
select: function(node){
|
||||
var code = templateHelper.getInsertDictionarySnippet(node.name);
|
||||
insert(code);
|
||||
@@ -306,7 +307,7 @@
|
||||
entityType: "partialView",
|
||||
multiPicker: false,
|
||||
show: true,
|
||||
title: "Insert Partial view",
|
||||
title: localizationService.localize("template_insertPartialView"),
|
||||
select: function(node){
|
||||
|
||||
var code = templateHelper.getInsertPartialSnippet(node.name);
|
||||
@@ -329,7 +330,7 @@
|
||||
vm.queryBuilderOverlay = {
|
||||
view: "querybuilder",
|
||||
show: true,
|
||||
title: "Query for content",
|
||||
title: localizationService.localize("template_queryBuilder"),
|
||||
submit: function (model) {
|
||||
|
||||
var code = templateHelper.getQuerySnippet(model.result.queryExpression);
|
||||
@@ -354,7 +355,7 @@
|
||||
|
||||
vm.sectionsOverlay = {
|
||||
view: "templatesections",
|
||||
hasMaster: vm.template.masterTemplateAlias,
|
||||
isMaster: vm.template.isMasterTemplate,
|
||||
submitButtonLabel: "Insert",
|
||||
show: true,
|
||||
submit: function(model) {
|
||||
@@ -402,7 +403,7 @@
|
||||
|
||||
vm.masterTemplateOverlay = {
|
||||
view: "itempicker",
|
||||
title: "Choose master template",
|
||||
title: localizationService.localize("template_mastertemplate"),
|
||||
availableItems: availableMasterTemplates,
|
||||
show: true,
|
||||
submit: function(model) {
|
||||
@@ -444,23 +445,15 @@
|
||||
}
|
||||
|
||||
function getMasterTemplateName(masterTemplateAlias, templates) {
|
||||
|
||||
if(masterTemplateAlias) {
|
||||
|
||||
var templateName = "";
|
||||
|
||||
angular.forEach(templates, function(template){
|
||||
if(template.alias === masterTemplateAlias) {
|
||||
templateName = template.name;
|
||||
}
|
||||
});
|
||||
|
||||
return templateName;
|
||||
|
||||
} else {
|
||||
return "No master";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function removeMasterTemplate() {
|
||||
|
||||
@@ -33,7 +33,11 @@
|
||||
class="umb-era-button umb-button--s"
|
||||
ng-click="vm.openMasterTemplateOverlay()">
|
||||
<i class="icon icon-layout"></i>
|
||||
<span class="bold">Master template:</span> <span style="margin-left: 5px;">{{ vm.getMasterTemplateName(vm.template.masterTemplateAlias, vm.templates) }}</span>
|
||||
<span class="bold"><localize key="template_mastertemplate">Master template</localize>:</span>
|
||||
<span style="margin-left: 5px;">
|
||||
<span ng-if="vm.template.masterTemplateAlias">{{ vm.getMasterTemplateName(vm.template.masterTemplateAlias, vm.templates) }}</span>
|
||||
<span ng-if="!vm.template.masterTemplateAlias"><localize key="template_noMaster">No master</localize></span>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<a ng-if="vm.template.masterTemplateAlias" ng-click="vm.removeMasterTemplate()" class="umb-era-button umb-button--s dropdown-toggle umb-button-group__toggle">
|
||||
@@ -62,7 +66,7 @@
|
||||
<li><a href="" ng-click="vm.openPageFieldOverlay()"><localize key="template_insertPageField">Value</localize></a></li>
|
||||
<li><a href="" ng-click="vm.openPartialOverlay()"><localize key="template_insertPartialView">Partial view</localize></a></li>
|
||||
<li><a href="" ng-click="vm.openDictionaryItemOverlay()"><localize key="template_insertDictionaryItem">Dictionary</localize></a></li>
|
||||
<li><a href="" ng-click="vm.openMacroOverlay()"><localize key="general_insertMacro">Macro</localize></a></li>
|
||||
<li><a href="" ng-click="vm.openMacroOverlay()"><localize key="template_insertMacro">Macro</localize></a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -17,7 +17,11 @@ describe('Content picker controller tests', function () {
|
||||
value:"1233,1231,23121",
|
||||
label: "My content picker",
|
||||
description: "desc",
|
||||
config: {}
|
||||
config: {
|
||||
startNode: {
|
||||
type: "content"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//this controller requires an angular form controller applied to it
|
||||
@@ -47,6 +51,12 @@ describe('Content picker controller tests', function () {
|
||||
}));
|
||||
|
||||
describe('content edit controller save and publish', function () {
|
||||
|
||||
var item = {
|
||||
name: "meh",
|
||||
id: 666,
|
||||
icon: "woop"
|
||||
};
|
||||
|
||||
it('should define the default properties on construction', function () {
|
||||
expect(scope.model.value).toNotBe(undefined);
|
||||
@@ -65,7 +75,6 @@ describe('Content picker controller tests', function () {
|
||||
});
|
||||
|
||||
it("Removing an item should update renderModel, ids and model.value", function(){
|
||||
|
||||
scope.remove(1);
|
||||
scope.$apply();
|
||||
expect(scope.renderModel.length).toBe(2);
|
||||
@@ -73,24 +82,29 @@ describe('Content picker controller tests', function () {
|
||||
});
|
||||
|
||||
it("Adding an item should update renderModel, ids and model.value", function(){
|
||||
|
||||
scope.add({name: "meh", id: 666, icon: "woop"});
|
||||
scope.add(item);
|
||||
scope.$apply();
|
||||
expect(scope.renderModel.length).toBe(4);
|
||||
expect(scope.model.value).toBe("1233,1231,23121,666");
|
||||
setTimeout(function(){
|
||||
expect(scope.renderModel.length).toBe(4);
|
||||
expect(scope.model.value).toBe("1233,1231,23121,666");
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
it("Adding a dublicate item should note update renderModel, ids and model.value", function(){
|
||||
|
||||
scope.add({ name: "meh", id: 666, icon: "woop" });
|
||||
it("Adding a duplicate item should note update renderModel, ids and model.value", function(){
|
||||
scope.add(item);
|
||||
scope.$apply();
|
||||
expect(scope.renderModel.length).toBe(4);
|
||||
expect(scope.model.value).toBe("1233,1231,23121,666");
|
||||
setTimeout(function(){
|
||||
expect(scope.renderModel.length).toBe(4);
|
||||
expect(scope.model.value).toBe("1233,1231,23121,666");
|
||||
}, 1000);
|
||||
|
||||
scope.add({ name: "meh 2", id: 666, icon: "woop 2" });
|
||||
scope.add(item);
|
||||
scope.$apply();
|
||||
expect(scope.renderModel.length).toBe(4);
|
||||
expect(scope.model.value).toBe("1233,1231,23121,666");
|
||||
setTimeout(function(){
|
||||
expect(scope.renderModel.length).toBe(4);
|
||||
expect(scope.model.value).toBe("1233,1231,23121,666");
|
||||
}, 1000);
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user