Merge branch 'temp8' of https://github.com/umbraco/Umbraco-CMS into temp8

This commit is contained in:
Stephan
2018-09-30 18:49:50 +02:00
9 changed files with 307 additions and 141 deletions

View File

@@ -0,0 +1,27 @@
(function () {
/**
* @ngdoc directive
* @name umbraco.directives.directive:multi
* @restrict A
* @description Used on input fields when you want to validate multiple fields at once.
**/
function multi($parse, $rootScope) {
return {
restrict: 'A',
require: 'ngModel',
link: function (scope, elem, attrs, ngModelCtrl) {
var validate = $parse(attrs.multi)(scope);
ngModelCtrl.$viewChangeListeners.push(function () {
// ngModelCtrl.$setValidity('multi', validate());
$rootScope.$broadcast('multi:valueChanged');
});
var deregisterListener = scope.$on('multi:valueChanged', function (event) {
ngModelCtrl.$setValidity('multi', validate());
});
scope.$on('$destroy', deregisterListener); // optional, only required for $rootScope.$on
}
};
}
angular.module('umbraco.directives.validation').directive('multi', ['$parse', '$rootScope', multi]);
})();

View File

@@ -242,6 +242,44 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
{ id: id, culture: culture })),
'Failed to publish content with id ' + id);
},
/**
* @ngdoc method
* @name umbraco.resources.contentResource#getCultureAndDomains
* @methodOf umbraco.resources.contentResource
*
* @description
* Gets the culture and hostnames for a content item with the given Id
*
* ##usage
* <pre>
* contentResource.getCultureAndDomains(1234)
* .then(function(data) {
* alert(data.Domains, data.Language);
* });
* </pre>
* @param {Int} id the ID of the node to get the culture and domains for.
* @returns {Promise} resourcePromise object.
*
*/
getCultureAndDomains: function (id) {
if (!id) {
throw "id cannot be null";
}
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"contentApiBaseUrl",
"GetCultureAndDomains", { id: id })),
'Failed to retreive culture and hostnames for ' + id);
},
saveLanguageAndDomains: function (model) {
return umbRequestHelper.resourcePromise(
$http.post(
umbRequestHelper.getApiUrl(
"contentApiBaseUrl",
"PostSaveLanguageAndDomains"),
model));
},
/**
* @ngdoc method
* @name umbraco.resources.contentResource#emptyRecycleBin
@@ -334,26 +372,26 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
*/
getById: function (id) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"contentApiBaseUrl",
"GetById",
{ id: id })),
'Failed to retrieve data for content id ' + id)
.then(function(result) {
$http.get(
umbRequestHelper.getApiUrl(
"contentApiBaseUrl",
"GetById",
{ id: id })),
'Failed to retrieve data for content id ' + id)
.then(function (result) {
return $q.when(umbDataFormatter.formatContentGetData(result));
});
},
getBlueprintById: function (id) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"contentApiBaseUrl",
"GetBlueprintById",
[{ id: id }])),
'Failed to retrieve data for content id ' + id)
.then(function(result) {
$http.get(
umbRequestHelper.getApiUrl(
"contentApiBaseUrl",
"GetBlueprintById",
[{ id: id }])),
'Failed to retrieve data for content id ' + id)
.then(function (result) {
return $q.when(umbDataFormatter.formatContentGetData(result));
});
},
@@ -410,15 +448,15 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
});
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"contentApiBaseUrl",
"GetByIds",
idQuery)),
'Failed to retrieve data for content with multiple ids')
$http.get(
umbRequestHelper.getApiUrl(
"contentApiBaseUrl",
"GetByIds",
idQuery)),
'Failed to retrieve data for content with multiple ids')
.then(function (result) {
//each item needs to be re-formatted
_.each(result, function(r) {
_.each(result, function (r) {
umbDataFormatter.formatContentGetData(r)
});
return $q.when(result);
@@ -461,13 +499,13 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
getScaffold: function (parentId, alias) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"contentApiBaseUrl",
"GetEmpty",
[{ contentTypeAlias: alias }, { parentId: parentId }])),
'Failed to retrieve data for empty content item type ' + alias)
.then(function(result) {
$http.get(
umbRequestHelper.getApiUrl(
"contentApiBaseUrl",
"GetEmpty",
[{ contentTypeAlias: alias }, { parentId: parentId }])),
'Failed to retrieve data for empty content item type ' + alias)
.then(function (result) {
return $q.when(umbDataFormatter.formatContentGetData(result));
});
},
@@ -475,13 +513,13 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
getBlueprintScaffold: function (parentId, blueprintId) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"contentApiBaseUrl",
"GetEmpty",
[{ blueprintId: blueprintId }, { parentId: parentId }])),
'Failed to retrieve blueprint for id ' + blueprintId)
.then(function(result) {
$http.get(
umbRequestHelper.getApiUrl(
"contentApiBaseUrl",
"GetEmpty",
[{ blueprintId: blueprintId }, { parentId: parentId }])),
'Failed to retrieve blueprint for id ' + blueprintId)
.then(function (result) {
return $q.when(umbDataFormatter.formatContentGetData(result));
});
},

View File

@@ -1,24 +1,70 @@
<div ng-controller="Umbraco.Editors.Content.AssignDomainController as vm">
<div class="umb-dialog-body">
<umb-pane>
<p>UI magic to be done...</p>
</umb-pane>
</div>
<div ng-controller="Umbraco.Editors.Content.AssignDomainController as vm" ng-cloak>
<div class="umb-dialog-body">
<umb-pane>
<h5 class="umb-pane-title"><localize key="assignDomain_setLanguage">Culture</localize></h5>
<label for="assignDomain_language" class="control-label"><localize key="general_language"></localize></label>
<select class="umb-property-editor umb-dropdown" name="language" id="assignDomain_language" ng-model="vm.language" ng-options="lang.name for lang in vm.languages">
<option value="">{{vm.inherit}}</option>
</select>
</umb-pane>
<umb-pane>
<h5 class="umb-pane-title"><localize key="assignDomain_setDomains">Domains</localize></h5>
<form name="vm.domainForm" novalidate="" ng-submit="vm.save()" class="control-group umb-control-group">
<small class="help-inline">
<localize key="assignDomain_domainHelp"></localize>
</small>
<div class="umb-el-wrap hidelabel">
<table class="table domains" ng-if="vm.domains.length > 0">
<thead>
<tr>
<th><localize key="assignDomain_domain"></localize></th>
<th><localize key="assignDomain_language"></localize></th>
<th />
</tr>
</thead>
<tbody>
<tr ng-repeat="domain in vm.domains">
<td>
<input type="text" ng-model="domain.Name" multi="vm.validateDomain" ng-pattern="vm.domainPattern" name="domain_name_{{$index}}" />
<span ng-if="vm.domainForm.$submitted" ng-messages="vm.domainForm['domain_name_' + $index].$error">
<span class="help-inline" ng-message="multi"><localize key="assignDomain_duplicateDomain"></localize></span>
<span class="help-inline" ng-message="pattern"><localize key="assignDomain_invalidDomain"></localize></span>
</span>
</td>
<td>
<select name="domain_language_{{$index}}" class="language" ng-model="domain.Lang" ng-options="lang.name for lang in vm.languages"></select>
</td>
<td>
<umb-button icon="icon-trash"
action="vm.removeDomain($index)"
type="button"
button-style="danger">
</umb-button>
</td>
</tr>
</tbody>
</table>
</div>
<umb-button label-key="assignDomain_addNew"
action="vm.addDomain()"
type="button">
</umb-button>
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar">
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar">
<umb-button label-key="general_cancel"
action="vm.closeDialog()"
type="button"
button-style="link">
</umb-button>
<umb-button
label-key="general_cancel"
action="vm.closeDialog()"
type="button"
button-style="link">
</umb-button>
<umb-button
label-key="buttons_save"
type="button"
button-style="success">
</umb-button>
<umb-button label-key="buttons_save"
type="submit"
button-style="success">
</umb-button>
</div>
</form>
</umb-pane>
</div>
</div>

View File

@@ -1,17 +1,126 @@
(function () {
"use strict";
function AssignDomainController($scope) {
function AssignDomainController($scope, localizationService, languageResource, contentResource) {
var vm = this;
vm.closeDialog = closeDialog;
function closeDialog() {
$scope.nav.hideDialog();
vm.addDomain = addDomain;
vm.removeDomain = removeDomain;
vm.save = save;
vm.validateDomain = validateDomain;
vm.languages = [];
vm.domains = [];
vm.language = null;
vm.domainPattern = /^(http[s]?:\/\/)?([-\w]+(\.[-\w]+)*)(:\d+)?(\/[-\w]*|-)?$/gi; //TODO: This regex is not working as it should.
function activate() {
languageResource.getAll().then(function (langs) {
vm.languages = langs;
var defLang = langs.filter(function (l) {
return l.isDefault;
});
if (defLang.length > 0) {
vm.defaultLanguage = defLang[0];
}
else {
vm.defaultLanguage = langs[0];
}
getCultureAndDomains();
});
localizationService.localize("assignDomain_inherit").then(function (value) {
vm.inherit = value;
});
}
function getCultureAndDomains () {
contentResource.getCultureAndDomains($scope.currentNode.id)
.then(function (data) {
if (data.Language !== "undefined") {
var lang = vm.languages.filter(function (l) {
return matchLanguageById(l, data.Language.Id);
});
if (lang.length > 0) {
vm.language = lang[0];
}
}
vm.domains = data.Domains.map(function (d) {
var matchedLangs = vm.languages.filter(function (l) {
return matchLanguageById(l, d.Language);
});
return {
Name: d.Name,
Lang: matchedLangs.length > 0 ? matchedLangs[0] : vm.defaultLanguage
}
});
});
}
function matchLanguageById(language, id) {
return language.Id === id;
}
function closeDialog() {
$scope.nav.hideDialog();
}
function addDomain() {
vm.domains.push({
Name: '',
Lang: vm.defaultLanguage
});
}
function removeDomain(index) {
vm.domains.splice(index, 1);
}
function validateDomain() {
var valid = true, duplicateTest = {};
if (vm.domains.length > 1) {
vm.domains.map(function (d, index) {
if (d.Name in duplicateTest) {
valid = false;
}
else {
duplicateTest[d.Name] = index;
}
});
}
return valid;
}
function save() {
if (vm.domainForm.$valid) {
var data = {
NodeId: $scope.currentNode.id,
Domains: vm.domains.map(function (d) {
return {
Name: d.Name,
Lang: d.Lang.id
};
}),
Language: vm.language != null ? vm.language.id : 0
};
console.log(data);
contentResource.saveLanguageAndDomains(data).then(function () {
closeDialog();
}, function (e) {
console.log(e); //TODO: not sure how best to handle this case
});
}
else {
console.log('not valid');
}
}
activate();
}
angular.module("umbraco").controller("Umbraco.Editors.Content.AssignDomainController", AssignDomainController);
})();
})();

View File

@@ -333,7 +333,6 @@
<Content Include="Umbraco\Developer\RelationTypes\RelationTypesWebService.asmx" />
<Content Include="Umbraco\Developer\RelationTypes\TreeMenu\ActionDeleteRelationType.js" />
<Content Include="Umbraco\Developer\RelationTypes\TreeMenu\ActionNewRelationType.js" />
<Content Include="Umbraco\Dialogs\AssignDomain2.aspx" />
<Content Include="Umbraco\Dialogs\ChangeDocType.aspx">
<SubType>ASPXCodeBehind</SubType>
</Content>

View File

@@ -1,79 +0,0 @@
<%@ Page Language="c#" MasterPageFile="../masterpages/umbracoDialog.Master" Codebehind="AssignDomain2.aspx.cs" AutoEventWireup="True" Inherits="umbraco.dialogs.AssignDomain2" %>
<%@ Import Namespace="Umbraco.Web" %>
<%@ Register TagPrefix="umb" Namespace="ClientDependency.Core.Controls" Assembly="ClientDependency.Core" %>
<%@ Register TagPrefix="cc1" Namespace="Umbraco.Web._Legacy.Controls" Assembly="Umbraco.Web" %>
<asp:Content ContentPlaceHolderID="head" runat="server">
<umb:JsInclude runat="server" FilePath="Dialogs/AssignDomain2.js" PathNameAlias="UmbracoClient" />
<umb:JsInclude runat="server" FilePath="PunyCode/punycode.min.js" PathNameAlias="UmbracoClient" />
<umb:JsInclude runat="server" FilePath="/Umbraco/lib/jquery-validate/jquery.validate.min.js" PathNameAlias="UmbracoClient" />
<umb:CssInclude runat="server" FilePath="Dialogs/AssignDomain2.css" PathNameAlias="UmbracoClient" />
<script type="text/javascript">
(function ($) {
$(document).ready(function () {
var dialog = new Umbraco.Dialogs.AssignDomain2({
nodeId: <%=GetNodeId()%>,
restServiceLocation: '<%=GetRestServicePath() %>',
invalidDomain: '<%=Services.TextService.Localize("assignDomain/invalidDomain") %>',
duplicateDomain: '<%=Services.TextService.Localize("assignDomain/duplicateDomain") %>',
<asp:Literal runat="server" ID="data" />
});
dialog.init();
});
})(jQuery);
</script>
</asp:Content>
<asp:Content ContentPlaceHolderID="body" runat="server">
<div class="umb-dialog-body">
<cc1:Feedback ID="feedback" runat="server" />
<div id="komask"></div>
<cc1:Pane runat="server" ID="pane_language" cssClass="hide">
<cc1:PropertyPanel runat="server" ID="prop_language">
<select class="umb-property-editor umb-dropdown" name="language" data-bind="options: languages, optionsText: 'Code', optionsValue: 'Id', value: language, optionsCaption: '<%=Services.TextService.Localize("assignDomain/inherit") %> '"></select>
<!-- <small class="help-inline"><%=Services.TextService.Localize("assignDomain/setLanguageHelp") %></small>-->
</cc1:PropertyPanel>
</cc1:Pane>
<cc1:Pane runat="server" ID="pane_domains">
<small class="help-inline"><%=Services.TextService.Localize("assignDomain/domainHelp") %></small>
<cc1:PropertyPanel runat="server">
<table class="table domains" data-bind="visible: domains().length > 0">
<thead>
<tr>
<th><%=Services.TextService.Localize("assignDomain/domain") %></th>
<th><%=Services.TextService.Localize("assignDomain/language") %></th>
<th />
</tr>
</thead>
<tbody data-bind="foreach: domains">
<tr>
<td valign="top"><input class="domain duplicate" data-bind="value: Name, uniqueName: true" /><input type="hidden" value="" data-bind="uniqueName: true"/></td>
<td valign="top"><select class="language" data-bind="options: $parent.languages, optionsText: 'Code', optionsValue: 'Id', value: Lang, uniqueName: true"></select></td>
<td valign="top"><a href="#" class="btn btn-danger" data-bind="click: $parent.removeDomain"><i class="icon icon-trash"></i></a></td>
</tr>
</tbody>
</table>
</cc1:PropertyPanel>
<cc1:PropertyPanel runat="server">
<button class="btn" data-bind="click: addDomain"><%=Services.TextService.Localize("assignDomain/addNew") %></button>
</cc1:PropertyPanel>
</cc1:Pane>
</div>
<div runat="server" ID="p_buttons" class="umb-dialog-footer btn-toolbar umb-btn-toolbar">
<a href="#" class="btn btn-link" onclick="UmbClientMgr.closeModalWindow()"><%=Services.TextService.Localize("general/cancel")%></a>
<button class="btn btn-primary" id="btnSave"><%=Services.TextService.Localize("buttons/save") %></button>
</div>
</asp:Content>

View File

@@ -56,6 +56,8 @@ namespace Umbraco.Web.Editors
private readonly PropertyEditorCollection _propertyEditors;
private readonly Lazy<IDictionary<string, ILanguage>> _allLangs;
public object Domains { get; private set; }
public ContentController(IPublishedSnapshotService publishedSnapshotService, PropertyEditorCollection propertyEditors)
{
if (publishedSnapshotService == null) throw new ArgumentNullException(nameof(publishedSnapshotService));
@@ -1146,6 +1148,18 @@ namespace Umbraco.Web.Editors
}
}
public ContentDomainsAndCulture GetCultureAndDomains(int id)
{
var nodeDomains = Services.DomainService.GetAssignedDomains(id, true).ToArray();
var wildcard = nodeDomains.FirstOrDefault(d => d.IsWildcard);
var domains = nodeDomains.Where(d => !d.IsWildcard).Select(d => new DomainDisplay(d.DomainName, d.LanguageId.GetValueOrDefault(0)));
return new ContentDomainsAndCulture
{
Domains = domains,
Language = wildcard == null || !wildcard.LanguageId.HasValue ? "undefined" : wildcard.LanguageId.ToString()
};
}
[HttpPost]
public DomainSave PostSaveLanguageAndDomains(DomainSave model)
{

View File

@@ -0,0 +1,11 @@
using System.Collections.Generic;
namespace Umbraco.Web.Models.ContentEditing
{
public class ContentDomainsAndCulture
{
public IEnumerable<DomainDisplay> Domains { get; set; }
public string Language { get; internal set; }
}
}

View File

@@ -163,6 +163,7 @@
<Compile Include="Editors\BackOfficeServerVariables.cs" />
<Compile Include="ImageProcessorLogger.cs" />
<Compile Include="Macros\MacroTagParser.cs" />
<Compile Include="Models\ContentEditing\ContentDomainsAndCulture.cs" />
<Compile Include="Models\ContentEditing\ContentSavedState.cs" />
<Compile Include="Models\Mapping\ContentSavedStateResolver.cs" />
<Compile Include="OwinExtensions.cs" />