Compare commits

...

44 Commits

Author SHA1 Message Date
Kenn Jacobsen 19aae9ffdc Make sure the color picker label is stored on first select (#4325)
(cherry picked from commit 4dd51f645a)
2019-01-30 16:14:09 +01:00
Sebastiaan Janssen 218995f9e0 Set version to 7.13.2 2019-01-29 17:34:05 +01:00
Kenn Jacobsen 0d167c4f2d Fix callback
(cherry picked from commit 99f0e6c05a)
2019-01-29 14:13:22 +01:00
Kenn Jacobsen d44e0d8664 Set form dirty on color picker value change + update selected item label + clean up unused code
(cherry picked from commit 2c40e46d56)
2019-01-29 14:13:14 +01:00
Sebastiaan Janssen f7671ec9a7 Fixes #4071 - Error executing scheduled task - This instance has already started one or more requests. 2019-01-15 08:39:43 +01:00
Kenn Jacobsen b9430158ce Move member group picker property data store from NVarchar to NText (#3712) 2019-01-14 09:25:59 +01:00
Kenn Jacobsen db8954e0a5 Verify that the current member is approved and not locked out (#3588) 2019-01-14 08:52:02 +01:00
Sebastiaan Janssen 05f1a24caf Fix duplicate IIS Express settings 2019-01-14 08:28:58 +01:00
Kenn Jacobsen b08e922600 Only allow setting up scheduled publishing if the user has the correct permissions to do so 2019-01-14 08:21:58 +01:00
Kenn Jacobsen fbf60fbac4 Don't add the "Notification" tree menu item if Umbraco can't send emails 2019-01-14 08:13:10 +01:00
Kenn Jacobsen 941baf09ce Fix linkpicker overlay issues (#3718) 2019-01-13 16:17:44 +01:00
Anders Bjerner be44741bf9 Localized parts of the codefile and template resources (#3495) 2019-01-13 15:58:31 +01:00
christophnz 282ac2b9c5 Added 2 HtmlHelper extension methods for rendering RelatedLinks, including Unit tests 2019-01-13 15:17:13 +01:00
Jannik Anker 1224f68297 Issue 3018 - non-admin users cannot create groups (derpness cleanup) 2019-01-13 15:13:26 +01:00
Jannik Anker 8d1733fd12 Issue 3018 - non-admin users cannot create groups 2019-01-13 15:13:26 +01:00
Bjarne Fyrstenborg 1213551ca9 Only show extension if media item has a file
(cherry picked from commit 168febae24)
2019-01-13 14:55:44 +01:00
Steve f620d0deca Fixes #4016 unpublished content styling in list view 2019-01-13 14:43:24 +01:00
Kenn Jacobsen d1cfe84723 Set the form dirty when changing focal point and editing crops 2019-01-13 14:01:11 +01:00
Kenn Jacobsen cd6cdcfda4 Visualize image transparency in upload and image cropper thumbnails (#4050) 2019-01-13 13:54:30 +01:00
Bjarne Fyrstenborg 2ebd7a077c Fix placeholder text when empty alias input after generating alias (#4032)
(cherry picked from commit c619b79276)
2019-01-13 13:16:00 +01:00
Sebastiaan Janssen 9e33581391 Merge branch 'patch-7.13.1' into dev-v7
# Conflicts:
#	src/SolutionInfo.cs
#	src/Umbraco.Core/Configuration/UmbracoVersion.cs
2019-01-11 09:53:50 +01:00
Quan Tran 59349dd355 Fix - refine code 2019-01-10 19:35:51 +01:00
Quan Tran 4170faf76e add null checking 2019-01-10 19:35:51 +01:00
Sebastian Hoffback cc13b99787 Removed already deleted file canvasdesigner.panel.js from canvasdesigner.loader.js 2019-01-10 19:32:59 +01:00
Kenn Jacobsen d41dbce601 Fix content picker dirty checking (#4003) 2019-01-09 11:20:34 +01:00
Sebastiaan Janssen 0f61de8bcd Bumps version to 7.14.0 2019-01-08 21:49:17 +01:00
Sebastiaan Janssen caf7a6a1ca Fixes #4000 - 7.13.0 Creating new node as an editor causes exception 2019-01-08 21:32:47 +01:00
Sebastiaan Janssen e0a38a4d9b Git clone includes a directory to clone to now,
should fix Azure Gallery release.
Tightened up the variables and paths.
2019-01-08 15:53:58 +01:00
Sebastiaan Janssen 086157cff8 Fixes #3990 All images uploaded to media section have umbracoHeight / umbracoWidth of 200x200px 2019-01-08 12:51:14 +01:00
Sebastiaan Janssen 21612454d0 Update umbtoggle.directive.js 2019-01-07 13:45:43 +01:00
Sebastiaan Janssen d53d0b4271 Add disabled state to toggle (#3967)
(cherry picked from commit d231db8ef2)

# Conflicts:
#	src/Umbraco.Web.UI.Client/src/views/languages/edit.html
2019-01-07 12:53:31 +01:00
Kenn Jacobsen 4564623899 Don't use a hardcoded folder type alias to determine folder types in the list view 2019-01-07 12:31:05 +01:00
Kenn Jacobsen cc6c16894c Safeguard the tags value converter against empty tags 2019-01-07 10:36:05 +01:00
Floris Robbemont 0852b20b31 Fix for wrong sorting overload in MediaService (#3948) 2019-01-04 11:55:52 +00:00
Claus 08e13ac530 Merge pull request #3814 from umbraco/temp7-269-xss-stylesheets
Removing malicious code from the name of a Stylesheet.
2019-01-04 10:11:25 +01:00
Claus 71f2b7ee06 updating unit tests. 2019-01-04 09:40:55 +01:00
Claus 7ead62730b reverting changes to StripHtml method. 2019-01-04 09:34:24 +01:00
elitsa 0aa1dc1dc7 Adding tests for verifying that malicious code input will be cleaned for XSS. 2018-12-27 10:02:49 +01:00
elitsa bb60d5e035 Reverting changes made from merge. 2018-12-27 09:57:31 +01:00
elitsa 247f213d26 Merge remote-tracking branch 'origin/dev-v7' into temp7-269-xss-stylesheets 2018-12-27 08:50:44 +01:00
elitsa d7696e8d91 Making a variable const 2018-12-18 11:34:50 +01:00
elitsa 8518aaf4c1 Merge branch 'temp7-269-xss-stylesheets' of https://github.com/umbraco/Umbraco-CMS into temp7-269-xss-stylesheets
# Conflicts:
#	src/Umbraco.Core/StringExtensions.cs
2018-12-10 11:00:31 +01:00
elitsa 9edafe37e1 Merge branch 'dev-v7' into temp7-269-xss-stylesheets
# Conflicts resolved:
#	src/Umbraco.Core/StringExtensions.cs
2018-12-10 10:57:30 +01:00
Elitsa Marinovska 914d956ada Merge branch 'dev-v7' into temp7-269-xss-stylesheets 2018-12-03 12:50:40 +01:00
47 changed files with 810 additions and 576 deletions
+2 -2
View File
@@ -11,5 +11,5 @@ using System.Resources;
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("7.13.1")]
[assembly: AssemblyInformationalVersion("7.13.1")]
[assembly: AssemblyFileVersion("7.13.2")]
[assembly: AssemblyInformationalVersion("7.13.2")]
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration
{
public class UmbracoVersion
{
private static readonly Version Version = new Version("7.13.1");
private static readonly Version Version = new Version("7.13.2");
/// <summary>
/// Gets the current version of Umbraco.
@@ -0,0 +1,36 @@
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenFourteenZero
{
/// <summary>
/// Migrates member group picker properties from NVarchar to NText. See https://github.com/umbraco/Umbraco-CMS/issues/3268.
/// </summary>
[Migration("7.14.0", 1, Constants.System.UmbracoMigrationName)]
public class UpdateMemberGroupPickerData : MigrationBase
{
public UpdateMemberGroupPickerData(ISqlSyntaxProvider sqlSyntax, ILogger logger) : base(sqlSyntax, logger)
{
}
public override void Up()
{
// move the data for all member group properties from the NVarchar to the NText column and clear the NVarchar column
Execute.Sql(@"UPDATE cmsPropertyData SET dataNtext = dataNvarchar, dataNvarchar = NULL
WHERE dataNtext IS NULL AND id IN (
SELECT id FROM cmsPropertyData WHERE propertyTypeId in (
SELECT id from cmsPropertyType where dataTypeID IN (
SELECT nodeId FROM cmsDataType WHERE propertyEditorAlias = 'Umbraco.MemberGroupPicker'
)
)
)");
// ensure that all exising member group properties are defined as NText
Execute.Sql("UPDATE cmsDataType SET dbType = 'Ntext' WHERE propertyEditorAlias = 'Umbraco.MemberGroupPicker'");
}
public override void Down()
{
}
}
}
+1 -2
View File
@@ -189,7 +189,6 @@ namespace Umbraco.Core
outputArray[i] = char.IsLetterOrDigit(inputArray[i]) ? inputArray[i] : replacement;
return new string(outputArray);
}
private static readonly char[] CleanForXssChars = "*?(){}[];:%<>/\\|&'\"".ToCharArray();
/// <summary>
@@ -542,7 +541,7 @@ namespace Umbraco.Core
public static string StripHtml(this string text)
{
const string pattern = @"<(.|\n)*?>";
return Regex.Replace(text, pattern, String.Empty);
return Regex.Replace(text, pattern, string.Empty);
}
/// <summary>
+1
View File
@@ -572,6 +572,7 @@
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenEightZero\AddInstructionCountColumn.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenEightZero\AddCmsMediaTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenEightZero\AddUserLoginTable.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenFourteenZero\UpdateMemberGroupPickerData.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenTwelveZero\RenameTrueFalseField.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenTwelveZero\SetDefaultTagsStorageType.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenNineZero\AddUmbracoAuditTable.cs" />
@@ -61,6 +61,17 @@ namespace Umbraco.Tests.Strings
Assert.AreEqual(stripped, result);
}
[TestCase("'+alert(1234)+'", "+alert1234+")]
[TestCase("'+alert(56+78)+'", "+alert56+78+")]
[TestCase("{{file}}", "file")]
[TestCase("'+alert('hello')+'", "+alerthello+")]
[TestCase("Test", "Test")]
public void Clean_From_XSS(string input, string result)
{
var cleaned = input.CleanForXss();
Assert.AreEqual(cleaned, result);
}
[TestCase("This is a string to encrypt")]
[TestCase("This is a string to encrypt\nThis is a second line")]
[TestCase(" White space is preserved ")]
@@ -29,5 +29,30 @@ namespace Umbraco.Tests.Web.Mvc
var output = _htmlHelper.Wrap("div", "hello world", new {style = "color:red;", onclick = "void();"});
Assert.AreEqual("<div style=\"color:red;\" onclick=\"void();\">hello world</div>", output.ToHtmlString());
}
}
}
[Test]
public void GetRelatedLinkHtml_Simple()
{
var relatedLink = new Umbraco.Web.Models.RelatedLink {
Caption = "Link Caption",
NewWindow = true,
Link = "https://www.google.com/"
};
var output = _htmlHelper.GetRelatedLinkHtml(relatedLink);
Assert.AreEqual("<a href=\"https://www.google.com/\" target=\"_blank\">Link Caption</a>", output.ToHtmlString());
}
[Test]
public void GetRelatedLinkHtml_HtmlAttributes()
{
var relatedLink = new Umbraco.Web.Models.RelatedLink
{
Caption = "Link Caption",
NewWindow = true,
Link = "https://www.google.com/"
};
var output = _htmlHelper.GetRelatedLinkHtml(relatedLink, new { @class = "test-class"});
Assert.AreEqual("<a class=\"test-class\" href=\"https://www.google.com/\" target=\"_blank\">Link Caption</a>", output.ToHtmlString());
}
}
}
@@ -11,8 +11,7 @@ LazyLoad.js([
'../js/umbraco.security.js',
'../ServerVariables',
'../lib/spectrum/spectrum.js',
'../js/umbraco.canvasdesigner.js',
'../js/canvasdesigner.panel.js'
'../js/umbraco.canvasdesigner.js'
], function () {
jQuery(document).ready(function () {
angular.bootstrap(document, ['Umbraco.canvasdesigner']);
@@ -18,6 +18,7 @@
<umb-toggle
checked="vm.checked"
disabled="vm.disabled"
on-click="vm.toggle()"
show-labels="true"
label-on="Start"
@@ -38,6 +39,7 @@
var vm = this;
vm.checked = false;
vm.disabled = false;
vm.toggle = toggle;
@@ -52,6 +54,7 @@
</pre>
@param {boolean} checked Set to <code>true</code> or <code>false</code> to toggle the switch.
@param {boolean} disabled Set to <code>true</code> or <code>false</code> to disable/enable the switch.
@param {callback} onClick The function which should be called when the toggle is clicked.
@param {string=} showLabels Set to <code>true</code> or <code>false</code> to show a "On" or "Off" label next to the switch.
@param {string=} labelOn Set a custom label for when the switched is turned on. It will default to "On".
@@ -115,6 +118,7 @@
templateUrl: 'views/components/buttons/umb-toggle.html',
scope: {
checked: "=",
disabled: "=",
onClick: "&",
labelOn: "@?",
labelOff: "@?",
@@ -53,6 +53,9 @@
if (scope.documentType !== null) {
scope.previewOpenUrl = '#/settings/documenttypes/edit/' + scope.documentType.id;
}
// only allow configuring scheduled publishing if the user has publish ("U") and unpublish ("Z") permissions on this node
scope.allowScheduledPublishing = _.contains(scope.node.allowedActions, "U") && _.contains(scope.node.allowedActions, "Z");
}
scope.auditTrailPageChange = function (pageNumber) {
@@ -14,7 +14,8 @@ angular.module("umbraco.directives")
scope: {
src: '=',
center: "=",
onImageLoaded: "&"
onImageLoaded: "&",
onGravityChanged: "&"
},
link: function(scope, element, attrs) {
@@ -52,7 +53,7 @@ angular.module("umbraco.directives")
calculateGravity(offsetX, offsetY);
lazyEndEvent();
gravityChanged();
};
var setDimensions = function () {
@@ -77,12 +78,11 @@ angular.module("umbraco.directives")
scope.center.top = (scope.dimensions.top+10) / scope.dimensions.height;
};
var lazyEndEvent = _.debounce(function(){
scope.$apply(function(){
scope.$emit("imageFocalPointStop");
});
}, 2000);
var gravityChanged = function () {
if (angular.isFunction(scope.onGravityChanged)) {
scope.onGravityChanged();
}
};
//Drag and drop positioning, using jquery ui draggable
//TODO ensure that the point doesnt go outside the box
@@ -100,7 +100,7 @@ angular.module("umbraco.directives")
calculateGravity(offsetX, offsetY);
});
lazyEndEvent();
gravityChanged();
}
});
@@ -86,20 +86,21 @@ angular.module("umbraco.directives")
function generateAlias(value) {
if (generateAliasTimeout) {
$timeout.cancel(generateAliasTimeout);
$timeout.cancel(generateAliasTimeout);
}
if( value !== undefined && value !== "" && value !== null) {
if (value !== undefined && value !== "" && value !== null) {
scope.alias = "";
scope.alias = "";
scope.placeholderText = scope.labels.busy;
generateAliasTimeout = $timeout(function () {
updateAlias = true;
entityResource.getSafeAlias(encodeURIComponent(value), true).then(function (safeAlias) {
if (updateAlias) {
scope.alias = safeAlias.alias;
}
scope.alias = safeAlias.alias;
}
scope.placeholderText = scope.labels.idle;
});
}, 500);
@@ -108,7 +109,6 @@ angular.module("umbraco.directives")
scope.alias = "";
scope.placeholderText = scope.labels.idle;
}
}
// if alias gets unlocked - stop watching alias
@@ -119,17 +119,17 @@ angular.module("umbraco.directives")
}));
// validate custom entered alias
eventBindings.push(scope.$watch('alias', function(newValue, oldValue){
if(scope.alias === "" && bindWatcher === true || scope.alias === null && bindWatcher === true) {
// add watcher
eventBindings.push(scope.$watch('aliasFrom', function(newValue, oldValue) {
if(bindWatcher) {
generateAlias(newValue);
}
}));
}
eventBindings.push(scope.$watch('alias', function (newValue, oldValue) {
if (scope.alias === "" || scope.alias === null || scope.alias === undefined) {
if (bindWatcher === true) {
// add watcher
eventBindings.push(scope.$watch('aliasFrom', function (newValue, oldValue) {
if (bindWatcher) {
generateAlias(newValue);
}
}));
}
}
}));
// clean up
@@ -38,7 +38,7 @@ Use this directive to generate color swatches to pick from.
scope.selectedColor = color;
if (scope.onSelect) {
scope.onSelect(color);
scope.onSelect({color: color });
}
};
}
@@ -3,7 +3,7 @@
* @name umbraco.resources.codefileResource
* @description Loads in data for files that contain code such as js scripts, partial views and partial view macros
**/
function codefileResource($q, $http, umbDataFormatter, umbRequestHelper) {
function codefileResource($q, $http, umbDataFormatter, umbRequestHelper, localizationService) {
return {
@@ -106,13 +106,16 @@ function codefileResource($q, $http, umbDataFormatter, umbRequestHelper) {
*
*/
deleteByPath: function (type, virtualpath) {
var promise = localizationService.localize("codefile_deleteItemFailed", [virtualpath]);
return umbRequestHelper.resourcePromise(
$http.post(
umbRequestHelper.getApiUrl(
"codeFileApiBaseUrl",
"Delete",
[{ type: type }, { virtualPath: virtualpath}])),
"Failed to delete item: " + virtualpath);
promise);
},
/**
@@ -236,13 +239,19 @@ function codefileResource($q, $http, umbDataFormatter, umbRequestHelper) {
*
*/
createContainer: function(type, parentId, name) {
createContainer: function (type, parentId, name) {
// Is the parent ID numeric?
var key = "codefile_createFolderFailedBy" + (isNaN(parseInt(parentId)) ? "Name" : "Id");
var promise = localizationService.localize(key, [parentId]);
return umbRequestHelper.resourcePromise(
$http.post(umbRequestHelper.getApiUrl(
"codeFileApiBaseUrl",
"PostCreateContainer",
{ type: type, parentId: parentId, name: encodeURIComponent(name) })),
'Failed to create a folder under parent id ' + parentId);
promise);
}
};
@@ -3,7 +3,7 @@
* @name umbraco.resources.templateResource
* @description Loads in data for templates
**/
function templateResource($q, $http, umbDataFormatter, umbRequestHelper) {
function templateResource($q, $http, umbDataFormatter, umbRequestHelper, localizationService) {
return {
@@ -152,13 +152,16 @@ function templateResource($q, $http, umbDataFormatter, umbRequestHelper) {
*
*/
deleteById: function(id) {
var promise = localizationService.localize("template_deleteByIdFailed", [id]);
return umbRequestHelper.resourcePromise(
$http.post(
umbRequestHelper.getApiUrl(
"templateApiBaseUrl",
"DeleteById",
[{ id: id }])),
"Failed to delete item " + id);
promise);
},
/**
@@ -28,7 +28,8 @@
.umb-toggle__toggle {
cursor: pointer;
display: inline-block;
align-items: center;
display: flex;
width: 48px;
height: 24px;
background: @gray-8;
@@ -41,6 +42,11 @@
background-color: @green;
}
.umb-toggle--disabled .umb-toggle__toggle {
cursor: not-allowed;
opacity: 0.8;
}
.umb-toggle--checked .umb-toggle__handler {
transform: translate3d(24px, 0, 0) rotate(0);
}
@@ -63,7 +69,7 @@
.umb-toggle__icon {
position: absolute;
top: 3px;
line-height: 1em;
text-decoration: none;
transition: all 0.2s ease;
}
@@ -165,7 +165,7 @@ input.umb-table__input {
}
.-content :not(.with-unpublished-version).-unpublished {
.-content .-unpublished:not(.with-unpublished-version) {
.umb-table__name > * {
opacity: .4;
}
@@ -21,6 +21,12 @@
cursor: pointer;
}
.umb-permission--disabled .umb-permission__toggle,
.umb-permission--disabled .umb-permission__content {
cursor: not-allowed;
opacity: 0.8;
}
.umb-permission__description {
font-size: 13px;
color: @gray-5;
@@ -1,3 +1,5 @@
@checkered-background: url(../img/checkered-background.png);
//
// Container styles
// --------------------------------------------------
@@ -386,7 +388,7 @@ div.umb-codeeditor .umb-btn-toolbar {
max-height:100%;
margin:auto;
display:block;
background-image: url(../img/checkered-background.png);
background-image: @checkered-background;
}
.umb-sortable-thumbnails li .trashed {
@@ -599,12 +601,18 @@ div.umb-codeeditor .umb-btn-toolbar {
vertical-align: top;
}
.gravity-container .viewport {
max-width: 600px;
}
.gravity-container {
border: 1px solid @gray-8;
line-height: 0;
.gravity-container .viewport:hover {
cursor: pointer;
.viewport {
max-width: 600px;
background: @checkered-background;
&:hover {
cursor: pointer;
}
}
}
.imagecropper {
@@ -617,6 +625,10 @@ div.umb-codeeditor .umb-btn-toolbar {
float: left;
max-width: 100%;
}
.viewport img {
background: @checkered-background;
}
}
.imagecropper .umb-cropper__container {
@@ -884,6 +896,10 @@ div.umb-codeeditor .umb-btn-toolbar {
list-style: none;
vertical-align: middle;
margin-bottom: 0;
img {
background: @checkered-background;
}
}
.umb-fileupload label {
@@ -25,30 +25,31 @@ angular.module("umbraco").controller("Umbraco.Overlays.LinkPickerController",
$scope.showTarget = $scope.model.hideTarget !== true;
if (dialogOptions.currentTarget) {
$scope.model.target = dialogOptions.currentTarget;
// clone the current target so we don't accidentally update the caller's model while manipulating $scope.model.target
$scope.model.target = angular.copy(dialogOptions.currentTarget);
//if we have a node ID, we fetch the current node to build the form data
if ($scope.model.target.id || $scope.model.target.udi) {
//will be either a udi or an int
var id = $scope.model.target.udi ? $scope.model.target.udi : $scope.model.target.id;
if (!$scope.model.target.path) {
// is it a content link?
if (!$scope.model.target.isMedia) {
// get the content path
entityResource.getPath(id, "Document").then(function(path) {
//now sync the tree to this path
$scope.dialogTreeEventHandler.syncTree({
path: path,
tree: "content"
});
});
entityResource.getPath(id, "Document").then(function (path) {
$scope.model.target.path = path;
//now sync the tree to this path
$scope.dialogTreeEventHandler.syncTree({
path: $scope.model.target.path,
tree: "content"
});
});
}
// if a link exists, get the properties to build the anchor name list
contentResource.getById(id).then(function (resp) {
$scope.model.target.url = resp.urls[0];
$scope.anchorValues = tinyMceService.getAnchorNames(JSON.stringify(resp.properties));
});
// get the content properties to build the anchor name list
contentResource.getById(id).then(function (resp) {
$scope.model.target.url = resp.urls[0];
$scope.anchorValues = tinyMceService.getAnchorNames(JSON.stringify(resp.properties));
});
}
} else if ($scope.model.target.url.length) {
// a url but no id/udi indicates an external link - trim the url to remove the anchor/qs
// only do the substring if there's a # or a ?
@@ -122,6 +123,12 @@ angular.module("umbraco").controller("Umbraco.Overlays.LinkPickerController",
$scope.mediaPickerOverlay.show = false;
$scope.mediaPickerOverlay = null;
// make sure the content tree has nothing highlighted
$scope.dialogTreeEventHandler.syncTree({
path: "-1",
tree: "content"
});
}
};
});
@@ -1,4 +1,4 @@
<button ng-click="click()" type="button" class="umb-toggle" ng-class="{'umb-toggle--checked': checked}">
<button ng-click="click()" type="button" class="umb-toggle" ng-disabled="disabled" ng-class="{'umb-toggle--checked': checked, 'umb-toggle--disabled': disabled}">
<span ng-if="!labelPosition && showLabels === 'true' || labelPosition === 'left' && showLabels === 'true'">
<span ng-if="!checked" class="umb-toggle__label umb-toggle__label--left">{{ displayLabelOff }}</span>
@@ -107,7 +107,7 @@
</div>
<div class="umb-package-details__sidebar">
<umb-box data-element="node-info-scheduled-publishing">
<umb-box data-element="node-info-scheduled-publishing" ng-if="allowScheduledPublishing">
<umb-box-header title-key="general_scheduledPublishing"></umb-box-header>
<umb-box-content class="block-form">
@@ -23,7 +23,7 @@
<!-- Icon for files -->
<span class="umb-media-grid__item-file-icon" ng-if="!item.thumbnail && item.extension != 'svg'">
<i class="umb-media-grid__item-icon {{item.icon}}"></i>
<span>.{{item.extension}}</span>
<span ng-if="item.extension">.{{item.extension}}</span>
</span>
</div>
</div>
@@ -57,7 +57,7 @@
</div>
</div>
<umb-control-group label="Enter a folder name" hide-label="false">
<umb-control-group label="@create_enterFolderName" localize="label" hide-label="false">
<input type="text" name="folderName" ng-model="vm.folderName" class="umb-textstring textstring input-block-level" umb-auto-focus required />
</umb-control-group>
@@ -12,6 +12,9 @@ function PartialViewsDeleteController($scope, codefileResource, treeService, nav
//mark it for deletion (used in the UI)
$scope.currentNode.loading = true;
// Reset the error message
$scope.error = null;
codefileResource.deleteByPath('partialViews', $scope.currentNode.id)
.then(function() {
@@ -21,6 +24,9 @@ function PartialViewsDeleteController($scope, codefileResource, treeService, nav
//TODO: Need to sync tree, etc...
treeService.removeNode($scope.currentNode);
navigationService.hideMenu();
}, function (err) {
$scope.currentNode.loading = false;
$scope.error = err;
});
};
@@ -1,6 +1,13 @@
<div class="umb-dialog umb-pane" ng-controller="Umbraco.Editors.PartialViews.DeleteController">
<div class="umb-dialog-body">
<div ng-show="error">
<div class="alert alert-error">
<div><strong>{{error.errorMsg}}</strong></div>
<div>{{error.data.message}}</div>
</div>
</div>
<p class="umb-abstract">
<localize key="defaultdialogs_confirmdelete">Are you sure you want to delete</localize> <strong>{{currentNode.name}}</strong> ?
</p>
@@ -1,4 +1,4 @@
function ColorPickerController($scope) {
function ColorPickerController($scope, angularHelper) {
//setup the default config
var config = {
@@ -12,32 +12,13 @@ function ColorPickerController($scope) {
//map back to the model
$scope.model.config = config;
function convertArrayToDictionaryArray(model) {
//now we need to format the items in the dictionary because we always want to have an array
var newItems = [];
for (var i = 0; i < model.length; i++) {
newItems.push({ id: model[i], sortOrder: 0, value: model[i] });
}
return newItems;
}
function convertObjectToDictionaryArray(model) {
//now we need to format the items in the dictionary because we always want to have an array
var newItems = [];
var vals = _.values($scope.model.config.items);
var keys = _.keys($scope.model.config.items);
for (var i = 0; i < vals.length; i++) {
var label = vals[i].value ? vals[i].value : vals[i];
newItems.push({ id: keys[i], sortOrder: vals[i].sortOrder, value: label });
}
return newItems;
}
$scope.isConfigured = $scope.model.config && $scope.model.config.items && _.keys($scope.model.config.items).length > 0;
$scope.model.activeColor = {
value: "",
label: ""
};
if ($scope.isConfigured) {
for (var key in $scope.model.config.items) {
@@ -77,29 +58,7 @@ function ColorPickerController($scope) {
//now make the editor model the array
$scope.model.config.items = items;
}
$scope.toggleItem = function (color) {
var currentColor = ($scope.model.value && $scope.model.value.hasOwnProperty("value"))
? $scope.model.value.value
: $scope.model.value;
var newColor;
if (currentColor === color.value) {
// deselect
$scope.model.value = $scope.model.useLabel ? { value: "", label: "" } : "";
newColor = "";
}
else {
// select
$scope.model.value = $scope.model.useLabel ? { value: color.value, label: color.label } : color.value;
newColor = color.value;
}
// this is required to re-validate
$scope.propertyForm.modelValue.$setViewValue(newColor);
};
// Method required by the valPropertyValidator directive (returns true if the property editor has at least one color selected)
$scope.validateMandatory = function () {
var isValid = !$scope.model.validation.mandatory || (
@@ -115,27 +74,41 @@ function ColorPickerController($scope) {
}
$scope.isConfigured = $scope.model.config && $scope.model.config.items && _.keys($scope.model.config.items).length > 0;
// A color is active if it matches the value and label of the model.
// If the model doesn't store the label, ignore the label during the comparison.
$scope.isActiveColor = function (color) {
$scope.onSelect = function (color) {
// did the value change?
if ($scope.model.value.value === color) {
// User clicked the currently selected color
// to remove the selection, they don't want
// to select any color after all.
// Unselect the color and mark as dirty
$scope.model.activeColor = null;
$scope.model.value = null;
angularHelper.getCurrentForm($scope).$setDirty();
// no value
if (!$scope.model.value)
return false;
return;
}
// Complex color (value and label)?
if (!$scope.model.value.hasOwnProperty("value"))
return $scope.model.value === color.value;
return $scope.model.value.value === color.value && $scope.model.value.label === color.label;
};
// yes, update the model (label + value) according to the new color
var selectedItem = _.find($scope.model.config.items, function (item) {
return item.value === color;
});
if (!selectedItem) {
return;
}
$scope.model.value = {
label: selectedItem.label,
value: selectedItem.value
};
// make sure to set dirty
angularHelper.getCurrentForm($scope).$setDirty();
}
// Finds the color best matching the model's color,
// and sets the model color to that one. This is useful when
// either the value or label was changed on the data type.
function initActiveColor() {
// no value
// no value - initialize default value
if (!$scope.model.value)
return;
@@ -144,10 +117,6 @@ function ColorPickerController($scope) {
$scope.model.value = { value: $scope.model.value, label: $scope.model.value };
}
// Complex color (value and label)?
if (!$scope.model.value.hasOwnProperty("value"))
return;
var modelColor = $scope.model.value.value;
var modelLabel = $scope.model.value.label;
@@ -187,8 +156,8 @@ function ColorPickerController($scope) {
// If a match was found, set it as the active color.
if (foundItem) {
$scope.model.value.value = foundItem.value;
$scope.model.value.label = foundItem.label;
$scope.model.activeColor.value = foundItem.value;
$scope.model.activeColor.label = foundItem.label;
}
}
@@ -6,9 +6,10 @@
</div>
<umb-color-swatches colors="model.config.items"
selected-color="model.value.value"
selected-color="model.activeColor.value"
size="m"
use-label="model.useLabel">
use-label="model.useLabel"
on-select="onSelect(color)">
</umb-color-swatches>
<input type="hidden" name="modelValue" ng-model="model.value" val-property-validator="validateMandatory" />
@@ -52,6 +52,7 @@ angular.module('umbraco')
});
editedCrop.coordinates = $scope.currentCrop.coordinates;
$scope.close();
angularHelper.getCurrentForm($scope).$setDirty();
};
//reset the current crop
@@ -98,6 +99,10 @@ angular.module('umbraco')
$scope.hasDimensions = hasDimensions;
};
$scope.focalPointChanged = function () {
angularHelper.getCurrentForm($scope).$setDirty();
}
//on image selected, update the cropper
$scope.$on("filesSelected", function (ev, args) {
$scope.model.value = config;
@@ -40,7 +40,8 @@
<umb-image-gravity
src="imageSrc"
center="model.value.focalPoint"
on-image-loaded="imageLoaded(isCroppable, hasDimensions)">
on-image-loaded="imageLoaded(isCroppable, hasDimensions)"
on-gravity-changed="focalPointChanged()">
</umb-image-gravity>
<a href class="btn btn-link btn-crop-delete" ng-click="clear()"><i class="icon-delete red"></i> <localize key="content_uploadClear">Remove file</localize></a>
</div>
@@ -1,4 +1,4 @@
function listViewController($rootScope, $scope, $routeParams, $injector, $cookieStore, notificationsService, iconHelper, dialogService, editorState, localizationService, $location, appState, $timeout, $q, mediaResource, listViewHelper, userService, navigationService, treeService) {
function listViewController($rootScope, $scope, $routeParams, $injector, $cookieStore, notificationsService, iconHelper, dialogService, editorState, localizationService, $location, appState, $timeout, $q, mediaResource, listViewHelper, userService, navigationService, treeService, mediaHelper) {
//this is a quick check to see if we're in create mode, if so just exit - we cannot show children for content
// that isn't created yet, if we continue this will use the parent id in the route params which isn't what
@@ -269,10 +269,12 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie
$scope.listViewResultSet = data;
//update all values for display
var section = appState.getSectionState("currentSection");
if ($scope.listViewResultSet.items) {
_.each($scope.listViewResultSet.items, function (e, index) {
setPropertyValues(e);
if (e.contentTypeAlias === 'Folder') {
// create the folders collection (only for media list views)
if (section === "media" && !mediaHelper.hasFilePropertyType(e)) {
$scope.folders.push(e);
}
});
@@ -12,6 +12,10 @@ function TemplatesDeleteController($scope, templateResource , treeService, navig
//mark it for deletion (used in the UI)
$scope.currentNode.loading = true;
// Reset the error message
$scope.error = null;
templateResource.deleteById($scope.currentNode.id).then(function () {
$scope.currentNode.loading = false;
@@ -21,6 +25,9 @@ function TemplatesDeleteController($scope, templateResource , treeService, navig
//TODO: Need to sync tree, etc...
treeService.removeNode($scope.currentNode);
navigationService.hideMenu();
}, function (err) {
$scope.currentNode.loading = false;
$scope.error = err;
});
};
@@ -1,11 +1,18 @@
<div class="umb-dialog umb-pane" ng-controller="Umbraco.Editors.Templates.DeleteController">
<div class="umb-dialog-body">
<div ng-show="error">
<div class="alert alert-error">
<div><strong>{{error.errorMsg}}</strong></div>
<div>{{error.data.message}}</div>
</div>
</div>
<p class="umb-abstract">
<localize key="defaultdialogs_confirmdelete">Are you sure you want to delete</localize>&nbsp;<strong>{{currentNode.name}}</strong> ?
</p>
<umb-confirm on-confirm="performDelete" on-cancel="cancel">
<umb-confirm on-confirm="performDelete" on-cancel="cancel">
</umb-confirm>
</div>
+2 -2
View File
@@ -1038,9 +1038,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\"
<WebProjectProperties>
<UseIIS>True</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>7131</DevelopmentServerPort>
<DevelopmentServerPort>7132</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:7131</IISUrl>
<IISUrl>http://localhost:7132</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
@@ -182,6 +182,11 @@
<key alias="validationErrorPropertyWithMoreThanOneMapping">Overførsel af egenskaber kunne ikke fuldføres, da en eller flere egenskaber er indstillet til at blive overført mere end én gang.</key>
<key alias="validDocTypesNote">Kun andre dokumenttyper, der er gyldige på denne placering, vises.</key>
</area>
<area alias="codefile">
<key alias="createFolderFailedById">Oprettelse af mappen under parent med ID %0% fejlede</key>
<key alias="createFolderFailedByName">Oprettelse af mappen under parent med navnet %0% fejlede</key>
<key alias="deleteItemFailed">Sletning af filen/mappen fejlede: %0%</key>
</area>
<area alias="content">
<key alias="isPublished" version="7.2">Udgivet</key>
<key alias="about">Om siden</key>
@@ -282,6 +287,7 @@
<key alias="chooseNode">Hvor ønsker du at oprette den nye %0%</key>
<key alias="createUnder">Opret under</key>
<key alias="createContentBlueprint">Vælg den dokumenttype, du vil oprette en indholdsskabelon til</key>
<key alias="enterFolderName">Angiv et navn for mappen</key>
<key alias="updateData">Vælg en type og skriv en titel</key>
<key alias="noDocumentTypes" version="7.0"><![CDATA[Der kunne ikke findes nogen tilladte dokument typer. Du skal tillade disse i indstillinger under <strong>"dokument typer"</strong>.]]></key>
<key alias="noMediaTypes" version="7.0"><![CDATA[Der kunne ikke findes nogen tilladte media typer. Du skal tillade disse i indstillinger under <strong>"media typer"</strong>.]]></key>
@@ -1158,6 +1164,7 @@ Mange hilsner fra Umbraco robotten
</area>
<area alias="template">
<key alias="deleteByIdFailed">Sletning af skabelonen med ID %0% fejlede</key>
<key alias="edittemplate">Rediger skabelon</key>
<key alias="insertSections">Sektioner</key>
@@ -188,6 +188,11 @@
<key alias="validationErrorPropertyWithMoreThanOneMapping">Could not complete property mapping as one or more properties have more than one mapping defined.</key>
<key alias="validDocTypesNote">Only alternate types valid for the current location are displayed.</key>
</area>
<area alias="codefile">
<key alias="createFolderFailedById">Failed to create a folder under parent with ID %0%</key>
<key alias="createFolderFailedByName">Failed to create a folder under parent with name %0%</key>
<key alias="deleteItemFailed">Failed to delete item: %0%</key>
</area>
<area alias="content">
<key alias="isPublished" version="7.2">Is Published</key>
<key alias="about">About this page</key>
@@ -290,6 +295,7 @@
<key alias="chooseNode">Where do you want to create the new %0%</key>
<key alias="createUnder">Create an item under</key>
<key alias="createContentBlueprint">Select the document type you want to make a content template for</key>
<key alias="enterFolderName">Enter a folder name</key>
<key alias="updateData">Choose a type and a title</key>
<key alias="noDocumentTypes" version="7.0"><![CDATA[There are no allowed document types available. You must enable these in the settings section under <strong>"document types"</strong>.]]></key>
<key alias="noMediaTypes" version="7.0"><![CDATA[There are no allowed media types available. You must enable these in the settings section under <strong>"media types"</strong>.]]></key>
@@ -1483,6 +1489,7 @@ To manage your website, simply open the Umbraco back office and start adding con
</area>
<area alias="template">
<key alias="deleteByIdFailed">Failed to delete template with ID %0%</key>
<key alias="edittemplate">Edit template</key>
<key alias="insertSections">Sections</key>
@@ -189,6 +189,11 @@
<key alias="validationErrorPropertyWithMoreThanOneMapping">Could not complete property mapping as one or more properties have more than one mapping defined.</key>
<key alias="validDocTypesNote">Only alternate types valid for the current location are displayed.</key>
</area>
<area alias="codefile">
<key alias="createFolderFailedById">Failed to create a folder under parent with ID %0%</key>
<key alias="createFolderFailedByName">Failed to create a folder under parent with name %0%</key>
<key alias="deleteItemFailed">Failed to delete item: %0%</key>
</area>
<area alias="content">
<key alias="isPublished" version="7.2">Is Published</key>
<key alias="about">About this page</key>
@@ -292,6 +297,7 @@
<key alias="chooseNode">Where do you want to create the new %0%</key>
<key alias="createUnder">Create an item under</key>
<key alias="createContentBlueprint">Select the document type you want to make a content template for</key>
<key alias="enterFolderName">Enter a folder name</key>
<key alias="updateData">Choose a type and a title</key>
<key alias="noDocumentTypes" version="7.0"><![CDATA[There are no allowed document types available. You must enable these in the settings section under <strong>"document types"</strong>.]]></key>
<key alias="noMediaTypes" version="7.0"><![CDATA[There are no allowed media types available. You must enable these in the settings section under <strong>"media types"</strong>.]]></key>
@@ -1481,6 +1487,7 @@ To manage your website, simply open the Umbraco back office and start adding con
<key alias="styles">Styles</key>
</area>
<area alias="template">
<key alias="deleteByIdFailed">Failed to delete template with ID %0%</key>
<key alias="edittemplate">Edit template</key>
<key alias="insertSections">Sections</key>
@@ -53,6 +53,16 @@ namespace Umbraco.Web.Editors
if (currentUser.IsAdmin())
return Attempt<string>.Succeed();
var existingGroups = _userService.GetUserGroupsByAlias(groupAliases);
if(!existingGroups.Any())
{
// We're dealing with new groups,
// so authorization should be given to any user with access to Users section
if (currentUser.AllowedSections.Contains(Constants.Applications.Users))
return Attempt<string>.Succeed();
}
var userGroups = currentUser.Groups.Select(x => x.Alias).ToArray();
var missingAccess = groupAliases.Except(userGroups).ToArray();
return missingAccess.Length == 0
@@ -119,4 +129,4 @@ namespace Umbraco.Web.Editors
return Attempt<string>.Succeed();
}
}
}
}
@@ -30,6 +30,7 @@ namespace Umbraco.Web.Editors
//authorize that the user has access to save this user group
var authHelper = new UserGroupEditorAuthorizationHelper(
Services.UserService, Services.ContentService, Services.MediaService, Services.EntityService);
var isAuthorized = authHelper.AuthorizeGroupAccess(Security.CurrentUser, userGroupSave.Alias);
if (isAuthorized == false)
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.Unauthorized, isAuthorized.Result));
@@ -50,6 +51,14 @@ namespace Umbraco.Web.Editors
if (isAuthorized == false)
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.Unauthorized, isAuthorized.Result));
//current user needs to be added to a new group if not an admin (possibly only if no other users are added?) to avoid a 401
if(!Security.CurrentUser.IsAdmin() && (userGroupSave.Id == null || Convert.ToInt32(userGroupSave.Id) >= 0)/* && !userGroupSave.Users.Any() */)
{
var userIds = userGroupSave.Users.ToList();
userIds.Add(Security.CurrentUser.Id);
userGroupSave.Users = userIds;
}
//save the group
Services.UserService.Save(userGroupSave.PersistedUserGroup, userGroupSave.Users.ToArray());
@@ -148,4 +157,4 @@ namespace Umbraco.Web.Editors
Services.TextService.Localize("speechBubbles/deleteUserGroupSuccess", new[] {userGroups[0].Name}));
}
}
}
}
@@ -965,5 +965,37 @@ namespace Umbraco.Web
#endregion
#region RelatedLink
/// <summary>
/// Renders an anchor element for a RelatedLink instance.
/// Format: &lt;a href=&quot;relatedLink.Link&quot; target=&quot;_blank/_self&quot;&gt;relatedLink.Caption&lt;/a&gt;
/// </summary>
/// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
/// <param name="relatedLink">The RelatedLink instance</param>
/// <returns>An anchor element </returns>
public static MvcHtmlString GetRelatedLinkHtml(this HtmlHelper htmlHelper, RelatedLink relatedLink)
{
return htmlHelper.GetRelatedLinkHtml(relatedLink, null);
}
/// <summary>
/// Renders an anchor element for a RelatedLink instance, accepting htmlAttributes.
/// Format: &lt;a href=&quot;relatedLink.Link&quot; target=&quot;_blank/_self&quot; htmlAttributes&gt;relatedLink.Caption&lt;/a&gt;
/// </summary>
/// <param name="htmlHelper">The HTML helper instance that this method extends.</param>
/// <param name="relatedLink">The RelatedLink instance</param>
/// <param name="htmlAttributes">An object that contains the HTML attributes to set for the element.</param>
/// <returns></returns>
public static MvcHtmlString GetRelatedLinkHtml(this HtmlHelper htmlHelper, RelatedLink relatedLink, object htmlAttributes)
{
var tagBuilder = new TagBuilder("a");
tagBuilder.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
tagBuilder.MergeAttribute("href", relatedLink.Link);
tagBuilder.MergeAttribute("target", relatedLink.NewWindow ? "_blank" : "_self");
tagBuilder.InnerHtml = HttpUtility.HtmlEncode(relatedLink.Caption);
return MvcHtmlString.Create(tagBuilder.ToString(TagRenderMode.Normal));
}
#endregion
}
}
@@ -8,7 +8,7 @@ using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PropertyEditors
{
[PropertyEditor(Constants.PropertyEditors.MemberGroupPickerAlias, "Member Group Picker", "membergrouppicker", Group="People", Icon="icon-users")]
[PropertyEditor(Constants.PropertyEditors.MemberGroupPickerAlias, "Member Group Picker", PropertyEditorValueTypes.Text, "membergrouppicker", Group="People", Icon="icon-users")]
public class MemberGroupPickerPropertyEditor : PropertyEditor
{
}
File diff suppressed because it is too large Load Diff
+5 -4
View File
@@ -63,10 +63,11 @@ namespace Umbraco.Web.Scheduling
private async Task<bool> GetTaskByHttpAync(string url, CancellationToken token)
{
if (_httpClient == null)
_httpClient = new HttpClient();
if (Uri.TryCreate(_appContext.UmbracoApplicationUrl, UriKind.Absolute, out var baseUri))
_httpClient.BaseAddress = baseUri;
{
_httpClient = Uri.TryCreate(_appContext.UmbracoApplicationUrl, UriKind.Absolute, out var baseUri)
? new HttpClient { BaseAddress = baseUri }
: new HttpClient();
}
var request = new HttpRequestMessage(HttpMethod.Get, url);
@@ -238,7 +238,10 @@ namespace Umbraco.Web.Trees
menu.Items.Add<ActionRights>(ui.Text("actions", ActionRights.Instance.Alias), true);
menu.Items.Add<ActionProtect>(ui.Text("actions", ActionProtect.Instance.Alias), true).ConvertLegacyMenuItem(item, "content", "content");
menu.Items.Add<ActionNotify>(ui.Text("actions", ActionNotify.Instance.Alias), true);
if (EmailSender.CanSendRequiredEmail)
{
menu.Items.Add<ActionNotify>(ui.Text("actions", ActionNotify.Instance.Alias), true);
}
menu.Items.Add<ActionSendToTranslate>(ui.Text("actions", ActionSendToTranslate.Instance.Alias)).ConvertLegacyMenuItem(item, "content", "content");
menu.Items.Add<RefreshNode, ActionRefresh>(ui.Text("actions", ActionRefresh.Instance.Alias), true);
+1 -1
View File
@@ -207,7 +207,7 @@ namespace Umbraco.Web.UI
typeInstance.TypeID = typeId;
typeInstance.ParentID = nodeId;
typeInstance.Alias = text;
typeInstance.Alias = text.CleanForXss();
// check for returning url
ITaskReturnUrl returnUrlTask = typeInstance as LegacyDialogTask;
@@ -243,7 +243,7 @@ namespace Umbraco.Web.WebServices
// sanitize input - stylesheet names have no extension
var svce = (FileService)Services.FileService;
filename = CleanFilename(filename);
filename = CleanFilename(filename.CleanForXss());
oldName = CleanFilename(oldName);
if (filename != oldName)
@@ -84,14 +84,19 @@ namespace umbraco.presentation.umbraco.translation {
pageRow[ui.Text("name")] = ui.Text("nodeName");
pageRow[ui.Text("value")] = page.Text;
pageTable.Rows.Add(pageRow);
foreach (PropertyType pt in page.ContentType.PropertyTypes) {
foreach (PropertyType pt in page.ContentType.PropertyTypes)
{
pageRow = pageTable.NewRow();
pageRow[ui.Text("name")] = pt.Name;
pageRow[ui.Text("value")] = page.getProperty(pt.Alias).Value;
var property = page.getProperty(pt.Alias);
if (property != null && property.Value != null)
{
pageRow[ui.Text("value")] = property.Value;
}
pageTable.Rows.Add(pageRow);
}
dg_fields.DataSource = pageTable;
dg_fields.DataBind();
}