Compare commits
35 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 967ca3b200 | |||
| 5b4ef5b29e | |||
| 5da220c436 | |||
| ac9be3995b | |||
| ec139ca16c | |||
| 23e81a67fa | |||
| c7a5786521 | |||
| c0ec2a5314 | |||
| cd6585c9b9 | |||
| a1c4bd6b7a | |||
| ca85b0e45c | |||
| 48c5e61d88 | |||
| 933bb8ad44 | |||
| ab90690e17 | |||
| 67e0b68b7b | |||
| c50f7a1284 | |||
| 5ab978ecf5 | |||
| 16ceca1598 | |||
| 404055917f | |||
| 6a7b6f7267 | |||
| f738e6d7c7 | |||
| e818197365 | |||
| 1ffcc853e1 | |||
| 284e440b7e | |||
| 50597b5715 | |||
| 9d7519d591 | |||
| f35110309a | |||
| c73860d144 | |||
| 1842c78c5d | |||
| da39eb3ceb | |||
| baef12eb2a | |||
| 5389a018b3 | |||
| 00487c87fc | |||
| 44e76adbd1 | |||
| 01b3747956 |
@@ -3,37 +3,8 @@
|
||||
"browser": true
|
||||
},
|
||||
|
||||
"plugins": [
|
||||
"angular"
|
||||
],
|
||||
|
||||
"rules": {
|
||||
"eqeqeq": 2,
|
||||
"curly": 2,
|
||||
|
||||
"no-unused-vars": 1,
|
||||
"no-eval": 1,
|
||||
"no-delete-var": 1,
|
||||
"quotes": 1,
|
||||
"dot-notation": 1,
|
||||
|
||||
"no-use-before-define": 0,
|
||||
"angular/ng_controller_as": 1,
|
||||
"angular/ng_controller_as_vm": 1,
|
||||
|
||||
|
||||
"strict": 0,
|
||||
"no-irregular-whitespace": 0,
|
||||
"no-mixed-spaces-and-tabs": 0,
|
||||
"no-multi-spaces": 0,
|
||||
"key-spacing": 0,
|
||||
"semi-spacing": 0,
|
||||
"space-infix-ops": 0,
|
||||
"comma-spacing": 0,
|
||||
"no-trailing-spaces": 0,
|
||||
"eol-last": 0,
|
||||
"no-underscore-dangle": 0,
|
||||
"camelcase": 0
|
||||
"comma-dangle": ["error", "never"]
|
||||
},
|
||||
|
||||
"globals": {
|
||||
|
||||
@@ -12,6 +12,9 @@ const imagemin = require('gulp-imagemin');
|
||||
var _ = require('lodash');
|
||||
var MergeStream = require('merge-stream');
|
||||
|
||||
// js
|
||||
const eslint = require('gulp-eslint');
|
||||
|
||||
//Less + css
|
||||
var postcss = require('gulp-postcss');
|
||||
var less = require('gulp-less');
|
||||
@@ -30,6 +33,11 @@ Helper functions
|
||||
function processJs(files, out) {
|
||||
|
||||
return gulp.src(files)
|
||||
// check for js errors
|
||||
.pipe(eslint())
|
||||
// outputs the lint results to the console
|
||||
.pipe(eslint.format())
|
||||
// sort files in stream by path or any custom sort comparator
|
||||
.pipe(sort())
|
||||
.pipe(concat(out))
|
||||
.pipe(wrap('(function(){\n%= body %\n})();'))
|
||||
|
||||
+1376
-553
File diff suppressed because it is too large
Load Diff
@@ -27,6 +27,7 @@
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-concat": "^2.6.0",
|
||||
"gulp-connect": "5.0.0",
|
||||
"gulp-eslint": "^5.0.0",
|
||||
"gulp-imagemin": "^4.1.0",
|
||||
"gulp-less": "^3.5.0",
|
||||
"gulp-ngdocs": "^0.3.0",
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
#Obsolete directives
|
||||
|
||||
Folder contains directives we plan to remove in the next major version of umbraco (8.0) these are not recommended to use.
|
||||
@@ -1,40 +0,0 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:autoScale
|
||||
* @element div
|
||||
* @deprecated
|
||||
* We plan to remove this directive in the next major version of umbraco (8.0). The directive is not recommended to use.
|
||||
* @function
|
||||
* @description
|
||||
* Resize div's automatically to fit to the bottom of the screen, as an optional parameter an y-axis offset can be set
|
||||
* So if you only want to scale the div to 70 pixels from the bottom you pass "70"
|
||||
|
||||
* @example
|
||||
* <example module="umbraco.directives">
|
||||
* <file name="index.html">
|
||||
* <div auto-scale="70" class="input-block-level"></div>
|
||||
* </file>
|
||||
* </example>
|
||||
**/
|
||||
|
||||
angular.module("umbraco.directives")
|
||||
.directive('autoScale', function ($window) {
|
||||
return function (scope, el, attrs) {
|
||||
|
||||
var totalOffset = 0;
|
||||
var offsety = parseInt(attrs.autoScale, 10);
|
||||
var window = angular.element($window);
|
||||
if (offsety !== undefined){
|
||||
totalOffset += offsety;
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
el.height(window.height() - (el.offset().top + totalOffset));
|
||||
}, 500);
|
||||
|
||||
window.bind("resize", function () {
|
||||
el.height(window.height() - (el.offset().top + totalOffset));
|
||||
});
|
||||
|
||||
};
|
||||
});
|
||||
@@ -1,83 +0,0 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:detectFold
|
||||
* @deprecated
|
||||
* We plan to remove this directive in the next major version of umbraco (8.0). The directive is not recommended to use.
|
||||
* @description This is used for the editor buttons to ensure they are displayed correctly if the horizontal overflow of the editor
|
||||
* exceeds the height of the window
|
||||
**/
|
||||
|
||||
angular.module("umbraco.directives.html")
|
||||
.directive('detectFold', function ($timeout, $log, windowResizeListener) {
|
||||
return {
|
||||
require: "^?umbTabs",
|
||||
restrict: 'A',
|
||||
link: function (scope, el, attrs, tabsCtrl) {
|
||||
|
||||
var firstRun = false;
|
||||
var parent = $(".umb-panel-body");
|
||||
var winHeight = $(window).height();
|
||||
var calculate = function () {
|
||||
if (el && el.is(":visible") && !el.hasClass("umb-bottom-bar")) {
|
||||
|
||||
//now that the element is visible, set the flag in a couple of seconds,
|
||||
// this will ensure that loading time of a current tab get's completed and that
|
||||
// we eventually stop watching to save on CPU time
|
||||
$timeout(function() {
|
||||
firstRun = true;
|
||||
}, 4000);
|
||||
|
||||
//var parent = el.parent();
|
||||
var hasOverflow = parent.innerHeight() < parent[0].scrollHeight;
|
||||
//var belowFold = (el.offset().top + el.height()) > winHeight;
|
||||
if (hasOverflow) {
|
||||
el.addClass("umb-bottom-bar");
|
||||
|
||||
//I wish we didn't have to put this logic here but unfortunately we
|
||||
// do. This needs to calculate the left offest to place the bottom bar
|
||||
// depending on if the left column splitter has been moved by the user
|
||||
// (based on the nav-resize directive)
|
||||
var wrapper = $("#mainwrapper");
|
||||
var contentPanel = $("#leftcolumn").next();
|
||||
var contentPanelLeftPx = contentPanel.css("left");
|
||||
|
||||
el.css({ left: contentPanelLeftPx });
|
||||
}
|
||||
}
|
||||
return firstRun;
|
||||
};
|
||||
|
||||
var resizeCallback = function(size) {
|
||||
winHeight = size.height;
|
||||
el.removeClass("umb-bottom-bar");
|
||||
calculate();
|
||||
};
|
||||
|
||||
windowResizeListener.register(resizeCallback);
|
||||
|
||||
//Only execute the watcher if this tab is the active (first) tab on load, otherwise there's no reason to execute
|
||||
// the watcher since it will be recalculated when the tab changes!
|
||||
if (el.closest(".umb-tab-pane").index() === 0) {
|
||||
//run a watcher to ensure that the calculation occurs until it's firstRun but ensure
|
||||
// the calculations are throttled to save a bit of CPU
|
||||
var listener = scope.$watch(_.throttle(calculate, 1000), function (newVal, oldVal) {
|
||||
if (newVal !== oldVal) {
|
||||
listener();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//listen for tab changes
|
||||
if (tabsCtrl != null) {
|
||||
tabsCtrl.onTabShown(function (args) {
|
||||
calculate();
|
||||
});
|
||||
}
|
||||
|
||||
//ensure to unregister
|
||||
scope.$on('$destroy', function() {
|
||||
windowResizeListener.unregister(resizeCallback);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -1,69 +0,0 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:umbItemSorter
|
||||
* @deprecated
|
||||
* We plan to remove this directive in the next major version of umbraco (8.0). The directive is not recommended to use.
|
||||
* @function
|
||||
* @element ANY
|
||||
* @restrict E
|
||||
* @description A re-usable directive for sorting items
|
||||
**/
|
||||
|
||||
function umbItemSorter(angularHelper) {
|
||||
return {
|
||||
scope: {
|
||||
model: "="
|
||||
},
|
||||
restrict: "E", // restrict to an element
|
||||
replace: true, // replace the html element with the template
|
||||
templateUrl: 'views/directives/_obsolete/umb-item-sorter.html',
|
||||
link: function(scope, element, attrs, ctrl) {
|
||||
var defaultModel = {
|
||||
okButton: "Ok",
|
||||
successMsg: "Sorting successful",
|
||||
complete: false
|
||||
};
|
||||
//assign user vals to default
|
||||
angular.extend(defaultModel, scope.model);
|
||||
//re-assign merged to user
|
||||
scope.model = defaultModel;
|
||||
|
||||
scope.performSort = function() {
|
||||
scope.$emit("umbItemSorter.sorting", {
|
||||
sortedItems: scope.model.itemsToSort
|
||||
});
|
||||
};
|
||||
|
||||
scope.handleCancel = function () {
|
||||
scope.$emit("umbItemSorter.cancel");
|
||||
};
|
||||
|
||||
scope.handleOk = function() {
|
||||
scope.$emit("umbItemSorter.ok");
|
||||
};
|
||||
|
||||
//defines the options for the jquery sortable
|
||||
scope.sortableOptions = {
|
||||
axis: 'y',
|
||||
cursor: "move",
|
||||
placeholder: "ui-sortable-placeholder",
|
||||
update: function (ev, ui) {
|
||||
//highlight the item when the position is changed
|
||||
$(ui.item).effect("highlight", { color: "#049cdb" }, 500);
|
||||
},
|
||||
stop: function (ev, ui) {
|
||||
//the ui-sortable directive already ensures that our list is re-sorted, so now we just
|
||||
// need to update the sortOrder to the index of each item
|
||||
angularHelper.safeApply(scope, function () {
|
||||
angular.forEach(scope.itemsToSort, function (val, index) {
|
||||
val.sortOrder = index + 1;
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
angular.module('umbraco.directives').directive("umbItemSorter", umbItemSorter);
|
||||
@@ -1,92 +0,0 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:umbContentName
|
||||
* @deprecated
|
||||
* We plan to remove this directive in the next major version of umbraco (8.0). The directive is not recommended to use.
|
||||
* @restrict E
|
||||
* @function
|
||||
* @description
|
||||
* Used by editors that require naming an entity. Shows a textbox/headline with a required validator within it's own form.
|
||||
**/
|
||||
|
||||
angular.module("umbraco.directives")
|
||||
.directive('umbContentName', function ($timeout, localizationService) {
|
||||
return {
|
||||
require: "ngModel",
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'views/directives/_obsolete/umb-content-name.html',
|
||||
|
||||
scope: {
|
||||
placeholder: '@placeholder',
|
||||
model: '=ngModel',
|
||||
ngDisabled: '='
|
||||
},
|
||||
link: function(scope, element, attrs, ngModel) {
|
||||
|
||||
var inputElement = element.find("input");
|
||||
if(scope.placeholder && scope.placeholder[0] === "@"){
|
||||
localizationService.localize(scope.placeholder.substring(1))
|
||||
.then(function(value){
|
||||
scope.placeholder = value;
|
||||
});
|
||||
}
|
||||
|
||||
var mX, mY, distance;
|
||||
|
||||
function calculateDistance(elem, mouseX, mouseY) {
|
||||
|
||||
var cx = Math.max(Math.min(mouseX, elem.offset().left + elem.width()), elem.offset().left);
|
||||
var cy = Math.max(Math.min(mouseY, elem.offset().top + elem.height()), elem.offset().top);
|
||||
return Math.sqrt((mouseX - cx) * (mouseX - cx) + (mouseY - cy) * (mouseY - cy));
|
||||
}
|
||||
|
||||
var mouseMoveDebounce = _.throttle(function (e) {
|
||||
mX = e.pageX;
|
||||
mY = e.pageY;
|
||||
// not focused and not over element
|
||||
if (!inputElement.is(":focus") && !inputElement.hasClass("ng-invalid")) {
|
||||
// on page
|
||||
if (mX >= inputElement.offset().left) {
|
||||
distance = calculateDistance(inputElement, mX, mY);
|
||||
if (distance <= 155) {
|
||||
|
||||
distance = 1 - (100 / 150 * distance / 100);
|
||||
inputElement.css("border", "1px solid rgba(175,175,175, " + distance + ")");
|
||||
inputElement.css("background-color", "rgba(255,255,255, " + distance + ")");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}, 15);
|
||||
|
||||
$(document).bind("mousemove", mouseMoveDebounce);
|
||||
|
||||
$timeout(function(){
|
||||
if(!scope.model){
|
||||
scope.goEdit();
|
||||
}
|
||||
}, 100, false);
|
||||
|
||||
scope.goEdit = function(){
|
||||
scope.editMode = true;
|
||||
|
||||
$timeout(function () {
|
||||
inputElement.focus();
|
||||
}, 100, false);
|
||||
};
|
||||
|
||||
scope.exitEdit = function(){
|
||||
if(scope.model && scope.model !== ""){
|
||||
scope.editMode = false;
|
||||
}
|
||||
};
|
||||
|
||||
//unbind doc event!
|
||||
scope.$on('$destroy', function () {
|
||||
$(document).unbind("mousemove", mouseMoveDebounce);
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -1,64 +0,0 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:umbHeader
|
||||
* @deprecated
|
||||
* We plan to remove this directive in the next major version of umbraco (8.0). The directive is not recommended to use.
|
||||
* @restrict E
|
||||
* @function
|
||||
* @description
|
||||
* The header on an editor that contains tabs using bootstrap tabs - THIS IS OBSOLETE, use umbTabHeader instead
|
||||
**/
|
||||
|
||||
angular.module("umbraco.directives")
|
||||
.directive('umbHeader', function ($parse, $timeout) {
|
||||
return {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
transclude: 'true',
|
||||
templateUrl: 'views/directives/_obsolete/umb-header.html',
|
||||
//create a new isolated scope assigning a tabs property from the attribute 'tabs'
|
||||
//which is bound to the parent scope property passed in
|
||||
scope: {
|
||||
tabs: "="
|
||||
},
|
||||
link: function (scope, iElement, iAttrs) {
|
||||
|
||||
scope.showTabs = iAttrs.tabs ? true : false;
|
||||
scope.visibleTabs = [];
|
||||
|
||||
//since tabs are loaded async, we need to put a watch on them to determine
|
||||
// when they are loaded, then we can close the watch
|
||||
var tabWatch = scope.$watch("tabs", function (newValue, oldValue) {
|
||||
|
||||
angular.forEach(newValue, function(val, index){
|
||||
var tab = {id: val.id, label: val.label};
|
||||
scope.visibleTabs.push(tab);
|
||||
});
|
||||
|
||||
//don't process if we cannot or have already done so
|
||||
if (!newValue) {return;}
|
||||
if (!newValue.length || newValue.length === 0){return;}
|
||||
|
||||
//we need to do a timeout here so that the current sync operation can complete
|
||||
// and update the UI, then this will fire and the UI elements will be available.
|
||||
$timeout(function () {
|
||||
|
||||
//use bootstrap tabs API to show the first one
|
||||
iElement.find(".nav-tabs a:first").tab('show');
|
||||
|
||||
//enable the tab drop
|
||||
iElement.find('.nav-pills, .nav-tabs').tabdrop();
|
||||
|
||||
//ensure to destroy tabdrop (unbinds window resize listeners)
|
||||
scope.$on('$destroy', function () {
|
||||
iElement.find('.nav-pills, .nav-tabs').tabdrop("destroy");
|
||||
});
|
||||
|
||||
//stop watching now
|
||||
tabWatch();
|
||||
}, 200);
|
||||
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:umbLogin
|
||||
* @deprecated
|
||||
* We plan to remove this directive in the next major version of umbraco (8.0). The directive is not recommended to use.
|
||||
* @function
|
||||
* @element ANY
|
||||
* @restrict E
|
||||
**/
|
||||
|
||||
function loginDirective() {
|
||||
return {
|
||||
restrict: "E", // restrict to an element
|
||||
replace: true, // replace the html element with the template
|
||||
templateUrl: 'views/directives/_obsolete/umb-login.html'
|
||||
};
|
||||
}
|
||||
|
||||
angular.module('umbraco.directives').directive("umbLogin", loginDirective);
|
||||
@@ -1,49 +0,0 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:umbOptionsMenu
|
||||
* @deprecated
|
||||
* We plan to remove this directive in the next major version of umbraco (8.0). The directive is not recommended to use.
|
||||
* @function
|
||||
* @element ANY
|
||||
* @restrict E
|
||||
**/
|
||||
|
||||
angular.module("umbraco.directives")
|
||||
.directive('umbOptionsMenu', function ($injector, treeService, navigationService, umbModelMapper, appState) {
|
||||
return {
|
||||
scope: {
|
||||
currentSection: "@",
|
||||
currentNode: "="
|
||||
},
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'views/directives/_obsolete/umb-optionsmenu.html',
|
||||
link: function (scope, element, attrs, ctrl) {
|
||||
|
||||
//adds a handler to the context menu item click, we need to handle this differently
|
||||
//depending on what the menu item is supposed to do.
|
||||
scope.executeMenuItem = function (action) {
|
||||
navigationService.executeMenuAction(action, scope.currentNode, scope.currentSection);
|
||||
};
|
||||
|
||||
//callback method to go and get the options async
|
||||
scope.getOptions = function () {
|
||||
|
||||
if (!scope.currentNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
//when the options item is selected, we need to set the current menu item in appState (since this is synonymous with a menu)
|
||||
appState.setMenuState("currentNode", scope.currentNode);
|
||||
|
||||
if (!scope.actions) {
|
||||
treeService.getMenu({ treeNode: scope.currentNode })
|
||||
.then(function (data) {
|
||||
scope.actions = data.menuItems;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -1,70 +0,0 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:umbPhotoFolder
|
||||
* @deprecated
|
||||
* We plan to remove this directive in the next major version of umbraco (8.0). The directive is not recommended to use.
|
||||
* @restrict E
|
||||
**/
|
||||
|
||||
angular.module("umbraco.directives.html")
|
||||
.directive('umbPhotoFolder', function($compile, $log, $timeout, $filter, umbPhotoFolderHelper) {
|
||||
|
||||
return {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
require: '?ngModel',
|
||||
terminate: true,
|
||||
templateUrl: 'views/directives/_obsolete/umb-photo-folder.html',
|
||||
link: function(scope, element, attrs, ngModel) {
|
||||
|
||||
var lastWatch = null;
|
||||
|
||||
ngModel.$render = function() {
|
||||
if (ngModel.$modelValue) {
|
||||
|
||||
$timeout(function() {
|
||||
var photos = ngModel.$modelValue;
|
||||
|
||||
scope.clickHandler = scope.$eval(element.attr('on-click'));
|
||||
|
||||
|
||||
var imagesOnly = element.attr('images-only') === "true";
|
||||
|
||||
|
||||
var margin = element.attr('border') ? parseInt(element.attr('border'), 10) : 5;
|
||||
var startingIndex = element.attr('baseline') ? parseInt(element.attr('baseline'), 10) : 0;
|
||||
var minWidth = element.attr('min-width') ? parseInt(element.attr('min-width'), 10) : 420;
|
||||
var minHeight = element.attr('min-height') ? parseInt(element.attr('min-height'), 10) : 100;
|
||||
var maxHeight = element.attr('max-height') ? parseInt(element.attr('max-height'), 10) : 300;
|
||||
var idealImgPerRow = element.attr('ideal-items-per-row') ? parseInt(element.attr('ideal-items-per-row'), 10) : 5;
|
||||
var fixedRowWidth = Math.max(element.width(), minWidth);
|
||||
|
||||
scope.containerStyle = { width: fixedRowWidth + "px" };
|
||||
scope.rows = umbPhotoFolderHelper.buildGrid(photos, fixedRowWidth, maxHeight, startingIndex, minHeight, idealImgPerRow, margin, imagesOnly);
|
||||
|
||||
if (attrs.filterBy) {
|
||||
|
||||
//we track the watches that we create, we don't want to create multiple, so clear it
|
||||
// if it already exists before creating another.
|
||||
if (lastWatch) {
|
||||
lastWatch();
|
||||
}
|
||||
|
||||
//TODO: Need to debounce this so it doesn't filter too often!
|
||||
lastWatch = scope.$watch(attrs.filterBy, function (newVal, oldVal) {
|
||||
if (newVal && newVal !== oldVal) {
|
||||
var p = $filter('filter')(photos, newVal, false);
|
||||
scope.baseline = 0;
|
||||
var m = umbPhotoFolderHelper.buildGrid(p, fixedRowWidth, maxHeight, startingIndex, minHeight, idealImgPerRow, margin, imagesOnly);
|
||||
scope.rows = m;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}, 500); //end timeout
|
||||
} //end if modelValue
|
||||
|
||||
}; //end $render
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -1,172 +0,0 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:umbSort
|
||||
* @deprecated
|
||||
* We plan to remove this directive in the next major version of umbraco (8.0). The directive is not recommended to use.
|
||||
*
|
||||
* @element div
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* Resize div's automatically to fit to the bottom of the screen, as an optional parameter an y-axis offset can be set
|
||||
* So if you only want to scale the div to 70 pixels from the bottom you pass "70"
|
||||
*
|
||||
* @example
|
||||
* <example module="umbraco.directives">
|
||||
* <file name="index.html">
|
||||
* <div umb-sort="70" class="input-block-level"></div>
|
||||
* </file>
|
||||
* </example>
|
||||
**/
|
||||
|
||||
angular.module("umbraco.directives")
|
||||
.value('umbSortContextInternal',{})
|
||||
.directive('umbSort', function($log,umbSortContextInternal) {
|
||||
return {
|
||||
require: '?ngModel',
|
||||
link: function(scope, element, attrs, ngModel) {
|
||||
var adjustment;
|
||||
|
||||
var cfg = scope.$eval(element.attr('umb-sort')) || {};
|
||||
|
||||
scope.model = ngModel;
|
||||
|
||||
scope.opts = cfg;
|
||||
scope.opts.containerSelector= cfg.containerSelector || ".umb-" + cfg.group + "-container",
|
||||
scope.opts.nested= cfg.nested || true,
|
||||
scope.opts.drop= cfg.drop || true,
|
||||
scope.opts.drag= cfg.drag || true,
|
||||
scope.opts.clone = cfg.clone || "<li/>";
|
||||
scope.opts.mode = cfg.mode || "list";
|
||||
|
||||
scope.opts.itemSelectorFull = $.trim(scope.opts.itemPath + " " + scope.opts.itemSelector);
|
||||
|
||||
/*
|
||||
scope.opts.isValidTarget = function(item, container) {
|
||||
if(container.el.is(".umb-" + scope.opts.group + "-container")){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
*/
|
||||
|
||||
element.addClass("umb-sort");
|
||||
element.addClass("umb-" + cfg.group + "-container");
|
||||
|
||||
scope.opts.onDrag = function (item, position) {
|
||||
if(scope.opts.mode === "list"){
|
||||
item.css({
|
||||
left: position.left - adjustment.left,
|
||||
top: position.top - adjustment.top
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
scope.opts.onDrop = function (item, targetContainer, _super) {
|
||||
|
||||
if(scope.opts.mode === "list"){
|
||||
//list mode
|
||||
var clonedItem = $(scope.opts.clone).css({height: 0});
|
||||
item.after(clonedItem);
|
||||
clonedItem.animate({'height': item.height()});
|
||||
|
||||
item.animate(clonedItem.position(), function () {
|
||||
clonedItem.detach();
|
||||
_super(item);
|
||||
});
|
||||
}
|
||||
|
||||
var children = $(scope.opts.itemSelectorFull, targetContainer.el);
|
||||
var targetIndex = children.index(item);
|
||||
var targetScope = $(targetContainer.el[0]).scope();
|
||||
|
||||
|
||||
if(targetScope === umbSortContextInternal.sourceScope){
|
||||
if(umbSortContextInternal.sourceScope.opts.onSortHandler){
|
||||
var _largs = {
|
||||
oldIndex: umbSortContextInternal.sourceIndex,
|
||||
newIndex: targetIndex,
|
||||
scope: umbSortContextInternal.sourceScope
|
||||
};
|
||||
|
||||
umbSortContextInternal.sourceScope.opts.onSortHandler.call(this, item, _largs);
|
||||
}
|
||||
}else{
|
||||
|
||||
|
||||
if(targetScope.opts.onDropHandler){
|
||||
var args = {
|
||||
sourceScope: umbSortContextInternal.sourceScope,
|
||||
sourceIndex: umbSortContextInternal.sourceIndex,
|
||||
sourceContainer: umbSortContextInternal.sourceContainer,
|
||||
|
||||
targetScope: targetScope,
|
||||
targetIndex: targetIndex,
|
||||
targetContainer: targetContainer
|
||||
};
|
||||
|
||||
targetScope.opts.onDropHandler.call(this, item, args);
|
||||
}
|
||||
|
||||
if(umbSortContextInternal.sourceScope.opts.onReleaseHandler){
|
||||
var _args = {
|
||||
sourceScope: umbSortContextInternal.sourceScope,
|
||||
sourceIndex: umbSortContextInternal.sourceIndex,
|
||||
sourceContainer: umbSortContextInternal.sourceContainer,
|
||||
|
||||
targetScope: targetScope,
|
||||
targetIndex: targetIndex,
|
||||
targetContainer: targetContainer
|
||||
};
|
||||
|
||||
umbSortContextInternal.sourceScope.opts.onReleaseHandler.call(this, item, _args);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
scope.changeIndex = function(from, to){
|
||||
scope.$apply(function(){
|
||||
var i = ngModel.$modelValue.splice(from, 1)[0];
|
||||
ngModel.$modelValue.splice(to, 0, i);
|
||||
});
|
||||
};
|
||||
|
||||
scope.move = function(args){
|
||||
var from = args.sourceIndex;
|
||||
var to = args.targetIndex;
|
||||
|
||||
if(args.sourceContainer === args.targetContainer){
|
||||
scope.changeIndex(from, to);
|
||||
}else{
|
||||
scope.$apply(function(){
|
||||
var i = args.sourceScope.model.$modelValue.splice(from, 1)[0];
|
||||
args.targetScope.model.$modelvalue.splice(to,0, i);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
scope.opts.onDragStart = function (item, container, _super) {
|
||||
var children = $(scope.opts.itemSelectorFull, container.el);
|
||||
var offset = item.offset();
|
||||
|
||||
umbSortContextInternal.sourceIndex = children.index(item);
|
||||
umbSortContextInternal.sourceScope = $(container.el[0]).scope();
|
||||
umbSortContextInternal.sourceContainer = container;
|
||||
|
||||
//current.item = ngModel.$modelValue.splice(current.index, 1)[0];
|
||||
|
||||
var pointer = container.rootGroup.pointer;
|
||||
adjustment = {
|
||||
left: pointer.left - offset.left,
|
||||
top: pointer.top - offset.top
|
||||
};
|
||||
|
||||
_super(item, container);
|
||||
};
|
||||
|
||||
element.sortable( scope.opts );
|
||||
}
|
||||
};
|
||||
|
||||
});
|
||||
@@ -1,18 +0,0 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:umbTabView
|
||||
* @deprecated
|
||||
* We plan to remove this directive in the next major version of umbraco (8.0). The directive is not recommended to use.
|
||||
*
|
||||
* @restrict E
|
||||
**/
|
||||
|
||||
angular.module("umbraco.directives")
|
||||
.directive('umbTabView', function($timeout, $log){
|
||||
return {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
transclude: 'true',
|
||||
templateUrl: 'views/directives/_obsolete/umb-tab-view.html'
|
||||
};
|
||||
});
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:umbUploadDropzone
|
||||
* @deprecated
|
||||
* We plan to remove this directive in the next major version of umbraco (8.0). The directive is not recommended to use.
|
||||
*
|
||||
* @restrict E
|
||||
**/
|
||||
|
||||
angular.module("umbraco.directives.html")
|
||||
.directive('umbUploadDropzone', function(){
|
||||
return {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'views/directives/_obsolete/umb-upload-dropzone.html'
|
||||
};
|
||||
});
|
||||
+1
-1
@@ -103,7 +103,7 @@
|
||||
backdropOpacity: "=?",
|
||||
highlightElement: "=?",
|
||||
highlightPreventClick: "=?",
|
||||
disableEventsOnClick: "=?",
|
||||
disableEventsOnClick: "=?"
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ angular.module("umbraco.directives")
|
||||
var $container = element.find(".crop-container");
|
||||
|
||||
//default constraints for drag n drop
|
||||
var constraints = {left: {max: scope.dimensions.margin, min: scope.dimensions.margin}, top: {max: scope.dimensions.margin, min: scope.dimensions.margin}, };
|
||||
var constraints = {left: {max: scope.dimensions.margin, min: scope.dimensions.margin}, top: {max: scope.dimensions.margin, min: scope.dimensions.margin} };
|
||||
scope.constraints = constraints;
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -82,7 +82,7 @@ angular.module("umbraco.directives")
|
||||
|
||||
generateAliasTimeout = $timeout(function () {
|
||||
updateAlias = true;
|
||||
entityResource.getSafeAlias(encodeURIComponent(value), true).then(function (safeAlias) {
|
||||
entityResource.getSafeAlias(value, true).then(function (safeAlias) {
|
||||
if (updateAlias) {
|
||||
scope.alias = safeAlias.alias;
|
||||
}
|
||||
|
||||
+1
-1
@@ -17,7 +17,7 @@
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
transclude: true,
|
||||
templateUrl: 'views/components/umb-dropdown-item.html',
|
||||
templateUrl: 'views/components/umb-dropdown-item.html'
|
||||
};
|
||||
|
||||
return directive;
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@
|
||||
},
|
||||
stop: function(e, ui) {
|
||||
updateTabsSortOrder();
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
scope.sortableOptionsProperty = {
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* @ngdoc directive
|
||||
* @name umbraco.directives.directive:autoScale
|
||||
* @element div
|
||||
* @function
|
||||
* @description
|
||||
* Resize div's automatically to fit to the bottom of the screen, as an optional parameter an y-axis offset can be set
|
||||
* So if you only want to scale the div to 70 pixels from the bottom you pass "70"
|
||||
|
||||
* @example
|
||||
* <example module="umbraco.directives">
|
||||
* <file name="index.html">
|
||||
* <div auto-scale="70" class="input-block-level"></div>
|
||||
* </file>
|
||||
* </example>
|
||||
**/
|
||||
|
||||
angular.module("umbraco.directives")
|
||||
.directive('autoScale', function ($window, $timeout, windowResizeListener) {
|
||||
return function (scope, el, attrs) {
|
||||
|
||||
var totalOffset = 0;
|
||||
var offsety = parseInt(attrs.autoScale, 10);
|
||||
var window = angular.element($window);
|
||||
if (offsety !== undefined) {
|
||||
totalOffset += offsety;
|
||||
}
|
||||
|
||||
$timeout(function () {
|
||||
setElementSize();
|
||||
});
|
||||
|
||||
function setElementSize() {
|
||||
el.height(window.height() - (el.offset().top + totalOffset));
|
||||
}
|
||||
|
||||
var resizeCallback = function() {
|
||||
setElementSize();
|
||||
};
|
||||
|
||||
windowResizeListener.register(resizeCallback);
|
||||
|
||||
//ensure to unregister from all events and kill jquery plugins
|
||||
scope.$on('$destroy', function () {
|
||||
windowResizeListener.unregister(resizeCallback);
|
||||
});
|
||||
|
||||
};
|
||||
});
|
||||
@@ -333,6 +333,17 @@ function contentTypeResource($q, $http, umbRequestHelper, umbDataFormatter, loca
|
||||
notificationsService.error(value);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
import: function (file) {
|
||||
if (!file) {
|
||||
throw "file cannot be null";
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(umbRequestHelper.getApiUrl("contentTypeApiBaseUrl", "Import", { file: file })),
|
||||
"Failed to import document type " + file
|
||||
);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -7,6 +7,6 @@
|
||||
$http.get(url),
|
||||
'Failed to retrieve content types'
|
||||
);
|
||||
},
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -329,7 +329,7 @@ angular.module('umbraco.services').factory("editorState", function() {
|
||||
},
|
||||
set: function (value) {
|
||||
throw "Use editorState.set to set the value of the current entity";
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
return state;
|
||||
|
||||
@@ -443,7 +443,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
|
||||
"removeDateMonth",
|
||||
"removeDateDayNumber",
|
||||
"removeDateDay",
|
||||
"removeDateTime",
|
||||
"removeDateTime"
|
||||
], function (i) {
|
||||
return i === propName;
|
||||
});
|
||||
@@ -519,25 +519,32 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
|
||||
var allNewProps = this.getAllProps(savedVariant);
|
||||
|
||||
//check for changed properties of the content
|
||||
for (var p in allOrigProps) {
|
||||
var alias = allOrigProps[p].alias;
|
||||
for (var k = 0; k < allOrigProps.length; k++) {
|
||||
|
||||
var origProp = allOrigProps[k];
|
||||
var alias = origProp.alias;
|
||||
var newProp = getNewProp(alias, allNewProps);
|
||||
if (newProp && !_.isEqual(alias, newProp.value)) {
|
||||
if (newProp && !_.isEqual(origProp.value, newProp.value)) {
|
||||
|
||||
//they have changed so set the origContent prop to the new one
|
||||
var origVal = allOrigProps[p].value;
|
||||
allOrigProps[p].value = newProp.value;
|
||||
var origVal = origProp.value;
|
||||
|
||||
origProp.value = newProp.value;
|
||||
|
||||
//instead of having a property editor $watch their expression to check if it has
|
||||
// been updated, instead we'll check for the existence of a special method on their model
|
||||
// and just call it.
|
||||
if (angular.isFunction(allOrigProps[p].onValueChanged)) {
|
||||
if (angular.isFunction(origProp.onValueChanged)) {
|
||||
//send the newVal + oldVal
|
||||
allOrigProps[p].onValueChanged(allOrigProps[p].value, origVal);
|
||||
origProp.onValueChanged(origProp.value, origVal);
|
||||
}
|
||||
|
||||
changed.push(allOrigProps[p]);
|
||||
changed.push(origProp);
|
||||
}
|
||||
|
||||
}
|
||||
for (var p in allOrigProps) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -159,10 +159,18 @@ function formHelper(angularHelper, serverValidationManager, $timeout, notificati
|
||||
|
||||
//Check if this is for content properties - specific to content/media/member editors because those are special
|
||||
// user defined properties with custom controls.
|
||||
if (parts.length > 2 && parts[0] === "_Properties") {
|
||||
if (parts.length > 1 && parts[0] === "_Properties") {
|
||||
|
||||
var propertyAlias = parts[1];
|
||||
var culture = parts[2];
|
||||
|
||||
var culture = null;
|
||||
if (parts.length > 2) {
|
||||
culture = parts[2];
|
||||
//special check in case the string is formatted this way
|
||||
if (culture === "null") {
|
||||
culture = null;
|
||||
}
|
||||
}
|
||||
|
||||
//if it contains 3 '.' then we will wire it up to a property's html field
|
||||
if (parts.length > 3) {
|
||||
|
||||
@@ -506,7 +506,7 @@
|
||||
canDelete: _.contains(intersectPermissions, 'D'), //Magic Char = D
|
||||
canMove: _.contains(intersectPermissions, 'M'), //Magic Char = M
|
||||
canPublish: _.contains(intersectPermissions, 'U'), //Magic Char = U
|
||||
canUnpublish: _.contains(intersectPermissions, 'U'), //Magic Char = Z (however UI says it can't be set, so if we can publish 'U' we can unpublish)
|
||||
canUnpublish: _.contains(intersectPermissions, 'U') //Magic Char = Z (however UI says it can't be set, so if we can publish 'U' we can unpublish)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -602,7 +602,7 @@ function navigationService($rootScope, $route, $routeParams, $log, $location, $q
|
||||
|
||||
//These will show up on the dialog controller's $scope under dialogOptions
|
||||
currentNode: args.node,
|
||||
currentAction: args.action,
|
||||
currentAction: args.action
|
||||
});
|
||||
|
||||
//save the currently assigned dialog so it can be removed before a new one is created
|
||||
@@ -623,7 +623,7 @@ function navigationService($rootScope, $route, $routeParams, $log, $location, $q
|
||||
setMode("default");
|
||||
|
||||
if(showMenu){
|
||||
this.showMenu(undefined, { skipDefault: true, node: appState.getMenuState("currentNode") });
|
||||
this.showMenu({ skipDefault: true, node: appState.getMenuState("currentNode") });
|
||||
}
|
||||
},
|
||||
/**
|
||||
|
||||
@@ -140,8 +140,9 @@ function serverValidationManager($timeout) {
|
||||
}
|
||||
}
|
||||
else if (propertyAlias !== undefined) {
|
||||
//normalize culture to null
|
||||
if (!culture) {
|
||||
culture = null; // if empty or null, always make null
|
||||
culture = null;
|
||||
}
|
||||
//don't add it if it already exists
|
||||
var exists2 = _.find(callbacks, function (item) {
|
||||
@@ -165,8 +166,9 @@ function serverValidationManager($timeout) {
|
||||
}
|
||||
else if (propertyAlias !== undefined) {
|
||||
|
||||
//normalize culture to null
|
||||
if (!culture) {
|
||||
culture = null; // if empty or null, always make null
|
||||
culture = null;
|
||||
}
|
||||
|
||||
//remove all callbacks for the content property
|
||||
@@ -192,8 +194,9 @@ function serverValidationManager($timeout) {
|
||||
*/
|
||||
getPropertyCallbacks: function (propertyAlias, culture, fieldName) {
|
||||
|
||||
//normalize culture to null
|
||||
if (!culture) {
|
||||
culture = null; // if empty or null, always make null
|
||||
culture = null;
|
||||
}
|
||||
|
||||
var found = _.filter(callbacks, function (item) {
|
||||
@@ -268,8 +271,9 @@ function serverValidationManager($timeout) {
|
||||
return;
|
||||
}
|
||||
|
||||
//normalize culture to null
|
||||
if (!culture) {
|
||||
culture = null; // if empty or null, always make null
|
||||
culture = null;
|
||||
}
|
||||
|
||||
//only add the item if it doesn't exist
|
||||
@@ -306,6 +310,12 @@ function serverValidationManager($timeout) {
|
||||
if (!propertyAlias) {
|
||||
return;
|
||||
}
|
||||
|
||||
//normalize culture to null
|
||||
if (!culture) {
|
||||
culture = null;
|
||||
}
|
||||
|
||||
//remove the item
|
||||
this.items = _.reject(this.items, function (item) {
|
||||
return (item.propertyAlias === propertyAlias && item.culture === culture && (item.fieldName === fieldName || (fieldName === undefined || fieldName === "")));
|
||||
@@ -354,6 +364,12 @@ function serverValidationManager($timeout) {
|
||||
* Gets the error message for the content property
|
||||
*/
|
||||
getPropertyError: function (propertyAlias, culture, fieldName) {
|
||||
|
||||
//normalize culture to null
|
||||
if (!culture) {
|
||||
culture = null;
|
||||
}
|
||||
|
||||
var err = _.find(this.items, function (item) {
|
||||
//return true if the property alias matches and if an empty field name is specified or the field name matches
|
||||
return (item.propertyAlias === propertyAlias && item.culture === culture && (item.fieldName === fieldName || (fieldName === undefined || fieldName === "")));
|
||||
@@ -388,6 +404,12 @@ function serverValidationManager($timeout) {
|
||||
* Checks if the content property + culture + field name combo has an error
|
||||
*/
|
||||
hasPropertyError: function (propertyAlias, culture, fieldName) {
|
||||
|
||||
//normalize culture to null
|
||||
if (!culture) {
|
||||
culture = null;
|
||||
}
|
||||
|
||||
var err = _.find(this.items, function (item) {
|
||||
//return true if the property alias matches and if an empty field name is specified or the field name matches
|
||||
return (item.propertyAlias === propertyAlias && item.culture === culture && (item.fieldName === fieldName || (fieldName === undefined || fieldName === "")));
|
||||
|
||||
@@ -75,7 +75,6 @@
|
||||
@import "listview.less";
|
||||
@import "gridview.less";
|
||||
@import "footer.less";
|
||||
@import "dragdrop.less";
|
||||
@import "dashboards.less";
|
||||
|
||||
@import "forms/umb-validation-label.less";
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
body.dragging, body.dragging * {
|
||||
cursor: move !important;
|
||||
}
|
||||
|
||||
li.dragged {
|
||||
position: absolute;
|
||||
opacity: 0.5;
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
.umb-sort li{
|
||||
display: block;
|
||||
margin: 5px;
|
||||
padding: 5px;
|
||||
border: 1px solid @gray-7;
|
||||
background: @gray-10;
|
||||
}
|
||||
|
||||
.umb-sort .placeholder {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.umb-sort .placeholder:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
width: 0;
|
||||
height: 0;
|
||||
margin-top: -5px;
|
||||
left: -5px;
|
||||
top: -4px;
|
||||
border: 5px solid transparent;
|
||||
border-left-color: @red;
|
||||
border-right: none;
|
||||
}
|
||||
@@ -496,21 +496,6 @@ input[type="checkbox"][readonly] {
|
||||
border-color: @red-l1 !important;
|
||||
}
|
||||
|
||||
//disable the glowing border for the umb-content-name
|
||||
.show-validation .umb-headline-editor-wrapper input:focus:invalid,
|
||||
.show-validation .umb-headline-editor-wrapper textarea:focus:invalid,
|
||||
.show-validation .umb-headline-editor-wrapper select:focus:invalid {
|
||||
border:none;
|
||||
color:inherit;
|
||||
border-color:inherit;
|
||||
@shadow:inherit;
|
||||
.box-shadow(@shadow);
|
||||
}
|
||||
|
||||
.ng-invalid > .umb-headline-editor-wrapper h1{
|
||||
border-bottom: 1px dashed @red; color: @red; cursor: pointer;
|
||||
};
|
||||
|
||||
// FORM ACTIONS
|
||||
// ------------
|
||||
|
||||
|
||||
@@ -80,18 +80,6 @@
|
||||
background-color: @white;
|
||||
}
|
||||
|
||||
.umb-headline-editor-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.umb-headline-editor-wrapper .help-inline {
|
||||
right: 0px;
|
||||
top: 25px;
|
||||
position: absolute;
|
||||
font-size: 10px;
|
||||
color: @red;
|
||||
}
|
||||
|
||||
.umb-panel-header p {
|
||||
margin: 0px 20px;
|
||||
}
|
||||
@@ -100,36 +88,6 @@
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.umb-headline-editor-wrapper input {
|
||||
background: none;
|
||||
border: none;
|
||||
margin: -6px 0 0 0;
|
||||
padding: 0 0 2px 0;
|
||||
border-radius: 0;
|
||||
line-height: normal;
|
||||
border: 1px solid transparent;
|
||||
color: @black;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
.umb-headline-editor-wrapper input.ng-invalid {
|
||||
color: @red;
|
||||
}
|
||||
|
||||
.umb-headline-editor-wrapper input.ng-invalid::-moz-placeholder,
|
||||
.umb-headline-editor-wrapper input.ng-invalid:-ms-input-placeholder,
|
||||
.umb-headline-editor-wrapper input.ng-invalid::-webkit-input-placeholder {
|
||||
color: @red;
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
/*
|
||||
.umb-panel-header i {
|
||||
font-size: 13px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
*/
|
||||
|
||||
.umb-panel-header-meta {
|
||||
height: 50px;
|
||||
}
|
||||
|
||||
@@ -657,28 +657,8 @@ ul.color-picker li {
|
||||
line-height: 120px
|
||||
}
|
||||
|
||||
.umb-upload-drop-zone{
|
||||
margin-bottom:5px;
|
||||
}
|
||||
|
||||
.umb-upload-drop-zone .info, .umb-upload-button-big{
|
||||
display: block;
|
||||
padding: 20px;
|
||||
opacity: 1;
|
||||
border: 1px dashed @gray-8;
|
||||
background: none;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
color: @gray-8;
|
||||
}
|
||||
|
||||
.umb-upload-button-big:hover{color: @gray-8;}
|
||||
|
||||
.umb-upload-drop-zone .info i.icon, .umb-upload-button-big i.icon{
|
||||
font-size: 55px;
|
||||
line-height: 70px
|
||||
}
|
||||
|
||||
.umb-upload-button-big {display: block}
|
||||
.umb-upload-button-big input {
|
||||
left: 0;
|
||||
@@ -688,123 +668,6 @@ ul.color-picker li {
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Photo folder styling
|
||||
// --------------------------------------------------
|
||||
|
||||
.umb-photo-folder .picrow{
|
||||
overflow-y: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.umb-photo-folder .picrow div, .umb-photo-preview{
|
||||
margin: 0px;
|
||||
padding: 0px;
|
||||
border: none;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.umb-photo-folder .picrow div a:first-child {
|
||||
width:100%;
|
||||
height:100%;
|
||||
}
|
||||
|
||||
.umb-photo-folder .picrow div.umb-photo {
|
||||
width:100%;
|
||||
height:100%;
|
||||
background-color: @gray-10;
|
||||
}
|
||||
|
||||
.umb-photo-folder a:hover{text-decoration: none}
|
||||
.umb-photo-folder .umb-non-thumbnail{
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
font-size: 12px;
|
||||
background: @gray-10;
|
||||
color: @black;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.umb-photo-folder .selector-overlay{
|
||||
display: none;
|
||||
}
|
||||
|
||||
//this is a temp hack, to provide selectors in the dialog:
|
||||
.umb-photo-folder .pic:hover .selector-overlay {
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
padding: 5px;
|
||||
background: @black;
|
||||
z-index: 100;
|
||||
display: block;
|
||||
text-align: center;
|
||||
color: @white;
|
||||
opacity: 0.4;
|
||||
text-decoration:none;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.umb-photo-folder .umb-non-thumbnail i{
|
||||
color: @gray-8;
|
||||
font-size: 50px;
|
||||
line-height: 60px;
|
||||
display: block;
|
||||
margin: auto;
|
||||
/*vertically aligns */
|
||||
position: relative;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.umb-photo-folder .umb-non-thumbnail span{
|
||||
position: absolute;
|
||||
display: block;
|
||||
margin: auto;
|
||||
width: 100%;
|
||||
top: 20px;
|
||||
}
|
||||
|
||||
.umb-photo-folder .selected{
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.umb-photo-folder .selected:before{
|
||||
content: "\e165";
|
||||
font-family: Icomoon;
|
||||
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
right: 10px;
|
||||
|
||||
font-size: 24px;
|
||||
color: @black;
|
||||
opacity: 0.5;
|
||||
background: @white;
|
||||
|
||||
line-height: 36px;
|
||||
text-align: center;
|
||||
-moz-border-radius: 15px;
|
||||
border-radius: 15px;
|
||||
|
||||
height: 32px;
|
||||
width: 32px;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// File upload
|
||||
// --------------------------------------------------
|
||||
|
||||
@@ -181,7 +181,7 @@
|
||||
modalClass: "login-overlay",
|
||||
animation: "slide",
|
||||
show: true,
|
||||
callback: callback,
|
||||
callback: callback
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
+2
-2
@@ -50,7 +50,7 @@ angular.module("umbraco")
|
||||
pageSize: 100,
|
||||
totalItems: 0,
|
||||
totalPages: 0,
|
||||
filter: '',
|
||||
filter: ''
|
||||
};
|
||||
|
||||
//preload selected item
|
||||
@@ -435,4 +435,4 @@ angular.module("umbraco")
|
||||
|
||||
onInit();
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@
|
||||
sort: {
|
||||
property: {
|
||||
alias: "",
|
||||
name: "",
|
||||
name: ""
|
||||
},
|
||||
direction: "ascending", //This is the value for sorting sent to server
|
||||
translation: {
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ angular.module("umbraco")
|
||||
pageSize: 100,
|
||||
totalItems: 0,
|
||||
totalPages: 0,
|
||||
filter: '',
|
||||
filter: ''
|
||||
};
|
||||
|
||||
//preload selected item
|
||||
|
||||
@@ -28,7 +28,7 @@ function DataTypeEditController($scope, $routeParams, $location, appState, navig
|
||||
label: preVals[i].label,
|
||||
view: preVals[i].view,
|
||||
value: preVals[i].value,
|
||||
config: preVals[i].config,
|
||||
config: preVals[i].config
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
<ng-form name="contentNameForm">
|
||||
<div class="umb-headline-editor-wrapper" ng-class="{'ng-invalid': contentNameForm.name.$invalid}">
|
||||
|
||||
<input type="text"
|
||||
ng-disabled="ngDisabled"
|
||||
name="name"
|
||||
localize="placeholder"
|
||||
class="umb-headline"
|
||||
select-on-focus
|
||||
placeholder="{{placeholder}}"
|
||||
ng-model="model"
|
||||
required
|
||||
val-server-field="Name"/>
|
||||
|
||||
<span class="help-inline" val-msg-for="name" val-toggle-msg="required">Required</span>
|
||||
<span class="help-inline" val-msg-for="name" val-toggle-msg="valServerField">{{contentNameForm.name.errorMsg}}</span>
|
||||
|
||||
</div>
|
||||
</ng-form>
|
||||
@@ -1,14 +0,0 @@
|
||||
<div class="umb-panel-header">
|
||||
<div class="row-fluid">
|
||||
|
||||
<div ng-transclude></div>
|
||||
|
||||
<ul ng-show="showTabs" class="nav nav-tabs umb-nav-tabs span12 -padding-left">
|
||||
|
||||
<li ng-class="{'tab-error': tabHasError}" ng-repeat="tab in visibleTabs" val-tab>
|
||||
<a href="#tab{{tab.id}}" data-toggle="tab">{{ tab.label }}</a>
|
||||
</li>
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,38 +0,0 @@
|
||||
<div class="umb-dialog" style="width: 500px" ng-switch on="model.complete">
|
||||
|
||||
<form name="sortForm" ng-submit="performSort()" ng-switch-when="false">
|
||||
<div class="umb-dialog-body" auto-scale="90">
|
||||
<p class="umb-abstract">Sort children of {{viewModel.name}}</p>
|
||||
|
||||
<table class="table umb-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<td>Name</td>
|
||||
<td>Last Update</td>
|
||||
<td>Index</td>
|
||||
</thead>
|
||||
<tbody ui-sortable="sortableOptions" ng-model="model.itemsToSort">
|
||||
<tr ng-repeat="item in model.itemsToSort">
|
||||
<td>{{item.column1}}</td>
|
||||
<td>{{item.column2}}</td>
|
||||
<td>{{item.column3}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<div class="btn-toolbar umb-btn-toolbar">
|
||||
<button type="button" class="btn" ng-click="handleCancel()">Cancel</button>
|
||||
<button type="submit" class="btn btn-primary">Sort</button>
|
||||
</div>
|
||||
</form>
|
||||
<div ng-switch-when="true">
|
||||
<div class="alert alert-success">
|
||||
{{model.successMsg}}
|
||||
</div>
|
||||
|
||||
<div class="btn-toolbar umb-btn-toolbar">
|
||||
<button class="btn" ng-click="handleOk()">{{model.okButton}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,12 +0,0 @@
|
||||
<div id="login" ng-show="!authenticated" ng-animate="'slide'" ng-cloak>
|
||||
<div class="form">
|
||||
<h1>Happy {{today}}!, log in below</h1>
|
||||
<div class="control-group">
|
||||
<input type="text" ng-model="login" class="input-xlarge" placeholder="Enter your username" />
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<input type="password" ng-model="password" class="input-xlarge" placeholder="Enter your password" />
|
||||
</div>
|
||||
<input type="button" ng-click="signin()" class="btn" value="Login" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,22 +0,0 @@
|
||||
<div class="btn-group">
|
||||
|
||||
<!-- options button -->
|
||||
<a class="btn" href="#" ng-click="getOptions()" prevent-default data-toggle="dropdown">
|
||||
<localize key="general_actions">Actions</localize>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
|
||||
<!-- actions -->
|
||||
<ul class="dropdown-menu umb-actions" role="menu" aria-labelledby="dLabel">
|
||||
<li class="action" ng-class="{sep:action.seperator}" ng-repeat="action in actions">
|
||||
|
||||
<!-- How does this reference executeMenuItem() i really don't think that this is very clear -->
|
||||
<a prevent-default
|
||||
ng-click="executeMenuItem(action)">
|
||||
<i class="icon icon-{{action.cssclass}}"></i>
|
||||
<span class="menu-label">{{action.name}}</span>
|
||||
</a>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -1,28 +0,0 @@
|
||||
<div class="umb-photo-folder" ng-style="containerStyle">
|
||||
<div class="picrow" ng-repeat="row in rows">
|
||||
|
||||
<div class="pic"
|
||||
ng-class="img.cssclass"
|
||||
ng-style="img.style" ng-repeat="img in row.images">
|
||||
|
||||
<a href="#media/media/edit/{{img.id}}"
|
||||
ng-click="clickHandler(img, $event, false)"
|
||||
title="{{img.name}}">
|
||||
|
||||
<div ng-style="img.style" class="umb-non-thumbnail" ng-if="!img.thumbnail">
|
||||
<i class="icon large {{img.icon}}"></i>
|
||||
<span>{{img.name}}</span>
|
||||
</div>
|
||||
|
||||
<div ng-if="img.thumbnail" class="umb-photo" ng-style="img.thumbStyle" alt="{{img.name}}">
|
||||
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href ng-click="clickHandler(img, $event, true)" class="selector-overlay">
|
||||
<localize key="buttons_select" ng-if="img.isFolder">Select</localize>
|
||||
<span ng-if="!img.isFolder">{{img.name}}</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,5 +0,0 @@
|
||||
<div class="umb-panel-body umb-scrollable row-fluid">
|
||||
<div class="tab-content form-horizontal" ng-transclude>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,8 +0,0 @@
|
||||
<div class="umb-upload-drop-zone">
|
||||
<div class="info">
|
||||
<i class="icon icon-parachute-drop"></i>
|
||||
<p>
|
||||
<localize key="media_dropFilesHere">Drop your files here...</localize>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,71 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.Editors.DocumentTypes.ImportController",
|
||||
function ($scope, contentTypeResource, navigationService, Upload, umbRequestHelper) {
|
||||
var vm = this;
|
||||
vm.serverErrorMessage = "";
|
||||
vm.state = "upload";
|
||||
vm.model = {};
|
||||
vm.uploadStatus = "";
|
||||
|
||||
$scope.handleFiles = function (files, event) {
|
||||
if (files && files.length > 0) {
|
||||
$scope.upload(files[0]);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.upload = function (file) {
|
||||
Upload.upload({
|
||||
url: umbRequestHelper.getApiUrl("contentTypeApiBaseUrl", "Upload"),
|
||||
fields: {},
|
||||
file: file
|
||||
}).success(function (data, status, headers, config) {
|
||||
if (data.notifications && data.notifications.length > 0) {
|
||||
|
||||
// set error status on file
|
||||
vm.uploadStatus = "error";
|
||||
|
||||
// Throw message back to user with the cause of the error
|
||||
vm.serverErrorMessage = data.notifications[0].message;
|
||||
} else {
|
||||
|
||||
// set done status on file
|
||||
vm.uploadStatus = "done";
|
||||
vm.model = data;
|
||||
vm.state = "confirm";
|
||||
}
|
||||
}).error(function (evt, status, headers, config) {
|
||||
|
||||
// set status done
|
||||
$scope.uploadStatus = "error";
|
||||
|
||||
// If file not found, server will return a 404 and display this message
|
||||
if (status === 404) {
|
||||
$scope.serverErrorMessage = "File not found";
|
||||
}
|
||||
else if (status == 400) {
|
||||
//it's a validation error
|
||||
$scope.serverErrorMessage = evt.message;
|
||||
}
|
||||
else {
|
||||
//it's an unhandled error
|
||||
//if the service returns a detailed error
|
||||
if (evt.InnerException) {
|
||||
$scope.serverErrorMessage = evt.InnerException.ExceptionMessage;
|
||||
|
||||
//Check if its the common "too large file" exception
|
||||
if (evt.InnerException.StackTrace && evt.InnerException.StackTrace.indexOf("ValidateRequestEntityLength") > 0) {
|
||||
$scope.serverErrorMessage = "File too large to upload";
|
||||
}
|
||||
|
||||
} else if (evt.Message) {
|
||||
$scope.serverErrorMessage = evt.Message;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.import = function () {
|
||||
contentTypeResource.import(vm.model.tempFileName);
|
||||
vm.state = "done";
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,53 @@
|
||||
<div class="umb-dialog umb-pane" ng-controller="Umbraco.Editors.DocumentTypes.ImportController as vm">
|
||||
<div ng-if="vm.state === 'upload'">
|
||||
<p>
|
||||
<localize key="settings_importDocumentTypeHelp">
|
||||
To import a document type, find the '.udt' file on your computer by clicking the 'Browse' button and click 'Import' (you'll be asked for confirmation on the next screen)
|
||||
</localize>
|
||||
</p>
|
||||
|
||||
<form name="importDoctype">
|
||||
|
||||
<!-- Select files -->
|
||||
<button class="btn"
|
||||
name="file"
|
||||
ngf-select
|
||||
ng-model="filesHolder"
|
||||
ngf-change="handleFiles($files, $event)"
|
||||
ngf-multiple="true"
|
||||
ngf-pattern="*.udt">
|
||||
<localize key="general_import">Import</localize>
|
||||
</button>
|
||||
|
||||
<localize key="general_or">or</localize>
|
||||
|
||||
<a class="btn-link" ng-click="nav.hideDialog()">
|
||||
<localize key="cancel">Cancel</localize>
|
||||
</a>
|
||||
</form>
|
||||
|
||||
<div ng-if="importDoctype.file.$error.pattern">Please choose a .udt file to import</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<div ng-if="vm.state === 'confirm'">
|
||||
<strong>
|
||||
<localize key="name">Name</localize>:
|
||||
</strong>
|
||||
{{vm.model.name}}
|
||||
<br />
|
||||
<strong>
|
||||
<localize key="alias">Alias</localize>:
|
||||
</strong>
|
||||
{{vm.model.alias}}
|
||||
<br />
|
||||
<br />
|
||||
<button class="btn btn-primary" ng-click="import()">
|
||||
<localize key="actions_importDocumentType">Import</localize>
|
||||
</button>
|
||||
</div>
|
||||
<div ng-if="vm.state === 'done'">
|
||||
{{vm.model.name}} has been imported!
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,108 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function HostnamesEditController($scope, $timeout, $location, $routeParams, localizationService, languageResource, formHelper) {
|
||||
|
||||
var vm = this;
|
||||
var hostnamesOverviewPath = "/settings/hostnames/overview";
|
||||
var id = $routeParams.id;
|
||||
var create = $routeParams.create;
|
||||
|
||||
vm.page = {};
|
||||
vm.showBackButton = true;
|
||||
vm.hostname = {};
|
||||
vm.availableCultures = null;
|
||||
vm.breadcrumbs = [];
|
||||
vm.labels = {};
|
||||
vm.allowRemoveNode = true;
|
||||
|
||||
vm.save = save;
|
||||
vm.back = back;
|
||||
vm.goToPage = goToPage;
|
||||
|
||||
function init() {
|
||||
|
||||
vm.loading = true;
|
||||
|
||||
// localize labels
|
||||
var labelKeys = [
|
||||
"treeHeaders_hostnames",
|
||||
"hostnames_addHostname",
|
||||
"hostnames_editHostname"
|
||||
];
|
||||
|
||||
localizationService.localizeMany(labelKeys).then(function (values) {
|
||||
vm.labels.hostnames = "Hostnames";
|
||||
vm.labels.addHostname = "Add hostname";
|
||||
vm.labels.editHostname = "Edit hostname";
|
||||
|
||||
languageResource.getAll().then(function (languages) {
|
||||
vm.languages = languages;
|
||||
});
|
||||
|
||||
if(create) {
|
||||
vm.page.name = vm.labels.addHostname;
|
||||
vm.loading = false;
|
||||
}
|
||||
|
||||
if(!create) {
|
||||
vm.page.name = vm.labels.editHostname;
|
||||
$timeout(function(){
|
||||
vm.hostname = {
|
||||
"id": 1,
|
||||
"hostname": "www.hostname.com",
|
||||
"language": {
|
||||
"displayName": "English (United States)",
|
||||
"culture": "en-US"
|
||||
},
|
||||
"node": {
|
||||
"id": 1,
|
||||
"name": "Home",
|
||||
"icon": "icon-home"
|
||||
}
|
||||
};
|
||||
makeBreadcrumbs();
|
||||
vm.loading = false;
|
||||
}, 500);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function save() {
|
||||
if (formHelper.submitForm({ scope: $scope })) {
|
||||
vm.page.saveButtonState = "busy";
|
||||
$timeout(function(){
|
||||
vm.page.saveButtonState = "success";
|
||||
}, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
function back() {
|
||||
$location.path(hostnamesOverviewPath);
|
||||
}
|
||||
|
||||
function goToPage(ancestor) {
|
||||
$location.path(ancestor.path);
|
||||
}
|
||||
|
||||
function makeBreadcrumbs() {
|
||||
vm.breadcrumbs = [
|
||||
{
|
||||
"name": vm.labels.hostnames,
|
||||
"path": hostnamesOverviewPath
|
||||
},
|
||||
{
|
||||
"name": vm.hostname.hostname
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.Hostnames.EditController", HostnamesEditController);
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,106 @@
|
||||
<div data-element="editor-hostnames" ng-controller="Umbraco.Editors.Hostnames.EditController as vm" class="clearfix">
|
||||
|
||||
<form name="editHostnameForm" no-validate val-form-manager>
|
||||
|
||||
<umb-editor-view>
|
||||
|
||||
<umb-editor-header
|
||||
name="vm.page.name"
|
||||
name-locked="true"
|
||||
on-back="vm.back()"
|
||||
show-back-button="vm.showBackButton"
|
||||
hide-icon="true"
|
||||
hide-description="true"
|
||||
hide-alias="true">
|
||||
</umb-editor-header>
|
||||
|
||||
<umb-editor-container>
|
||||
|
||||
<umb-load-indicator ng-if="vm.loading"></umb-load-indicator>
|
||||
|
||||
<umb-box ng-if="!vm.loading" class="block-form">
|
||||
<umb-box-content>
|
||||
<p></p>
|
||||
|
||||
<umb-control-group label="Hostname" description="Valid domain names are: 'example.com', 'www.example.com', 'example.com:8080' or 'https://www.example.com/'. One-level paths in domains are supported, eg. 'example.com/en'. However, they should be avoided. Better use the culture setting above." required="true">
|
||||
<input type="text"
|
||||
class="input-block-level"
|
||||
ng-model="vm.hostname.hostname"
|
||||
umb-auto-focus
|
||||
name="hostname"
|
||||
required
|
||||
val-server-field="Hostname" />
|
||||
<span ng-messages="editHostnameForm.hostname.$error" show-validation-on-submit >
|
||||
<span class="help-inline" ng-message="required"><localize key="general_required">Required</localize></span>
|
||||
<span class="help-inline" ng-message="valServerField">{{editHostnameForm.hostname.errorMsg}}</span>
|
||||
</span>
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group label="@general_language" description="Cras sagittis interdum risus, sit amet convallis erat fringilla sed." required="true">
|
||||
<select name="newLang"
|
||||
class="input-block-level"
|
||||
ng-model="vm.hostname.language.culture"
|
||||
ng-options="language.culture as language.name for language in vm.languages"
|
||||
val-server-field="IsoCode"
|
||||
required>
|
||||
</select>
|
||||
<span ng-messages="editHostnameForm.newLang.$error" show-validation-on-submit >
|
||||
<span class="help-inline" ng-message="required">Required</span>
|
||||
<span class="help-inline" ng-message="valServerField">{{editHostnameForm.newLang.errorMsg}}</span>
|
||||
</span>
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group label="Node" description="Etiam facilisis quis est ac laoreet. Vestibulum id tincidunt augue. Suspendisse vitae tellus turpis." required="true">
|
||||
<umb-node-preview
|
||||
ng-if="vm.hostname.node.id"
|
||||
style="max-width: 100%;"
|
||||
icon="vm.hostname.node.icon"
|
||||
name="vm.hostname.node.name"
|
||||
allow-remove="vm.allowRemoveNode"
|
||||
on-remove="vm.removeNode(vm.hostname.node)">
|
||||
</umb-node-preview>
|
||||
<a href=""
|
||||
ng-if="!vm.hostname.node.id"
|
||||
style="max-width: 100%;"
|
||||
class="umb-node-preview-add"
|
||||
ng-click="vm.openContentPicker()"
|
||||
prevent-default>
|
||||
<localize key="general_add">Add</localize>
|
||||
</a>
|
||||
</umb-control-group>
|
||||
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
|
||||
</umb-editor-container>
|
||||
|
||||
<umb-editor-footer>
|
||||
|
||||
<umb-editor-footer-content-left>
|
||||
<umb-breadcrumbs
|
||||
ancestors="vm.breadcrumbs"
|
||||
allow-on-open="true"
|
||||
on-open="vm.goToPage(ancestor)">
|
||||
</umb-breadcrumbs>
|
||||
</umb-editor-footer-content-left>
|
||||
|
||||
<umb-editor-footer-content-right>
|
||||
<umb-button
|
||||
type="button"
|
||||
action="vm.save()"
|
||||
state="vm.page.saveButtonState"
|
||||
button-style="success"
|
||||
shortcut="ctrl+s"
|
||||
label="Save"
|
||||
label-key="buttons_save"
|
||||
disabled="vm.loading">
|
||||
</umb-button>
|
||||
</umb-editor-footer-content-right>
|
||||
|
||||
</umb-editor-footer>
|
||||
|
||||
</umb-editor-view>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,109 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function HostnamesOverviewController($location, $timeout, navigationService, localizationService) {
|
||||
|
||||
var vm = this;
|
||||
|
||||
vm.page = {};
|
||||
vm.languages = [];
|
||||
vm.labels = {};
|
||||
|
||||
vm.addHostname = addHostname;
|
||||
vm.editHostname = editHostname;
|
||||
vm.deleteHostname = deleteHostname;
|
||||
|
||||
function init() {
|
||||
|
||||
vm.loading = true;
|
||||
|
||||
// localize labels
|
||||
var labelKeys = [
|
||||
"treeHeaders_languages"
|
||||
];
|
||||
|
||||
localizationService.localizeMany(labelKeys).then(function (values) {
|
||||
vm.labels.languages = values[0];
|
||||
vm.page.name = "Hostnames";
|
||||
});
|
||||
|
||||
vm.hostnames = [
|
||||
{
|
||||
"id": 1,
|
||||
"hostname": "www.hostname.com",
|
||||
"language": "English (United States)",
|
||||
"node": {
|
||||
"name": "Home",
|
||||
"icon": "icon-home"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"hostname": "www.hostname.com/da",
|
||||
"language": "Danish",
|
||||
"node": {
|
||||
"name": "Forside",
|
||||
"icon": "icon-home"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"hostname": "www.hostname.com/fr",
|
||||
"language": "French",
|
||||
"node": {
|
||||
"name": "French root node",
|
||||
"icon": "icon-home"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"hostname": "www.hostname.com/es",
|
||||
"language": "Spanish",
|
||||
"node": {
|
||||
"name": "Spanish root node",
|
||||
"icon": "icon-home"
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
vm.loading = false;
|
||||
|
||||
/*
|
||||
$timeout(function () {
|
||||
navigationService.syncTree({ tree: "hostnames", path: "-1" });
|
||||
});
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
function addHostname() {
|
||||
$location.search('create', null);
|
||||
$location.path("/settings/hostnames/edit/-1").search("create", "true");
|
||||
}
|
||||
|
||||
function editHostname(hostname) {
|
||||
$location.search('create', null);
|
||||
$location.path("/settings/hostnames/edit/" + hostname.id);
|
||||
}
|
||||
|
||||
function deleteHostname(hostname, event) {
|
||||
var confirmed = confirm("Are you sure you want to delete " + hostname.name + "?");
|
||||
if(confirmed) {
|
||||
hostname.deleteButtonState = "busy";
|
||||
// fake request
|
||||
$timeout(function(){
|
||||
var index = vm.hostnames.indexOf(hostname);
|
||||
vm.hostnames.splice(index, 1);
|
||||
}, 1000);
|
||||
}
|
||||
event.preventDefault()
|
||||
event.stopPropagation();
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.Hostnames.OverviewController", HostnamesOverviewController);
|
||||
|
||||
})();
|
||||
@@ -0,0 +1,69 @@
|
||||
<div data-element="editor-hostnames" ng-controller="Umbraco.Editors.Hostnames.OverviewController as vm" class="clearfix">
|
||||
|
||||
<umb-editor-view footer="false">
|
||||
|
||||
<umb-editor-header
|
||||
name="vm.page.name"
|
||||
name-locked="true"
|
||||
hide-icon="true"
|
||||
hide-description="true"
|
||||
hide-alias="true">
|
||||
</umb-editor-header>
|
||||
|
||||
<umb-editor-container>
|
||||
|
||||
<umb-load-indicator ng-if="vm.loading"></umb-load-indicator>
|
||||
|
||||
<umb-editor-sub-header>
|
||||
|
||||
<umb-editor-sub-header-content-left>
|
||||
<umb-button
|
||||
button-style="success"
|
||||
type="button"
|
||||
action="vm.addHostname()"
|
||||
label="Add hostname">
|
||||
</umb-button>
|
||||
</umb-editor-sub-header-content-left>
|
||||
|
||||
</umb-editor-sub-header>
|
||||
|
||||
<table class="table table-hover" ng-if="!vm.loading">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Hostname</th>
|
||||
<th>Language</th>
|
||||
<th>Node</th>
|
||||
</th>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="hostname in vm.hostnames" ng-click="vm.editHostname(hostname)" style="cursor: pointer;">
|
||||
<td>
|
||||
<i class="icon-home" style="color: #BBBABF; margin-right: 5px;"></i>
|
||||
<span class="bold">{{ hostname.hostname }}</span>
|
||||
</td>
|
||||
<td>{{hostname.language}}</td>
|
||||
<td>
|
||||
<div>
|
||||
<i class="{{hostname.node.icon}}" style="opacity: 0.8; margin-right: 2px;"></i>
|
||||
<span>{{hostname.node.name}}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td style="text-align: right;">
|
||||
<umb-button
|
||||
type="button"
|
||||
size="xxs"
|
||||
button-style="danger"
|
||||
state="hostname.deleteButtonState"
|
||||
action="vm.deleteHostname(hostname, $event)"
|
||||
label-key="general_delete">
|
||||
</umb-button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</umb-editor-container>
|
||||
|
||||
</umb-editor-view>
|
||||
|
||||
</div>
|
||||
@@ -21,7 +21,7 @@
|
||||
var labelKeys = [
|
||||
"treeHeaders_languages",
|
||||
"general_mandatory",
|
||||
"general_default",
|
||||
"general_default"
|
||||
];
|
||||
|
||||
localizationService.localizeMany(labelKeys).then(function (values) {
|
||||
|
||||
@@ -355,7 +355,7 @@
|
||||
});
|
||||
},
|
||||
readOnly: true
|
||||
},
|
||||
}
|
||||
|
||||
]);
|
||||
|
||||
|
||||
+1
-1
@@ -143,7 +143,7 @@
|
||||
templateUrl: 'views/propertyeditors/fileupload/fileupload.directive.html',
|
||||
controller: 'Umbraco.PropertyEditors.FileUploadController',
|
||||
scope: {
|
||||
model: "=",
|
||||
model: "="
|
||||
},
|
||||
link: function (scope, element, attrs, ctrl) {
|
||||
|
||||
|
||||
+2
-2
@@ -28,7 +28,7 @@ angular.module("umbraco")
|
||||
name: "1 column layout",
|
||||
sections: [
|
||||
{
|
||||
grid: 12,
|
||||
grid: 12
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -36,7 +36,7 @@ angular.module("umbraco")
|
||||
name: "2 column layout",
|
||||
sections: [
|
||||
{
|
||||
grid: 4,
|
||||
grid: 4
|
||||
},
|
||||
{
|
||||
grid: 8
|
||||
|
||||
@@ -76,7 +76,7 @@ function listViewController($rootScope, $scope, $routeParams, $injector, notific
|
||||
"canDelete": _.contains(currentUserPermissions, 'D'), //Magic Char = D
|
||||
"canMove": _.contains(currentUserPermissions, 'M'), //Magic Char = M
|
||||
"canPublish": _.contains(currentUserPermissions, 'U'), //Magic Char = U
|
||||
"canUnpublish": _.contains(currentUserPermissions, 'U'), //Magic Char = Z (however UI says it can't be set, so if we can publish 'U' we can unpublish)
|
||||
"canUnpublish": _.contains(currentUserPermissions, 'U') //Magic Char = Z (however UI says it can't be set, so if we can publish 'U' we can unpublish)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ angular.module("umbraco")
|
||||
tagsHound.get(query, function (suggestions) {
|
||||
cb(removeCurrentTagsFromSuggestions(suggestions));
|
||||
});
|
||||
},
|
||||
}
|
||||
}).bind("typeahead:selected", function (obj, datum, name) {
|
||||
angularHelper.safeApply($scope, function () {
|
||||
addTag(datum["value"]);
|
||||
|
||||
@@ -159,7 +159,7 @@
|
||||
});
|
||||
},
|
||||
readOnly: true
|
||||
},
|
||||
}
|
||||
]);
|
||||
|
||||
// initial cursor placement
|
||||
|
||||
@@ -313,7 +313,7 @@
|
||||
});
|
||||
},
|
||||
readOnly: true
|
||||
},
|
||||
}
|
||||
|
||||
]);
|
||||
|
||||
|
||||
@@ -123,7 +123,8 @@ describe('contentEditingHelper tests', function () {
|
||||
var allProps = contentEditingHelper.getAllProps(content);
|
||||
|
||||
//act
|
||||
formHelper.handleServerValidation({ "_Properties.bodyText.value": ["Required"] });
|
||||
//note the null, that's because culture is null
|
||||
formHelper.handleServerValidation({ "_Properties.bodyText.null.value": ["Required"] });
|
||||
|
||||
//assert
|
||||
expect(serverValidationManager.items.length).toBe(1);
|
||||
@@ -143,7 +144,8 @@ describe('contentEditingHelper tests', function () {
|
||||
{
|
||||
"Name": ["Required"],
|
||||
"UpdateDate": ["Invalid date"],
|
||||
"_Properties.bodyText.value": ["Required field"],
|
||||
//note the null, that's because culture is null
|
||||
"_Properties.bodyText.null.value": ["Required field"],
|
||||
"_Properties.textarea": ["Invalid format"]
|
||||
});
|
||||
|
||||
@@ -226,6 +228,7 @@ describe('contentEditingHelper tests', function () {
|
||||
//act
|
||||
var changed = contentEditingHelper.reBindChangedProperties(origContent, newContent);
|
||||
|
||||
|
||||
//assert
|
||||
expect(changed.length).toBe(2);
|
||||
expect(changed[0].alias).toBe("grid");
|
||||
|
||||
@@ -10,24 +10,39 @@ describe('file manager tests', function () {
|
||||
describe('file management', function () {
|
||||
|
||||
it('adding a file adds to the collection', function () {
|
||||
fileManager.setFiles('testProp', ["testFile"]);
|
||||
fileManager.setFiles({
|
||||
propertyAlias: 'testProp',
|
||||
files: ["testFile"]
|
||||
});
|
||||
expect(fileManager.getFiles().length).toBe(1);
|
||||
});
|
||||
|
||||
it('adding a file with the same property id replaces the existing one', function () {
|
||||
fileManager.setFiles('testProp', ["testFile"]);
|
||||
fileManager.setFiles('testProp', ["testFile2"]);
|
||||
fileManager.setFiles({
|
||||
propertyAlias: 'testProp',
|
||||
files: ["testFile"]
|
||||
});
|
||||
fileManager.setFiles({
|
||||
propertyAlias: 'testProp',
|
||||
files: ["testFile2"]
|
||||
});
|
||||
expect(fileManager.getFiles().length).toBe(1);
|
||||
expect(fileManager.getFiles()[0].file).toBe("testFile2");
|
||||
});
|
||||
|
||||
it('clears all files', function () {
|
||||
fileManager.setFiles('testProp1', ["testFile"]);
|
||||
fileManager.setFiles('testProp2', ["testFile"]);
|
||||
fileManager.setFiles({
|
||||
propertyAlias: 'testProp',
|
||||
files: ["testFile"]
|
||||
});
|
||||
fileManager.setFiles({
|
||||
propertyAlias: 'testProp2',
|
||||
files: ["testFile"]
|
||||
});
|
||||
expect(fileManager.getFiles().length).toBe(2);
|
||||
fileManager.clearFiles();
|
||||
expect(fileManager.getFiles().length).toBe(0);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -361,7 +361,6 @@
|
||||
<Content Include="Umbraco\Developer\Packages\directoryBrowser.aspx" />
|
||||
<Content Include="Umbraco\Developer\Packages\editPackage.aspx" />
|
||||
<Content Include="Umbraco\Dialogs\create.aspx" />
|
||||
<Content Include="Umbraco\Dialogs\importDocumenttype.aspx" />
|
||||
<Content Include="Umbraco\Dialogs\notifications.aspx" />
|
||||
<Content Include="Umbraco\Dialogs\protectPage.aspx" />
|
||||
<Content Include="Umbraco\Dialogs\rollBack.aspx" />
|
||||
|
||||
@@ -1,19 +1,11 @@
|
||||
@using System.Collections
|
||||
@using System.Net.Http
|
||||
@using System.Web.Mvc.Html
|
||||
@using Umbraco.Core
|
||||
@using Umbraco.Core
|
||||
@using ClientDependency.Core
|
||||
@using ClientDependency.Core.Mvc
|
||||
@using Microsoft.Owin.Security
|
||||
@using Newtonsoft.Json
|
||||
@using Newtonsoft.Json.Linq
|
||||
@using Umbraco.Core.IO
|
||||
@using Umbraco.Web
|
||||
@using Umbraco.Web.Editors
|
||||
@using umbraco
|
||||
@using Umbraco.Core.Configuration
|
||||
|
||||
@inherits System.Web.Mvc.WebViewPage<Umbraco.Web.Editors.BackOfficeModel>
|
||||
@inherits WebViewPage<Umbraco.Web.Editors.BackOfficeModel>
|
||||
|
||||
@{
|
||||
var isDebug = false;
|
||||
@@ -51,18 +43,25 @@
|
||||
new BasicPath("Umbraco", IOHelper.ResolveUrl(SystemDirectories.Umbraco)),
|
||||
new BasicPath("UmbracoClient", IOHelper.ResolveUrl(SystemDirectories.UmbracoClient)))
|
||||
</head>
|
||||
<noscript><h5><strong> JavaScript is disabled. Please enable to continue!</strong></h5></noscript>
|
||||
<body ng-class="{'touch':touchDevice, 'emptySection':emptySection, 'umb-drawer-is-visible':drawer.show}" ng-controller="Umbraco.MainController" id="umbracoMainPageBody">
|
||||
|
||||
<noscript>
|
||||
<div style="margin: 10px;">
|
||||
<h3><img src="assets/img/application/logo.png" alt="Umbraco logo" style="vertical-align: text-bottom;" /> Umbraco</h3>
|
||||
<p>For full functionality of Umbraco CMS it is necessary to enable JavaScript.</p>
|
||||
<p>Here are the <a href="https://www.enable-javascript.com/" target="_blank" style="text-decoration: underline;">instructions how to enable JavaScript in your web browser</a>.</p>
|
||||
</div>
|
||||
</noscript>
|
||||
|
||||
<div ng-hide="!authenticated" ng-cloak>
|
||||
|
||||
<div id="mainwrapper" class="clearfix" ng-click="closeDialogs($event)">
|
||||
|
||||
<div style="display: none;" id="mainwrapper" class="clearfix" ng-click="closeDialogs($event)">
|
||||
|
||||
<umb-app-header></umb-app-header>
|
||||
|
||||
<div class="umb-app-content">
|
||||
|
||||
<umb-navigation></umb-navigation>
|
||||
|
||||
<umb-navigation></umb-navigation>
|
||||
|
||||
<section id="contentwrapper">
|
||||
|
||||
@@ -70,18 +69,16 @@
|
||||
|
||||
<div class="umb-editor" ng-view></div>
|
||||
<div class="umb-editor__overlay" ng-if="editors.length > 0"></div>
|
||||
|
||||
<umb-editors></umb-editors>
|
||||
|
||||
<umb-editors></umb-editors>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
<umb-tour
|
||||
ng-if="tour.show"
|
||||
model="tour">
|
||||
<umb-tour ng-if="tour.show"
|
||||
model="tour">
|
||||
</umb-tour>
|
||||
|
||||
<umb-notifications></umb-notifications>
|
||||
@@ -90,45 +87,42 @@
|
||||
|
||||
<!-- help dialog controller by the help button - this also forces the backoffice UI to shift 400px -->
|
||||
<umb-drawer data-element="drawer" ng-if="drawer.show" model="drawer.model" view="drawer.view"></umb-drawer>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<umb-backdrop
|
||||
ng-if="backdrop.show"
|
||||
backdrop-opacity="backdrop.opacity"
|
||||
highlight-element="backdrop.element"
|
||||
highlight-prevent-click="backdrop.elementPreventClick"
|
||||
disable-events-on-click="backdrop.disableEventsOnClick">
|
||||
<umb-backdrop ng-if="backdrop.show"
|
||||
backdrop-opacity="backdrop.opacity"
|
||||
highlight-element="backdrop.element"
|
||||
highlight-prevent-click="backdrop.elementPreventClick"
|
||||
disable-events-on-click="backdrop.disableEventsOnClick">
|
||||
</umb-backdrop>
|
||||
|
||||
<umb-overlay
|
||||
ng-if="overlay.show"
|
||||
model="overlay"
|
||||
position="{{overlay.position}}"
|
||||
view="overlay.view">
|
||||
<umb-overlay ng-if="overlay.show"
|
||||
model="overlay"
|
||||
position="{{overlay.position}}"
|
||||
view="overlay.view">
|
||||
</umb-overlay>
|
||||
|
||||
<umb-overlay
|
||||
ng-if="ysodOverlay.show"
|
||||
model="ysodOverlay"
|
||||
position="right"
|
||||
view="ysodOverlay.view">
|
||||
<umb-overlay ng-if="ysodOverlay.show"
|
||||
model="ysodOverlay"
|
||||
position="right"
|
||||
view="ysodOverlay.view">
|
||||
</umb-overlay>
|
||||
|
||||
@Html.BareMinimumServerVariablesScript(Url, Url.Action("ExternalLogin", "BackOffice", new { area = ViewBag.UmbracoPath }), Model.Features, UmbracoConfig.For.GlobalSettings())
|
||||
|
||||
<script type="text/javascript">
|
||||
<script>
|
||||
|
||||
document.angularReady = function(app) {
|
||||
|
||||
@Html.AngularValueExternalLoginInfoScript((IEnumerable<string>)ViewBag.ExternalSignInError)
|
||||
@Html.AngularValueResetPasswordCodeInfoScript(ViewData["PasswordResetCode"])
|
||||
//required for the noscript trick
|
||||
document.getElementById("mainwrapper").style.display = "inherit";
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@*And finally we can load in our angular app*@
|
||||
<script type="text/javascript" src="lib/rgrove-lazyload/lazyload.js"></script>
|
||||
<script type="text/javascript" src="@Url.GetUrlWithCacheBust("Application", "BackOffice")"></script>
|
||||
<script src="lib/rgrove-lazyload/lazyload.js"></script>
|
||||
<script src="@Url.GetUrlWithCacheBust("Application", "BackOffice")"></script>
|
||||
|
||||
@if (isDebug)
|
||||
{
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
<%@ Page MasterPageFile="../masterpages/umbracoDialog.Master" Language="c#" Codebehind="importDocumenttype.aspx.cs" AutoEventWireup="false"
|
||||
Inherits="umbraco.presentation.umbraco.dialogs.importDocumentType" %>
|
||||
|
||||
<asp:Content ID="Content1" runat="server" ContentPlaceHolderID="body">
|
||||
<input id="tempFile" type="hidden" name="tempFile" runat="server" />
|
||||
|
||||
<asp:Literal ID="FeedBackMessage" runat="server" />
|
||||
|
||||
<table class="propertyPane" id="Table1" cellspacing="0" cellpadding="4" width="360" border="0" runat="server">
|
||||
<tr>
|
||||
<td class="propertyContent" colspan="2">
|
||||
<asp:Panel ID="Wizard" runat="server" Visible="True">
|
||||
<p>
|
||||
<span class="guiDialogNormal">
|
||||
<%=Services.TextService.Localize("importDocumentTypeHelp")%>
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<input id="documentTypeFile" type="file" runat="server" />
|
||||
</p>
|
||||
|
||||
|
||||
<asp:Button ID="submit" runat="server"></asp:Button> <em><%= Services.TextService.Localize("or") %></em> <a href="#" onclick="UmbClientMgr.closeModalWindow(); return false;"><%= Services.TextService.Localize("cancel") %></a>
|
||||
</asp:Panel>
|
||||
|
||||
|
||||
<asp:Panel ID="Confirm" runat="server" Visible="False">
|
||||
<strong>
|
||||
<%=Services.TextService.Localize("name")%>
|
||||
:</strong>
|
||||
<asp:Literal ID="dtName" runat="server"></asp:Literal>
|
||||
<br />
|
||||
<strong>
|
||||
<%=Services.TextService.Localize("alias")%>
|
||||
:</strong>
|
||||
<asp:Literal ID="dtAlias" runat="server"></asp:Literal>
|
||||
<br />
|
||||
<br />
|
||||
<asp:Button ID="import" runat="server"></asp:Button>
|
||||
</asp:Panel>
|
||||
<asp:Panel ID="done" runat="server" Visible="False">
|
||||
<asp:Literal ID="dtNameConfirm" runat="server"></asp:Literal>
|
||||
has been imported!
|
||||
</asp:Panel>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</asp:Content>
|
||||
@@ -1,21 +1,29 @@
|
||||
using AutoMapper;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web.Http;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Composing;
|
||||
using Umbraco.Web.Models;
|
||||
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;
|
||||
using Notification = Umbraco.Web.Models.ContentEditing.Notification;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
@@ -454,5 +462,93 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
public HttpResponseMessage Import(string file)
|
||||
{
|
||||
var filePath = Path.Combine(IOHelper.MapPath(SystemDirectories.Data), file);
|
||||
if (string.IsNullOrEmpty(file) || !System.IO.File.Exists(filePath))
|
||||
{
|
||||
return Request.CreateResponse(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
var xd = new XmlDocument();
|
||||
xd.XmlResolver = null;
|
||||
xd.Load(filePath);
|
||||
|
||||
var userId = Security.GetUserId();
|
||||
var element = XElement.Parse(xd.InnerXml);
|
||||
Current.Services.PackagingService.ImportContentTypes(element, userId);
|
||||
|
||||
// Try to clean up the temporary file.
|
||||
try
|
||||
{
|
||||
System.IO.File.Delete(filePath);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Current.Logger.Error(typeof(ContentTypeController), "Error cleaning up temporary udt file in App_Data: " + ex.Message, ex);
|
||||
}
|
||||
|
||||
return Request.CreateResponse(HttpStatusCode.OK);
|
||||
}
|
||||
|
||||
[HttpPost]
|
||||
[FileUploadCleanupFilter(false)]
|
||||
public async Task<ContentTypeImportModel> Upload()
|
||||
{
|
||||
if (Request.Content.IsMimeMultipartContent() == false)
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
|
||||
}
|
||||
|
||||
var root = IOHelper.MapPath("~/App_Data/TEMP/FileUploads");
|
||||
//ensure it exists
|
||||
Directory.CreateDirectory(root);
|
||||
var provider = new MultipartFormDataStreamProvider(root);
|
||||
var result = await Request.Content.ReadAsMultipartAsync(provider);
|
||||
|
||||
//must have a file
|
||||
if (result.FileData.Count == 0)
|
||||
{
|
||||
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
|
||||
}
|
||||
|
||||
var model = new ContentTypeImportModel();
|
||||
var file = result.FileData[0];
|
||||
var fileName = file.Headers.ContentDisposition.FileName.Trim('\"');
|
||||
var ext = fileName.Substring(fileName.LastIndexOf('.') + 1).ToLower();
|
||||
if (ext.InvariantEquals("udt"))
|
||||
{
|
||||
//TODO: Currently it has to be here, it's not ideal but that's the way it is right now
|
||||
var tempDir = IOHelper.MapPath(SystemDirectories.Data);
|
||||
|
||||
//ensure it's there
|
||||
Directory.CreateDirectory(tempDir);
|
||||
|
||||
model.TempFileName = "justDelete_" + Guid.NewGuid() + ".udt";
|
||||
var tempFileLocation = Path.Combine(tempDir, model.TempFileName);
|
||||
System.IO.File.Copy(file.LocalFileName, tempFileLocation, true);
|
||||
|
||||
var xd = new XmlDocument
|
||||
{
|
||||
XmlResolver = null
|
||||
};
|
||||
xd.Load(tempFileLocation);
|
||||
|
||||
model.Alias = xd.DocumentElement?.SelectSingleNode("//DocumentType/Info/Alias")?.FirstChild.Value;
|
||||
model.Name = xd.DocumentElement?.SelectSingleNode("//DocumentType/Info/Name")?.FirstChild.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
model.Notifications.Add(new Notification(
|
||||
Services.TextService.Localize("speechBubbles/operationFailedHeader"),
|
||||
Services.TextService.Localize("media/disallowedFileType"),
|
||||
SpeechBubbleIcon.Warning));
|
||||
}
|
||||
|
||||
return model;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Web.Models
|
||||
{
|
||||
[DataContract(Name = "contentTypeImportModel")]
|
||||
public class ContentTypeImportModel : INotificationModel
|
||||
{
|
||||
public ContentTypeImportModel()
|
||||
{
|
||||
Notifications = new List<Notification>();
|
||||
}
|
||||
|
||||
[DataMember(Name = "alias")]
|
||||
public string Alias { get; set; }
|
||||
|
||||
[DataMember(Name = "name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[DataMember(Name = "notifications")]
|
||||
public List<Notification> Notifications { get; }
|
||||
|
||||
[DataMember(Name = "tempFileName")]
|
||||
public string TempFileName { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ using System.Net.Http.Formatting;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.Entities;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web._Legacy.Actions;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
@@ -74,13 +73,7 @@ namespace Umbraco.Web.Trees
|
||||
|
||||
// root actions
|
||||
menu.Items.Add<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
|
||||
menu.Items.Add<ActionImport>(Services.TextService.Localize(string.Format("actions/{0}", ActionImport.Instance.Alias)), true).ConvertLegacyMenuItem(new EntitySlim
|
||||
{
|
||||
Id = int.Parse(id),
|
||||
Level = 1,
|
||||
ParentId = Constants.System.Root,
|
||||
Name = ""
|
||||
}, "documenttypes", "settings");
|
||||
menu.Items.Add<ActionImport>(Services.TextService.Localize(string.Format("actions/{0}", ActionImport.Instance.Alias)), true);
|
||||
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
|
||||
return menu;
|
||||
}
|
||||
|
||||
@@ -257,12 +257,6 @@ namespace Umbraco.Web.Trees
|
||||
"dialogs/sendToTranslation.aspx?id=" + nodeId + "&rnd=" + DateTime.UtcNow.Ticks,
|
||||
Current.Services.TextService.Localize("actions/sendToTranslate")));
|
||||
|
||||
case "UmbClientMgr.appActions().actionImport()":
|
||||
return Attempt.Succeed(
|
||||
new LegacyUrlAction(
|
||||
"dialogs/importDocumentType.aspx",
|
||||
Current.Services.TextService.Localize("actions/importDocumentType")));
|
||||
|
||||
}
|
||||
return Attempt<LegacyUrlAction>.Fail();
|
||||
}
|
||||
|
||||
@@ -246,6 +246,7 @@
|
||||
<Compile Include="Models\ContentEditing\UserProfile.cs" />
|
||||
<Compile Include="Models\ContentEditing\UserSave.cs" />
|
||||
<Compile Include="Models\ContentEditing\Language.cs" />
|
||||
<Compile Include="Models\ContentTypeImportModel.cs" />
|
||||
<Compile Include="Models\Mapping\ActionButtonsResolver.cs" />
|
||||
<Compile Include="Models\Mapping\AuditMapperProfile.cs" />
|
||||
<Compile Include="Models\Mapping\ContentAppResolver.cs" />
|
||||
@@ -1295,10 +1296,6 @@
|
||||
<Compile Include="umbraco.presentation\umbraco\developer\Packages\editPackage.aspx.designer.cs">
|
||||
<DependentUpon>editPackage.aspx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="umbraco.presentation\umbraco\dialogs\importDocumenttype.aspx.cs">
|
||||
<DependentUpon>importDocumenttype.aspx</DependentUpon>
|
||||
<SubType>ASPXCodeBehind</SubType>
|
||||
</Compile>
|
||||
<Compile Include="umbraco.presentation\umbraco\dialogs\rollBack.aspx.cs">
|
||||
<DependentUpon>rollBack.aspx</DependentUpon>
|
||||
</Compile>
|
||||
@@ -1449,7 +1446,6 @@
|
||||
<Content Include="umbraco.presentation\umbraco\developer\Packages\editPackage.aspx">
|
||||
<SubType>ASPXCodeBehind</SubType>
|
||||
</Content>
|
||||
<Content Include="umbraco.presentation\umbraco\dialogs\importDocumenttype.aspx" />
|
||||
<Content Include="umbraco.presentation\umbraco\dialogs\rollBack.aspx">
|
||||
<SubType>ASPXCodeBehind</SubType>
|
||||
</Content>
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
using System;
|
||||
using Umbraco.Web.UI.Pages;
|
||||
|
||||
namespace Umbraco.Web._Legacy.Actions
|
||||
namespace Umbraco.Web._Legacy.Actions
|
||||
{
|
||||
/// <summary>
|
||||
/// This action is invoked when importing a document type
|
||||
@@ -32,7 +29,7 @@ namespace Umbraco.Web._Legacy.Actions
|
||||
{
|
||||
get
|
||||
{
|
||||
return string.Format("{0}.actionImport()", ClientTools.Scripts.GetAppActions);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
<%@ Page MasterPageFile="../masterpages/umbracoDialog.Master" Language="c#" Codebehind="importDocumenttype.aspx.cs" AutoEventWireup="false"
|
||||
Inherits="umbraco.presentation.umbraco.dialogs.importDocumentType" %>
|
||||
|
||||
<asp:Content ID="Content1" runat="server" ContentPlaceHolderID="body">
|
||||
<input id="tempFile" type="hidden" name="tempFile" runat="server" />
|
||||
|
||||
<asp:Literal ID="FeedBackMessage" runat="server" />
|
||||
|
||||
<table class="propertyPane" id="Table1" cellspacing="0" cellpadding="4" width="360" border="0" runat="server">
|
||||
<tr>
|
||||
<td class="propertyContent" colspan="2">
|
||||
<asp:Panel ID="Wizard" runat="server" Visible="True">
|
||||
<p>
|
||||
<span class="guiDialogNormal">
|
||||
<%=Services.TextService.Localize("importDocumentTypeHelp")%>
|
||||
</span>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<input id="documentTypeFile" type="file" runat="server" />
|
||||
</p>
|
||||
|
||||
|
||||
<asp:Button ID="submit" runat="server"></asp:Button> <em><%= Services.TextService.Localize("or") %></em> <a href="#" onclick="UmbClientMgr.closeModalWindow(); return false;"><%= Services.TextService.Localize("cancel") %></a>
|
||||
</asp:Panel>
|
||||
|
||||
|
||||
<asp:Panel ID="Confirm" runat="server" Visible="False">
|
||||
<strong>
|
||||
<%=Services.TextService.Localize("name")%>
|
||||
:</strong>
|
||||
<asp:Literal ID="dtName" runat="server"></asp:Literal>
|
||||
<br />
|
||||
<strong>
|
||||
<%=Services.TextService.Localize("alias")%>
|
||||
:</strong>
|
||||
<asp:Literal ID="dtAlias" runat="server"></asp:Literal>
|
||||
<br />
|
||||
<br />
|
||||
<asp:Button ID="import" runat="server"></asp:Button>
|
||||
</asp:Panel>
|
||||
<asp:Panel ID="done" runat="server" Visible="False">
|
||||
<asp:Literal ID="dtNameConfirm" runat="server"></asp:Literal>
|
||||
has been imported!
|
||||
</asp:Panel>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</asp:Content>
|
||||
@@ -1,121 +0,0 @@
|
||||
using Umbraco.Core.Services;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Web.UI.WebControls;
|
||||
using System.Web.UI.HtmlControls;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web.Composing;
|
||||
|
||||
namespace umbraco.presentation.umbraco.dialogs
|
||||
{
|
||||
/// <summary>
|
||||
/// Summary description for importDocumentType.
|
||||
/// </summary>
|
||||
public class importDocumentType : Umbraco.Web.UI.Pages.UmbracoEnsuredPage
|
||||
{
|
||||
public importDocumentType()
|
||||
{
|
||||
|
||||
CurrentApp = Constants.Applications.Settings.ToString();
|
||||
|
||||
}
|
||||
protected Literal FeedBackMessage;
|
||||
protected Literal jsShowWindow;
|
||||
protected Panel Wizard;
|
||||
protected HtmlTable Table1;
|
||||
protected HtmlInputHidden tempFile;
|
||||
protected HtmlInputFile documentTypeFile;
|
||||
protected Button submit;
|
||||
protected Panel Confirm;
|
||||
protected Literal dtName;
|
||||
protected Literal dtAlias;
|
||||
protected Button import;
|
||||
protected Literal dtNameConfirm;
|
||||
protected Panel done;
|
||||
private string tempFileName = "";
|
||||
|
||||
private void Page_Load(object sender, EventArgs e)
|
||||
{
|
||||
if (!IsPostBack)
|
||||
{
|
||||
submit.Text = Services.TextService.Localize("import");
|
||||
import.Text = Services.TextService.Localize("import");
|
||||
}
|
||||
}
|
||||
|
||||
#region Web Form Designer generated code
|
||||
override protected void OnInit(EventArgs e)
|
||||
{
|
||||
//
|
||||
// CODEGEN: This call is required by the ASP.NET Web Form Designer.
|
||||
//
|
||||
InitializeComponent();
|
||||
base.OnInit(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
this.submit.Click += new System.EventHandler(this.submit_Click);
|
||||
this.import.Click += new System.EventHandler(this.import_Click);
|
||||
this.Load += new System.EventHandler(this.Page_Load);
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void import_Click(object sender, EventArgs e)
|
||||
{
|
||||
var xd = new XmlDocument();
|
||||
xd.XmlResolver = null;
|
||||
xd.Load(tempFile.Value);
|
||||
|
||||
var userId = Security.GetUserId();
|
||||
|
||||
var element = XElement.Parse(xd.InnerXml);
|
||||
var importContentTypes = Current.Services.PackagingService.ImportContentTypes(element, userId);
|
||||
var contentType = importContentTypes.FirstOrDefault();
|
||||
if (contentType != null)
|
||||
dtNameConfirm.Text = contentType.Name;
|
||||
|
||||
// Try to clean up the temporary file.
|
||||
try
|
||||
{
|
||||
System.IO.File.Delete(tempFile.Value);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
Current.Logger.Error(typeof(importDocumentType), "Error cleaning up temporary udt file in App_Data: " + ex.Message, ex);
|
||||
}
|
||||
|
||||
Wizard.Visible = false;
|
||||
Confirm.Visible = false;
|
||||
done.Visible = true;
|
||||
}
|
||||
|
||||
private void submit_Click(object sender, EventArgs e)
|
||||
{
|
||||
tempFileName = "justDelete_" + Guid.NewGuid().ToString() + ".udt";
|
||||
var fileName = IOHelper.MapPath(SystemDirectories.Data + "/" + tempFileName);
|
||||
tempFile.Value = fileName;
|
||||
|
||||
documentTypeFile.PostedFile.SaveAs(fileName);
|
||||
|
||||
var xd = new XmlDocument();
|
||||
xd.XmlResolver = null;
|
||||
xd.Load(fileName);
|
||||
dtName.Text = xd.DocumentElement.SelectSingleNode("//DocumentType/Info/Name").FirstChild.Value;
|
||||
dtAlias.Text = xd.DocumentElement.SelectSingleNode("//DocumentType/Info/Alias").FirstChild.Value;
|
||||
|
||||
Wizard.Visible = false;
|
||||
done.Visible = false;
|
||||
Confirm.Visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user