Compare commits

..

3 Commits

Author SHA1 Message Date
copilaurobert b5653e616b Added some styling for disabled variants 2018-08-13 14:48:27 +02:00
copilaurobert 8ef782bd11 Fixed typo 2018-08-13 13:07:13 +02:00
copilaurobert 1af2780c58 Removes the ability to open the same variant twice in split view 2018-08-13 13:04:44 +02:00
50 changed files with 1092 additions and 1860 deletions
+30 -1
View File
@@ -3,8 +3,37 @@
"browser": true
},
"plugins": [
"angular"
],
"rules": {
"comma-dangle": ["error", "never"]
"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
},
"globals": {
-8
View File
@@ -12,9 +12,6 @@ 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');
@@ -33,11 +30,6 @@ 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})();'))
+553 -1376
View File
File diff suppressed because it is too large Load Diff
-1
View File
@@ -27,7 +27,6 @@
"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",
@@ -103,7 +103,7 @@
backdropOpacity: "=?",
highlightElement: "=?",
highlightPreventClick: "=?",
disableEventsOnClick: "=?"
disableEventsOnClick: "=?",
}
};
@@ -107,7 +107,7 @@
$scope.editors[s].content = initVariant(variant);
}
}
}
}
@@ -128,15 +128,16 @@
//if the variant list that defines the header drop down isn't assigned to the variant then assign it now
if (!variant.variants) {
variant.variants = _.map($scope.content.variants,
function(v) {
function (v) {
return _.pick(v, "active", "language", "state");
});
}
else {
//merge the scope variants on top of the header variants collection (handy when needing to refresh)
var orgVar = variant;
angular.extend(variant.variants,
_.map($scope.content.variants,
function(v) {
function (v) {
return _.pick(v, "active", "language", "state");
}));
}
@@ -150,6 +151,25 @@
variant.variants[i].active = false;
}
}
// disables the active variant in the opposite editor language dropdown
// to prevent same variant to be opened twice
if ($scope.editors.length > 1) {
for (var y = 0; y < $scope.editors.length; y++) {
for (var $ = 0; $ < $scope.editors[y].content.variants.length; $++) {
var editorIndex = y === 0 ? 1 : 0;
if ($scope.editors[y].content.variants[$].active === true) {
$scope.editors[editorIndex].content.variants[$].disabled = true;
} else {
$scope.editors[editorIndex].content.variants[$].disabled = false;
}
}
}
}
}
//then assign the variant to a view model to the content app
@@ -158,10 +178,6 @@
});
contentApp.viewModel = variant;
// emit variant change event so content apps can update content
var args = { "node": $scope.content, "variant": variant };
eventsService.emit("editors.content.changeVariant", args);
return variant;
}
@@ -316,7 +332,7 @@
$scope.page.buttonGroupState = "success";
eventsService.emit("content.saved", { content: $scope.content, action: args.action });
return $q.when(data);
},
function (err) {
@@ -326,7 +342,7 @@
}
$scope.page.buttonGroupState = "error";
return $q.reject(err);
});
}
@@ -585,7 +601,7 @@
$scope.saveAndCloseButtonState = "success";
}).catch(angular.noop);;
};
function moveNode(node, target) {
contentResource.move({ "parentId": target.id, "id": node.id })
@@ -6,7 +6,7 @@
function link(scope, element, attrs, ctrl) {
var evts = [];
var isInfoApp = false;
var isInfoTab = false;
var labels = {};
scope.publishStatus = [];
@@ -16,11 +16,6 @@
function onInit() {
//get the current variant
scope.activeVariant = _.find(scope.node.variants, function (variant) {
return variant.active;
});
userService.getCurrentUser().then(function(user){
// only allow change of media type if user has access to the settings sections
angular.forEach(user.sections, function(section){
@@ -47,7 +42,7 @@
labels.publishedPendingChanges = data[3];
labels.notCreated = data[4];
setPublishState(scope.node, scope.activeVariant);
setNodePublishStatus(scope.node);
});
@@ -177,40 +172,49 @@
});
}
function setPublishState(node, variant) {
function setNodePublishStatus(node) {
var state = {};
if (node.trashed) {
// deleted node
state.label = labels.deleted;
state.color = "danger";
// deleted node
if (node.trashed === true) {
scope.publishStatus.push({
label: labels.deleted,
color: "danger"
});
return;
}
if (variant.state === "NotCreated") {
// not created variant
state.label = labels.notCreated;
state.color = "gray";
}
else if (variant.state === "Draft") {
// draft variant
state.label = labels.unpublished;
state.color = "gray";
}
else if (variant.state === "Published") {
// published variant
state.label = labels.published;
state.color = "success";
}
else if (variant.state === "PublishedPendingChanges") {
// published variant with pending changes
state.label = labels.publishedPendingChanges;
state.color = "success";
}
if (node.variants) {
for (var i = 0; i < node.variants.length; i++) {
scope.variantState = state;
var variant = node.variants[i];
var status = {
culture: variant.language ? variant.language.culture : null
};
if (variant.state === "NotCreated") {
status.label = labels.notCreated;
status.color = "gray";
}
else if (variant.state === "Draft") {
// draft node
status.label = labels.unpublished;
status.color = "gray";
}
else if (variant.state === "Published") {
// published node
status.label = labels.published;
status.color = "success";
}
else if (variant.state === "PublishedPendingChanges") {
// published node with pending changes
status.label = labels.publishedPendingChanges;
status.color = "success";
}
scope.publishStatus.push(status);
}
}
}
function setPublishDate(date) {
@@ -288,7 +292,7 @@
function formatDatesToLocal() {
// get current backoffice user and format dates
userService.getCurrentUser().then(function (currentUser) {
scope.activeVariant.createDateFormatted = dateHelper.getLocalDate(scope.activeVariant.createDate, currentUser.locale, 'LLL');
scope.node.createDateFormatted = dateHelper.getLocalDate(scope.node.createDate, currentUser.locale, 'LLL');
scope.node.releaseDateYear = scope.node.releaseDate ? ucfirst(dateHelper.getLocalDate(scope.node.releaseDate, currentUser.locale, 'YYYY')) : null;
scope.node.releaseDateMonth = scope.node.releaseDate ? ucfirst(dateHelper.getLocalDate(scope.node.releaseDate, currentUser.locale, 'MMMM')) : null;
@@ -308,30 +312,24 @@
evts.push(eventsService.on("app.tabChange", function (event, args) {
$timeout(function(){
if (args.alias === "info") {
isInfoApp = true;
isInfoTab = true;
loadAuditTrail();
} else {
isInfoApp = false;
isInfoTab = false;
}
});
}));
// listen for variant change so we can update the content
evts.push(eventsService.on("editors.content.changeVariant", function (event, args) {
setPublishState(args.node, args.variant);
formatDatesToLocal();
}));
// watch for content updates - reload content when node is saved, published etc.
scope.$watch('node.updateDate', function(newValue, oldValue){
if(!newValue) { return; }
if(newValue === oldValue) { return; }
if(newValue === oldValue) { return; }
if(isInfoTab) {
loadAuditTrail();
formatDatesToLocal();
setPublishState(scope.node);
setNodePublishStatus(scope.node);
}
});
@@ -43,10 +43,13 @@
});
var editor = {
content: scope.initVariant({ variant: variant})
content: scope.initVariant({ variant: variant })
};
scope.editors.push(editor);
disableActiveVariant();
//TODO: hacking animation states - these should hopefully be easier to do when we upgrade angular
editor.collapsed = true;
editor.loading = true;
@@ -56,6 +59,7 @@
}, 100);
};
/**
* Changes the currently selected variant
* @param {any} variantDropDownItem
@@ -71,8 +75,7 @@
if (editorIndex === 0) {
//if we've made it this far, then update the query string
$location.search("cculture", variantDropDownItem.language.culture);
}
else {
} else {
//set all variant drop down items as inactive for this editor and then set the selected on as active
for (var i = 0; i < scope.editor.content.variants.length; i++) {
scope.editor.content.variants[i].active = false;
@@ -85,21 +88,64 @@
});
scope.editor.content = scope.initVariant({ variant: variant });
}
disableActiveVariant();
};
/** Closes the split view */
scope.closeSplitView = function () {
// if we close split view, then disabled to false on all active variants
for (var i = 0; i < scope.editors.length; i++) {
for (var c = 0; c < scope.editors[i].content.variants.length; c++) {
if (scope.editors[1].content.variants[c].active === true) {
if (scope.editors[i].content.variants[c].hide) {
scope.editors[i].content.variants[c].hide = false;
}
}
}
}
//TODO: hacking animation states - these should hopefully be easier to do when we upgrade angular
scope.editor.loading = true;
scope.editor.collapsed = true;
$timeout(function () {
var index = _.findIndex(scope.editors, function(e) {
var index = _.findIndex(scope.editors, function (e) {
return e === scope.editor;
});
scope.editors.splice(index, 1);
}, 400);
};
/*
* Disables the active variant in the opposite editor language dropdown
* to prevent same variant to be opened twice
*/
function disableActiveVariant() {
for (var j = 0; j < scope.editors[0].content.variants.length; j++) {
if (scope.editors[1].content.variants[j].disabled) {
scope.editors[1].content.variants[j].disabled = false;
}
if (scope.editors[0].content.variants[j].active === true) {
scope.editors[1].content.variants[j].disabled = true;
}
}
for (var c = 0; c < scope.editors[1].content.variants.length; c++) {
if (scope.editors[0].content.variants[c].disabled) {
scope.editors[0].content.variants[c].disabled = false;
}
if (scope.editors[1].content.variants[c].active === true) {
scope.editors[0].content.variants[c].disabled = true;
}
}
}
//set the content to dirty if the header changes
scope.$watch("contentHeaderForm.$dirty",
function (newValue, oldValue) {
@@ -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;
@@ -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;
@@ -57,7 +57,7 @@
},
stop: function(e, ui) {
updateTabsSortOrder();
}
},
};
scope.sortableOptionsProperty = {
@@ -333,17 +333,6 @@ 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,32 +519,25 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
var allNewProps = this.getAllProps(savedVariant);
//check for changed properties of the content
for (var k = 0; k < allOrigProps.length; k++) {
var origProp = allOrigProps[k];
var alias = origProp.alias;
for (var p in allOrigProps) {
var alias = allOrigProps[p].alias;
var newProp = getNewProp(alias, allNewProps);
if (newProp && !_.isEqual(origProp.value, newProp.value)) {
if (newProp && !_.isEqual(alias, newProp.value)) {
//they have changed so set the origContent prop to the new one
var origVal = origProp.value;
origProp.value = newProp.value;
var origVal = allOrigProps[p].value;
allOrigProps[p].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(origProp.onValueChanged)) {
if (angular.isFunction(allOrigProps[p].onValueChanged)) {
//send the newVal + oldVal
origProp.onValueChanged(origProp.value, origVal);
allOrigProps[p].onValueChanged(allOrigProps[p].value, origVal);
}
changed.push(origProp);
changed.push(allOrigProps[p]);
}
}
for (var p in allOrigProps) {
}
}
@@ -159,18 +159,10 @@ 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 > 1 && parts[0] === "_Properties") {
if (parts.length > 2 && parts[0] === "_Properties") {
var propertyAlias = parts[1];
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;
}
}
var culture = parts[2];
//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({ skipDefault: true, node: appState.getMenuState("currentNode") });
this.showMenu(undefined, { skipDefault: true, node: appState.getMenuState("currentNode") });
}
},
/**
@@ -140,9 +140,8 @@ function serverValidationManager($timeout) {
}
}
else if (propertyAlias !== undefined) {
//normalize culture to null
if (!culture) {
culture = null;
culture = null; // if empty or null, always make null
}
//don't add it if it already exists
var exists2 = _.find(callbacks, function (item) {
@@ -166,9 +165,8 @@ function serverValidationManager($timeout) {
}
else if (propertyAlias !== undefined) {
//normalize culture to null
if (!culture) {
culture = null;
culture = null; // if empty or null, always make null
}
//remove all callbacks for the content property
@@ -194,9 +192,8 @@ function serverValidationManager($timeout) {
*/
getPropertyCallbacks: function (propertyAlias, culture, fieldName) {
//normalize culture to null
if (!culture) {
culture = null;
culture = null; // if empty or null, always make null
}
var found = _.filter(callbacks, function (item) {
@@ -271,9 +268,8 @@ function serverValidationManager($timeout) {
return;
}
//normalize culture to null
if (!culture) {
culture = null;
culture = null; // if empty or null, always make null
}
//only add the item if it doesn't exist
@@ -310,12 +306,6 @@ 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 === "")));
@@ -364,12 +354,6 @@ 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 === "")));
@@ -404,12 +388,6 @@ 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 === "")));
@@ -168,12 +168,17 @@ a.umb-variant-switcher__toggle {
border-left: 2px solid @turquoise;
}
.umb-variant-switcher_item--disabled .umb-variant-switcher__name-wrapper-disabled {
background-color: @gray-9;
border-left: 2px solid @red;
}
.umb-variant-switcher__item:hover,
.umb-variant-switcher__item:focus,
.umb-variant-switcher__name-wrapper:hover,
.umb-variant-switcher__name-wrapper:focus {
background-color: @gray-10;
outline: none;
background-color: @gray-10;
outline: none;
}
.umb-variant-switcher__item:hover .umb-variant-switcher__split-view {
@@ -190,9 +195,18 @@ a.umb-variant-switcher__toggle {
border-left: 2px solid transparent;
}
.umb-variant-switcher__name-wrapper-disabled {
font-size: 14px;
flex: 1;
cursor: not-allowed;
padding-top: 6px !important;
padding-bottom: 6px !important;
border-left: 2px solid transparent;
}
.umb-variant-switcher__name {
display: block;
font-weight: bold;
display: block;
font-weight: bold;
}
.umb-variant-switcher__state {
@@ -181,7 +181,7 @@
modalClass: "login-overlay",
animation: "slide",
show: true,
callback: callback
callback: callback,
});
}
@@ -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();
});
});
@@ -58,7 +58,7 @@
sort: {
property: {
alias: "",
name: ""
name: "",
},
direction: "ascending", //This is the value for sorting sent to server
translation: {
@@ -49,7 +49,7 @@ angular.module("umbraco")
pageSize: 100,
totalItems: 0,
totalPages: 0,
filter: ''
filter: '',
};
//preload selected item
@@ -169,11 +169,16 @@
<umb-box-content class="block-form">
<umb-control-group data-element="node-info-status" label="@general_status">
<umb-badge size="xs" color="{{variantState.color}}">{{variantState.label}}</umb-badge>
<div ng-repeat="status in publishStatus" style="margin-bottom: 5px;">
<span ng-if="status.culture"><em>{{status.culture}}: </em></span>
<umb-badge size="xs" color="{{status.color}}">
{{status.label}}
</umb-badge>
</div>
</umb-control-group>
<umb-control-group data-element="node-info-create-date" label="@template_createdDate">
{{activeVariant.createDateFormatted}} <localize key="general_by">by</localize> {{ node.owner.name }}
{{node.createDateFormatted}} <localize key="general_by">by</localize> {{ node.owner.name }}
</umb-control-group>
<umb-control-group data-element="node-info-document-type" label="@content_documentType">
@@ -50,6 +50,7 @@
server-validation-field="Alias">
</umb-generate-alias>
<a ng-if="variants.length > 0 && hideChangeVariant !== true" class="umb-variant-switcher__toggle" href="" ng-click="vm.dropdownOpen = !vm.dropdownOpen">
<span>{{vm.currentVariant.language.name}}</span>
<ins class="umb-variant-switcher__expand" ng-class="{'icon-navigation-down': !vm.dropdownOpen, 'icon-navigation-up': vm.dropdownOpen}">&nbsp;</ins>
@@ -60,8 +61,10 @@
</span>
<umb-dropdown ng-if="vm.dropdownOpen" style="width: 100%; max-height: 250px; overflow-y: scroll; margin-top: 5px;" on-close="vm.dropdownOpen = false" umb-keyboard-list>
<umb-dropdown-item class="umb-variant-switcher__item" ng-class="{'umb-variant-switcher_item--current': variant.active}" ng-repeat="variant in variants">
<a href="" class="umb-variant-switcher__name-wrapper" ng-click="selectVariant($event, variant)" prevent-default>
<umb-dropdown-item class="umb-variant-switcher__item" ng-class="{'umb-variant-switcher_item--current': variant.active, 'umb-variant-switcher_item--disabled': variant.disabled}" ng-repeat="variant in variants">
<!--Dropdown in nonsplit view-->
<a ng-if="splitViewOpen !== true" href="" class="umb-variant-switcher__name-wrapper" ng-click="selectVariant($event, variant)" prevent-default>
<span class="umb-variant-switcher__name">{{variant.language.name}}</span>
<span ng-switch="variant.state">
<span class="umb-variant-switcher__state" ng-switch-when="NotCreated"><localize key="content_notCreated"></localize></span>
@@ -70,9 +73,29 @@
<span class="umb-variant-switcher__state" ng-switch-when="Published"><localize key="content_published"></localize></span>
</span>
</a>
<div ng-if="splitViewOpen !== true" class="umb-variant-switcher__split-view" ng-click="openInSplitView($event, variant)">Open in split view</div>
<!--Dropdown in split view -->
<a ng-if="splitViewOpen === true && variant.disabled !== true" href="" class="umb-variant-switcher__name-wrapper" ng-click="selectVariant($event, variant)" prevent-default>
<span class="umb-variant-switcher__name">{{variant.language.name}}</span>
<span ng-switch="variant.state">
<span class="umb-variant-switcher__state" ng-switch-when="NotCreated"><localize key="content_notCreated"></localize></span>
<span class="umb-variant-switcher__state" ng-switch-when="Draft"><localize key="content_unpublished"></localize></span>
<span class="umb-variant-switcher__state" ng-switch-when="PublishedPendingChanges"><localize key="content_publishedPendingChanges"></localize></span>
<span class="umb-variant-switcher__state" ng-switch-when="Published"><localize key="content_published"></localize></span>
</span>
</a>
<a ng-if="splitViewOpen === true && variant.disabled === true" href="" class="umb-variant-switcher__name-wrapper-disabled" prevent-default>
<span class="umb-variant-switcher__name">{{variant.language.name}}</span>
<span ng-switch="variant.state">
<span class="umb-variant-switcher__state" ng-switch-when="NotCreated"><localize key="content_notCreated"></localize></span>
<span class="umb-variant-switcher__state" ng-switch-when="Draft"><localize key="content_unpublished"></localize></span>
<span class="umb-variant-switcher__state" ng-switch-when="PublishedPendingChanges"><localize key="content_publishedPendingChanges"></localize></span>
<span class="umb-variant-switcher__state" ng-switch-when="Published"><localize key="content_published"></localize></span>
</span>
</a>
<div ng-if="splitViewOpen !== true && variant.active != true" class="umb-variant-switcher__split-view" ng-click="openInSplitView($event, variant)">Open in split view</div>
</umb-dropdown-item>
</umb-dropdown>
@@ -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,71 +0,0 @@
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";
}
});
@@ -1,53 +0,0 @@
<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>
@@ -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
}
},
]);
@@ -143,7 +143,7 @@
templateUrl: 'views/propertyeditors/fileupload/fileupload.directive.html',
controller: 'Umbraco.PropertyEditors.FileUploadController',
scope: {
model: "="
model: "=",
},
link: function (scope, element, attrs, ctrl) {
@@ -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,8 +123,7 @@ describe('contentEditingHelper tests', function () {
var allProps = contentEditingHelper.getAllProps(content);
//act
//note the null, that's because culture is null
formHelper.handleServerValidation({ "_Properties.bodyText.null.value": ["Required"] });
formHelper.handleServerValidation({ "_Properties.bodyText.value": ["Required"] });
//assert
expect(serverValidationManager.items.length).toBe(1);
@@ -144,8 +143,7 @@ describe('contentEditingHelper tests', function () {
{
"Name": ["Required"],
"UpdateDate": ["Invalid date"],
//note the null, that's because culture is null
"_Properties.bodyText.null.value": ["Required field"],
"_Properties.bodyText.value": ["Required field"],
"_Properties.textarea": ["Invalid format"]
});
@@ -228,7 +226,6 @@ describe('contentEditingHelper tests', function () {
//act
var changed = contentEditingHelper.reBindChangedProperties(origContent, newContent);
//assert
expect(changed.length).toBe(2);
expect(changed[0].alias).toBe("grid");
@@ -10,39 +10,24 @@ describe('file manager tests', function () {
describe('file management', function () {
it('adding a file adds to the collection', function () {
fileManager.setFiles({
propertyAlias: 'testProp',
files: ["testFile"]
});
fileManager.setFiles('testProp', ["testFile"]);
expect(fileManager.getFiles().length).toBe(1);
});
it('adding a file with the same property id replaces the existing one', function () {
fileManager.setFiles({
propertyAlias: 'testProp',
files: ["testFile"]
});
fileManager.setFiles({
propertyAlias: 'testProp',
files: ["testFile2"]
});
fileManager.setFiles('testProp', ["testFile"]);
fileManager.setFiles('testProp', ["testFile2"]);
expect(fileManager.getFiles().length).toBe(1);
expect(fileManager.getFiles()[0].file).toBe("testFile2");
});
it('clears all files', function () {
fileManager.setFiles({
propertyAlias: 'testProp',
files: ["testFile"]
});
fileManager.setFiles({
propertyAlias: 'testProp2',
files: ["testFile"]
});
fileManager.setFiles('testProp1', ["testFile"]);
fileManager.setFiles('testProp2', ["testFile"]);
expect(fileManager.getFiles().length).toBe(2);
fileManager.clearFiles();
expect(fileManager.getFiles().length).toBe(0);
});
});
});
});
+1
View File
@@ -361,6 +361,7 @@
<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" />
+45 -39
View File
@@ -1,11 +1,19 @@
@using Umbraco.Core
@using System.Collections
@using System.Net.Http
@using System.Web.Mvc.Html
@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 WebViewPage<Umbraco.Web.Editors.BackOfficeModel>
@inherits System.Web.Mvc.WebViewPage<Umbraco.Web.Editors.BackOfficeModel>
@{
var isDebug = false;
@@ -43,25 +51,18 @@
new BasicPath("Umbraco", IOHelper.ResolveUrl(SystemDirectories.Umbraco)),
new BasicPath("UmbracoClient", IOHelper.ResolveUrl(SystemDirectories.UmbracoClient)))
</head>
<noscript><h5><strong>&nbsp; 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 style="display: none;" id="mainwrapper" class="clearfix" ng-click="closeDialogs($event)">
<div 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">
@@ -69,16 +70,18 @@
<div class="umb-editor" ng-view></div>
<div class="umb-editor__overlay" ng-if="editors.length > 0"></div>
<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>
@@ -87,42 +90,45 @@
<!-- 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>
<script type="text/javascript">
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>
<script src="lib/rgrove-lazyload/lazyload.js"></script>
<script src="@Url.GetUrlWithCacheBust("Application", "BackOffice")"></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>
@if (isDebug)
{
@@ -0,0 +1,49 @@
<%@ 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,29 +1,21 @@
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
{
@@ -462,93 +454,5 @@ 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;
}
}
}
@@ -1,27 +0,0 @@
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,6 +6,7 @@ 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;
@@ -73,7 +74,13 @@ 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);
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<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
return menu;
}
@@ -257,6 +257,12 @@ 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();
}
+5 -1
View File
@@ -246,7 +246,6 @@
<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" />
@@ -1296,6 +1295,10 @@
<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>
@@ -1446,6 +1449,7 @@
<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,4 +1,7 @@
namespace Umbraco.Web._Legacy.Actions
using System;
using Umbraco.Web.UI.Pages;
namespace Umbraco.Web._Legacy.Actions
{
/// <summary>
/// This action is invoked when importing a document type
@@ -29,7 +32,7 @@
{
get
{
return "";
return string.Format("{0}.actionImport()", ClientTools.Scripts.GetAppActions);
}
}
@@ -0,0 +1,49 @@
<%@ 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>
@@ -0,0 +1,121 @@
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;
}
}
}