Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 98684e6292 | |||
| 9687b2abee | |||
| 4ea589e954 | |||
| 621a19d4bd | |||
| 5821444678 | |||
| 7533baf368 | |||
| d691e525b3 | |||
| 02d9d42ae2 | |||
| 17838e044c | |||
| 73173f92d6 | |||
| 2ab1cf59a6 | |||
| 56cd1cee81 | |||
| 002988ce86 | |||
| 81c32716fe | |||
| c2f34cefb5 | |||
| 2f7727af68 | |||
| 5a9874bfad | |||
| 68b4a493c6 | |||
| 6338d57959 | |||
| 7de1b2d09d | |||
| 06ae6ad15e | |||
| 81dac97917 | |||
| 4a8a09c78a |
@@ -107,3 +107,4 @@ src/Umbraco.Web.UI/[Cc]onfig/appSettings.config
|
||||
src/Umbraco.Web.UI/[Cc]onfig/connectionStrings.config
|
||||
src/Umbraco.Web.UI/umbraco/plugins/*
|
||||
src/Umbraco.Web.UI/umbraco/js/init.js
|
||||
build/ApiDocs/*
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
@ECHO OFF
|
||||
SET release=7.0.2
|
||||
SET release=7.0.3
|
||||
SET comment=
|
||||
SET version=%release%
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Umbraco.Core.Configuration
|
||||
|
||||
int oldVersion;
|
||||
int.TryParse(versionAttribute.Value, out oldVersion);
|
||||
var newVersion = oldVersion + 1;
|
||||
var newVersion = oldVersion + 100;
|
||||
|
||||
versionAttribute.SetValue(newVersion);
|
||||
clientDependencyConfigXml.Save(_fileName, SaveOptions.DisableFormatting);
|
||||
|
||||
@@ -5,7 +5,7 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
public class UmbracoVersion
|
||||
{
|
||||
private static readonly Version Version = new Version("7.0.2");
|
||||
private static readonly Version Version = new Version("7.0.3");
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current version of Umbraco.
|
||||
|
||||
@@ -292,7 +292,20 @@ namespace Umbraco.Core
|
||||
else if (destinationType == typeof(DateTime))
|
||||
{
|
||||
DateTime value;
|
||||
return DateTime.TryParse(input, out value) ? Attempt<object>.Succeed(value) : Attempt<object>.Fail();
|
||||
if (DateTime.TryParse(input, out value))
|
||||
{
|
||||
switch (value.Kind)
|
||||
{
|
||||
case DateTimeKind.Unspecified:
|
||||
case DateTimeKind.Utc:
|
||||
return Attempt<object>.Succeed(value);
|
||||
case DateTimeKind.Local:
|
||||
return Attempt<object>.Succeed(value.ToUniversalTime());
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
return Attempt<object>.Fail();
|
||||
}
|
||||
else if (destinationType == typeof(DateTimeOffset))
|
||||
{
|
||||
@@ -526,7 +539,7 @@ namespace Umbraco.Core
|
||||
if (type == typeof(bool)) return XmlConvert.ToString((bool)value);
|
||||
if (type == typeof(byte)) return XmlConvert.ToString((byte)value);
|
||||
if (type == typeof(char)) return XmlConvert.ToString((char)value);
|
||||
if (type == typeof(DateTime)) return XmlConvert.ToString((DateTime)value, XmlDateTimeSerializationMode.RoundtripKind);
|
||||
if (type == typeof(DateTime)) return XmlConvert.ToString((DateTime)value, XmlDateTimeSerializationMode.Unspecified);
|
||||
if (type == typeof(DateTimeOffset)) return XmlConvert.ToString((DateTimeOffset)value);
|
||||
if (type == typeof(decimal)) return XmlConvert.ToString((decimal)value);
|
||||
if (type == typeof(double)) return XmlConvert.ToString((double)value);
|
||||
|
||||
@@ -26,13 +26,14 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
if (source == null) return DateTime.MinValue;
|
||||
|
||||
// in XML a DateTime is: string - format "yyyy-MM-ddTHH:mm:ss"
|
||||
// Actually, not always sometimes it is formatted in UTC style with 'Z' suffixed on the end but that is due to this bug:
|
||||
// http://issues.umbraco.org/issue/U4-4145, http://issues.umbraco.org/issue/U4-3894
|
||||
// We should just be using TryConvertTo instead.
|
||||
var sourceString = source as string;
|
||||
if (sourceString != null)
|
||||
{
|
||||
DateTime value;
|
||||
return DateTime.TryParseExact(sourceString, "yyyy-MM-ddTHH:mm:ss", CultureInfo.InvariantCulture, DateTimeStyles.None, out value)
|
||||
? value
|
||||
: DateTime.MinValue;
|
||||
var attempt = sourceString.TryConvertTo<DateTime>();
|
||||
return attempt.Success == false ? DateTime.MinValue : attempt.Result;
|
||||
}
|
||||
|
||||
// in the database a DateTime is: DateTime
|
||||
@@ -47,7 +48,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
public override object ConvertSourceToXPath(PublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
// source should come from ConvertSource and be a DateTime already
|
||||
return XmlConvert.ToString((DateTime) source, "yyyy-MM-ddTHH:mm:ss");
|
||||
return XmlConvert.ToString((DateTime)source, XmlDateTimeSerializationMode.Unspecified);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
using System.Linq;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
{
|
||||
/// <summary>
|
||||
/// Ensures that no matter what is selected in (editor), the value results in a string.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>For more details see issues http://issues.umbraco.org/issue/U4-3776 (MNTP)
|
||||
/// and http://issues.umbraco.org/issue/U4-4160 (media picker).</para>
|
||||
/// <para>The cache level is set to .Content because the string is supposed to depend
|
||||
/// on the source value only, and not on any other content. It is NOT appropriate
|
||||
/// to use that converter for values whose .ToString() would depend on other content.</para>
|
||||
/// </remarks>
|
||||
[DefaultPropertyValueConverter]
|
||||
[PropertyValueType(typeof(string))]
|
||||
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)]
|
||||
public class MustBeStringValueConverter : PropertyValueConverterBase
|
||||
{
|
||||
private static readonly string[] Aliases =
|
||||
{
|
||||
Constants.PropertyEditors.MultiNodeTreePickerAlias,
|
||||
Constants.PropertyEditors.MultipleMediaPickerAlias
|
||||
};
|
||||
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
{
|
||||
return Aliases.Contains(propertyType.PropertyEditorAlias);
|
||||
}
|
||||
|
||||
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
if (source == null) return null;
|
||||
return source.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -711,6 +711,11 @@ namespace Umbraco.Core.Security
|
||||
var decrypted = DecryptPassword(dbPassword);
|
||||
return decrypted == password;
|
||||
case MembershipPasswordFormat.Hashed:
|
||||
|
||||
//only triggered when we set the initial installer password
|
||||
if (dbPassword == "default" && password == dbPassword)
|
||||
return true;
|
||||
|
||||
string salt;
|
||||
var storedHashedPass = StoredPassword(dbPassword, out salt);
|
||||
var hashed = EncryptOrHashPassword(password, salt);
|
||||
|
||||
@@ -368,6 +368,7 @@
|
||||
<Compile Include="PropertyEditors\ValueConverters\JsonValueConverter.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\MultipleTextStringValueConverter.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\MarkdownEditorValueConverter.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\MustBeStringValueConverter.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\TextStringValueConverter.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\TinyMceValueConverter.cs" />
|
||||
<Compile Include="PropertyEditors\IPropertyValueConverter.cs" />
|
||||
|
||||
@@ -104,30 +104,24 @@ namespace Umbraco.Tests
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public virtual void CanConvertStringToDateTime()
|
||||
[TestCase("2012-11-10", true)]
|
||||
[TestCase("2012/11/10", true)]
|
||||
[TestCase("10/11/2012", true)]// assuming your culture uses DD/MM/YYYY
|
||||
[TestCase("11/10/2012", false)]// assuming your culture uses DD/MM/YYYY
|
||||
[TestCase("Sat 10, Nov 2012", true)]
|
||||
[TestCase("Saturday 10, Nov 2012", true)]
|
||||
[TestCase("Sat 10, November 2012", true)]
|
||||
[TestCase("Saturday 10, November 2012", true)]
|
||||
[TestCase("2012-11-10 13:14:15", true)]
|
||||
[TestCase("2012-11-10T13:14:15Z", true)]
|
||||
public virtual void CanConvertStringToDateTime(string date, bool outcome)
|
||||
{
|
||||
var dateTime = new DateTime(2012, 11, 10, 13, 14, 15);
|
||||
var testCases = new Dictionary<string, bool>
|
||||
{
|
||||
{"2012-11-10", true},
|
||||
{"2012/11/10", true},
|
||||
{"10/11/2012", true}, // assuming your culture uses DD/MM/YYYY
|
||||
{"11/10/2012", false}, // assuming your culture uses DD/MM/YYYY
|
||||
{"Sat 10, Nov 2012", true},
|
||||
{"Saturday 10, Nov 2012", true},
|
||||
{"Sat 10, November 2012", true},
|
||||
{"Saturday 10, November 2012", true},
|
||||
{"2012-11-10 13:14:15", true}
|
||||
};
|
||||
|
||||
foreach (var testCase in testCases)
|
||||
{
|
||||
var result = testCase.Key.TryConvertTo<DateTime>();
|
||||
var result = date.TryConvertTo<DateTime>();
|
||||
|
||||
Assert.IsTrue(result.Success, testCase.Key);
|
||||
Assert.AreEqual(DateTime.Equals(dateTime.Date, result.Result.Date), testCase.Value, testCase.Key);
|
||||
}
|
||||
Assert.IsTrue(result.Success, date);
|
||||
Assert.AreEqual(DateTime.Equals(dateTime.Date, result.Result.Date), outcome, date);
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -235,8 +235,9 @@ function umbTreeDirective($compile, $log, $q, $rootScope, treeService, notificat
|
||||
|
||||
//set the root as the current active tree
|
||||
scope.activeTree = scope.tree.root;
|
||||
emitEvent("treeLoaded", { tree: scope.tree.root });
|
||||
|
||||
emitEvent("treeLoaded", { tree: scope.tree });
|
||||
emitEvent("treeNodeExpanded", { tree: scope.tree, node: scope.tree.root, children: scope.tree.root.children });
|
||||
|
||||
}, function(reason) {
|
||||
scope.loading = false;
|
||||
notificationsService.error("Tree Error", reason);
|
||||
|
||||
@@ -99,6 +99,16 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
'Failed to retreive entity data for id ' + id);
|
||||
},
|
||||
|
||||
getByQuery: function (query, nodeContextId, type) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"entityApiBaseUrl",
|
||||
"GetByQuery",
|
||||
[{query: query},{ nodeContextId: nodeContextId}, {type: type }])),
|
||||
'Failed to retreive entity data for query ' + query);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.entityResource#getByIds
|
||||
|
||||
@@ -47,6 +47,15 @@ app.run(['userService', '$log', '$rootScope', '$location', 'navigationService',
|
||||
$location.path(rejection.path).search(rejection.search);
|
||||
});
|
||||
|
||||
|
||||
/** For debug mode, always clear template cache to cut down on
|
||||
dev frustration and chrome cache on templates */
|
||||
if(Umbraco.Sys.ServerVariables.isDebuggingEnabled){
|
||||
$rootScope.$on('$viewContentLoaded', function() {
|
||||
$templateCache.removeAll();
|
||||
});
|
||||
}
|
||||
|
||||
/* this will initialize the navigation service once the application has started */
|
||||
navigationService.init();
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
angular.module("umbraco").controller("Umbraco.Dialogs.RteEmbedController", function ($scope, $http) {
|
||||
angular.module("umbraco").controller("Umbraco.Dialogs.RteEmbedController", function ($scope, $http, umbRequestHelper) {
|
||||
$scope.form = {};
|
||||
$scope.form.url = "";
|
||||
$scope.form.width = 360;
|
||||
@@ -20,7 +20,7 @@
|
||||
$scope.form.info = "";
|
||||
$scope.form.success = false;
|
||||
|
||||
$http({ method: 'GET', url: '/umbraco/UmbracoApi/RteEmbed/GetEmbed', params: { url: $scope.form.url, width: $scope.form.width, height: $scope.form.height } })
|
||||
$http({ method: 'GET', url: umbRequestHelper.getApiUrl("embedApiBaseUrl", "GetEmbed"), params: { url: $scope.form.url, width: $scope.form.width, height: $scope.form.height } })
|
||||
.success(function (data) {
|
||||
|
||||
$scope.form.preview = "";
|
||||
|
||||
@@ -40,11 +40,11 @@ angular.module("umbraco").controller("Umbraco.Dialogs.TreePickerController",
|
||||
//Configures filtering
|
||||
if (dialogOptions.filter) {
|
||||
|
||||
dialogOptions.filterExclude = true;
|
||||
dialogOptions.filterExclude = false;
|
||||
dialogOptions.filterAdvanced = false;
|
||||
|
||||
if(dialogOptions.filter[0] === "!"){
|
||||
dialogOptions.filterExclude = false;
|
||||
dialogOptions.filterExclude = true;
|
||||
dialogOptions.filter = dialogOptions.filter.substring(1);
|
||||
}
|
||||
|
||||
@@ -112,8 +112,10 @@ angular.module("umbraco").controller("Umbraco.Dialogs.TreePickerController",
|
||||
angular.forEach(nodes, function (value, key) {
|
||||
|
||||
var found = a.indexOf(value.metaData.contentType) >= 0;
|
||||
if ((dialogOptions.filterExclude && found) || !found) {
|
||||
value.filtered = true;
|
||||
|
||||
if (!dialogOptions.filterExclude && !found || dialogOptions.filterExclude && found){
|
||||
value.filtered = true;
|
||||
|
||||
if(dialogOptions.filterCssClass){
|
||||
value.cssClasses.push(dialogOptions.filterCssClass);
|
||||
}
|
||||
|
||||
@@ -37,10 +37,13 @@ angular.module('umbraco')
|
||||
};
|
||||
|
||||
$scope.clear = function() {
|
||||
$scope.model.value.id = undefined;
|
||||
$scope.node = undefined;
|
||||
$scope.model.value.id = undefined;
|
||||
$scope.node = undefined;
|
||||
$scope.model.value.query = undefined;
|
||||
};
|
||||
|
||||
|
||||
//we always need to ensure we dont submit anything broken
|
||||
$scope.$on("formSubmitting", function (ev, args) {
|
||||
if($scope.model.value.type === "member"){
|
||||
$scope.model.value.id = -1;
|
||||
|
||||
@@ -1,30 +1,77 @@
|
||||
<div ng-controller="Umbraco.PrevalueEditors.TreeSourceController" class="umb-editor umb-contentpicker">
|
||||
|
||||
<select ng-model="model.value.type">
|
||||
<select ng-model="model.value.type" class="umb-editor" ng-change="clear()">
|
||||
<option value="content">Content</option>
|
||||
<option value="media">Media</option>
|
||||
<option value="member">Members</option>
|
||||
</select>
|
||||
|
||||
<br/><br/>
|
||||
<ul class="unstyled list-icons" ng-if="node" style="margin-top: 30px">
|
||||
<li>
|
||||
<i class="icon icon-delete red hover-show pull-right" ng-click="clear()"></i>
|
||||
<i class="icon {{node.icon}} hover-hide"></i>
|
||||
|
||||
<a href prevent-default ng-click="openContentPicker()" >{{node.name}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div ng-hide="model.value.type === 'member'">
|
||||
<ul class="unstyled list-icons" ng-if="node" >
|
||||
<li>
|
||||
<i class="icon icon-delete red hover-show pull-right" ng-click="clear()"></i>
|
||||
<i class="icon {{node.icon}} hover-hide"></i>
|
||||
|
||||
<a href prevent-default ng-click="openContentPicker()" >{{node.name}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div ng-if="!node && model.value.type !== 'member'" style="margin-top: 30px">
|
||||
<span ng-hide="showSearch || model.value.query">
|
||||
<ul class="unstyled list-icons">
|
||||
<li>
|
||||
<i class="icon icon-add blue"></i>
|
||||
<a href ng-click="openContentPicker()" prevent-default>
|
||||
<localize key="general_choose">Choose a root node</localize>...
|
||||
</a>
|
||||
</li>
|
||||
<li ng-show="model.value.type == 'content'">
|
||||
<i class="icon icon-search"></i>
|
||||
<a href ng-click="showSearch = true">Query for root node with xpath</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
|
||||
<ul class="unstyled list-icons" ng-show="multipicker || !node">
|
||||
<li ng-hide="showSearch">
|
||||
<i class="icon icon-add blue"></i>
|
||||
<a href ng-click="openContentPicker()" prevent-default>
|
||||
<localize key="general_choose">Choose</localize>...
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<span ng-show="showSearch || model.value.query">
|
||||
|
||||
<input type="text"
|
||||
ng-model="model.value.query"
|
||||
class="umb-editor umb-textstring"
|
||||
placeholder="Enter xpath query">
|
||||
|
||||
<ul class="unstyled list-icons" style="margin-top: 15px">
|
||||
<li style="max-width: 600px">
|
||||
<i class="icon icon-help-alt"></i>
|
||||
<a href ng-click="showHelp = 1" prevent-default>
|
||||
Show xpath query help
|
||||
</a>
|
||||
|
||||
<small ng-if="showHelp">
|
||||
<p>
|
||||
Use Xpath query to set a root node on the tree, either based on a search from the root of the content tree, or by using a context-aware placeholder.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Placeholders finds the nearest published ID and runs its query from there. so for instance:
|
||||
|
||||
<pre>$parent/newsArticle</pre>
|
||||
|
||||
Will try to get the parent if available, but will then fall back to the nearest ancestor and query for all news articles there.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Available placeholders: <br/>
|
||||
<code>$current</code>: current page or closest found ancestor<br/>
|
||||
<code>$parent</code>: parent page or closest found ancestor<br/>
|
||||
<code>$root</code>: root of the content tree<br/>
|
||||
<code>$site</code>: Ancestor node at level 1 <br/>
|
||||
</p>
|
||||
</small>
|
||||
</li>
|
||||
<li>
|
||||
<i class="icon icon-delete red"></i>
|
||||
<a href ng-click="showSearch = false; model.value.query = ''"> Cancel and clear query</a>
|
||||
</li>
|
||||
</ul>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
+82
-71
@@ -2,69 +2,80 @@
|
||||
//with a specified callback, this callback will receive an object with a selection on it
|
||||
angular.module('umbraco')
|
||||
.controller("Umbraco.PropertyEditors.ContentPickerController",
|
||||
|
||||
function($scope, dialogService, entityResource, $log, iconHelper){
|
||||
$scope.renderModel = [];
|
||||
$scope.ids = $scope.model.value ? $scope.model.value.split(',') : [];
|
||||
|
||||
//configuration
|
||||
$scope.cfg = {
|
||||
multiPicker: "0",
|
||||
entityType: "Document",
|
||||
startNode:{
|
||||
type: "content",
|
||||
id: -1
|
||||
}
|
||||
};
|
||||
|
||||
if($scope.model.config){
|
||||
$scope.cfg = angular.extend($scope.cfg, $scope.model.config);
|
||||
}
|
||||
|
||||
function ($scope, dialogService, entityResource, editorState, $log, iconHelper, $routeParams) {
|
||||
$scope.renderModel = [];
|
||||
$scope.ids = $scope.model.value ? $scope.model.value.split(',') : [];
|
||||
|
||||
//configuration
|
||||
$scope.cfg = {
|
||||
multiPicker: "0",
|
||||
entityType: "Document",
|
||||
filterCssClass: "not-allowed not-published",
|
||||
|
||||
startNode: {
|
||||
query: "",
|
||||
type: "content",
|
||||
id: -1
|
||||
}
|
||||
};
|
||||
|
||||
if ($scope.model.config) {
|
||||
$scope.cfg = angular.extend($scope.cfg, $scope.model.config);
|
||||
}
|
||||
|
||||
//Umbraco persists boolean for prevalues as "0" or "1" so we need to convert that!
|
||||
$scope.cfg.multiPicker = ($scope.cfg.multiPicker === "0" ? false : true);
|
||||
$scope.cfg.multiPicker = ($scope.cfg.multiPicker === "0" ? false : true);
|
||||
|
||||
if($scope.cfg.startNode.type === "member"){
|
||||
$scope.cfg.entityType = "Member";
|
||||
}
|
||||
else if ($scope.cfg.startNode.type === "media") {
|
||||
$scope.cfg.entityType = "Media";
|
||||
}
|
||||
if ($scope.cfg.startNode.type === "member") {
|
||||
$scope.cfg.entityType = "Member";
|
||||
}
|
||||
else if ($scope.cfg.startNode.type === "media") {
|
||||
$scope.cfg.entityType = "Media";
|
||||
}
|
||||
|
||||
$scope.cfg.callback = populate;
|
||||
$scope.cfg.treeAlias = $scope.cfg.startNode.type;
|
||||
$scope.cfg.section = $scope.cfg.startNode.type;
|
||||
$scope.cfg.startNodeId = $scope.cfg.startNode.id;
|
||||
$scope.cfg.filterCssClass = "not-allowed not-published";
|
||||
|
||||
//load current data
|
||||
entityResource.getByIds($scope.ids, $scope.cfg.entityType).then(function(data){
|
||||
_.each(data, function (item, i) {
|
||||
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
|
||||
$scope.renderModel.push({name: item.name, id: item.id, icon: item.icon});
|
||||
});
|
||||
});
|
||||
//if we have a query for the startnode, we will use that.
|
||||
if ($scope.cfg.startNode.query) {
|
||||
var rootId = $routeParams.id;
|
||||
entityResource.getByQuery($scope.cfg.startNode.query, rootId, "Document").then(function (ent) {
|
||||
$scope.cfg.startNodeId = ent.id;
|
||||
});
|
||||
} else {
|
||||
$scope.cfg.startNodeId = $scope.cfg.startNode.id;
|
||||
}
|
||||
|
||||
$scope.cfg.callback = populate;
|
||||
$scope.cfg.treeAlias = $scope.cfg.startNode.type;
|
||||
$scope.cfg.section = $scope.cfg.startNode.type;
|
||||
|
||||
//load current data
|
||||
entityResource.getByIds($scope.ids, $scope.cfg.entityType).then(function (data) {
|
||||
_.each(data, function (item, i) {
|
||||
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
|
||||
$scope.renderModel.push({ name: item.name, id: item.id, icon: item.icon });
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
//dialog
|
||||
$scope.openContentPicker =function(){
|
||||
var d = dialogService.treePicker($scope.cfg);
|
||||
};
|
||||
//dialog
|
||||
$scope.openContentPicker = function () {
|
||||
var d = dialogService.treePicker($scope.cfg);
|
||||
};
|
||||
|
||||
|
||||
$scope.remove =function(index){
|
||||
$scope.renderModel.splice(index, 1);
|
||||
};
|
||||
$scope.remove = function (index) {
|
||||
$scope.renderModel.splice(index, 1);
|
||||
};
|
||||
|
||||
|
||||
$scope.add =function(item){
|
||||
if($scope.ids.indexOf(item.id) < 0){
|
||||
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
|
||||
$scope.renderModel.push({name: item.name, id: item.id, icon: item.icon});
|
||||
}
|
||||
};
|
||||
$scope.add = function (item) {
|
||||
if ($scope.ids.indexOf(item.id) < 0) {
|
||||
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
|
||||
$scope.renderModel.push({ name: item.name, id: item.id, icon: item.icon });
|
||||
}
|
||||
};
|
||||
|
||||
$scope.clear = function() {
|
||||
$scope.clear = function () {
|
||||
$scope.renderModel = [];
|
||||
};
|
||||
|
||||
@@ -72,10 +83,10 @@ angular.module('umbraco')
|
||||
// because the ui-sortable doesn't dispatch an event after the digest of the sort operation. Any of the events for UI sortable
|
||||
// occur after the DOM has updated but BEFORE the digest has occured so the model has NOT changed yet - it even states so in the docs.
|
||||
// In their source code there is no event so we need to just subscribe to our model changes here.
|
||||
//This also makes it easier to manage models, we update one and the rest will just work.
|
||||
$scope.$watch(function() {
|
||||
//This also makes it easier to manage models, we update one and the rest will just work.
|
||||
$scope.$watch(function () {
|
||||
//return the joined Ids as a string to watch
|
||||
return _.map($scope.renderModel, function(i) {
|
||||
return _.map($scope.renderModel, function (i) {
|
||||
return i.id;
|
||||
}).join();
|
||||
}, function (newVal) {
|
||||
@@ -86,22 +97,22 @@ angular.module('umbraco')
|
||||
});
|
||||
|
||||
$scope.$on("formSubmitting", function (ev, args) {
|
||||
$scope.model.value = trim($scope.ids.join(), ",");
|
||||
$scope.model.value = trim($scope.ids.join(), ",");
|
||||
});
|
||||
|
||||
function trim(str, chr) {
|
||||
var rgxtrim = (!chr) ? new RegExp('^\\s+|\\s+$', 'g') : new RegExp('^'+chr+'+|'+chr+'+$', 'g');
|
||||
return str.replace(rgxtrim, '');
|
||||
}
|
||||
function trim(str, chr) {
|
||||
var rgxtrim = (!chr) ? new RegExp('^\\s+|\\s+$', 'g') : new RegExp('^' + chr + '+|' + chr + '+$', 'g');
|
||||
return str.replace(rgxtrim, '');
|
||||
}
|
||||
|
||||
function populate(data){
|
||||
if(angular.isArray(data)){
|
||||
_.each(data, function (item, i) {
|
||||
$scope.add(item);
|
||||
});
|
||||
}else{
|
||||
$scope.clear();
|
||||
$scope.add(data);
|
||||
}
|
||||
}
|
||||
});
|
||||
function populate(data) {
|
||||
if (angular.isArray(data)) {
|
||||
_.each(data, function (item, i) {
|
||||
$scope.add(item);
|
||||
});
|
||||
} else {
|
||||
$scope.clear();
|
||||
$scope.add(data);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -23,5 +23,4 @@
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
@@ -2643,9 +2643,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.0\x86\*.* "$(TargetDir)x86\"
|
||||
<WebProjectProperties>
|
||||
<UseIIS>True</UseIIS>
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<DevelopmentServerPort>7020</DevelopmentServerPort>
|
||||
<DevelopmentServerPort>7030</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:7020</IISUrl>
|
||||
<IISUrl>http://localhost:7030</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>False</UseCustomServer>
|
||||
<CustomServerUrl>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
<%
|
||||
// NH: Adds this inline check to avoid a simple codebehind file in the legacy project!
|
||||
if (!umbraco.cms.helpers.url.ValidateProxyUrl(Request["url"], Request.Url.AbsoluteUri))
|
||||
if (Request["url"].ToLower().Contains("booting.aspx") || !umbraco.cms.helpers.url.ValidateProxyUrl(Request["url"], Request.Url.AbsoluteUri))
|
||||
{
|
||||
throw new ArgumentException("Can't redirect to the requested url - it's not local or an approved proxy url",
|
||||
"url");
|
||||
|
||||
@@ -110,6 +110,10 @@ namespace Umbraco.Web.Editors
|
||||
{"manifestAssetList", Url.Action("GetManifestAssetList", "BackOffice")},
|
||||
{"serverVarsJs", Url.Action("Application", "BackOffice")},
|
||||
//API URLs
|
||||
{
|
||||
"embedApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<RteEmbedController>(
|
||||
controller => controller.GetEmbed("",0,0))
|
||||
},
|
||||
{
|
||||
"contentApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<ContentController>(
|
||||
controller => controller.PostSave(null))
|
||||
|
||||
@@ -25,6 +25,7 @@ using Examine;
|
||||
using Examine.LuceneEngine.SearchCriteria;
|
||||
using Examine.SearchCriteria;
|
||||
using Umbraco.Web.Dynamics;
|
||||
using umbraco;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
@@ -128,6 +129,106 @@ namespace Umbraco.Web.Editors
|
||||
return GetResultForKey(id, type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets an entity by a xpath query
|
||||
/// </summary>
|
||||
/// <param name="query"></param>
|
||||
/// <param name="nodeContextId"></param>
|
||||
/// <param name="type"></param>
|
||||
/// <returns></returns>
|
||||
public EntityBasic GetByQuery(string query, int nodeContextId, UmbracoEntityTypes type)
|
||||
{
|
||||
|
||||
if (type != UmbracoEntityTypes.Document)
|
||||
throw new ArgumentException("Get by query is only compatible with enitities of type Document");
|
||||
|
||||
|
||||
var q = ParseXPathQuery(query, nodeContextId);
|
||||
var node = Umbraco.TypedContentSingleAtXPath(q);
|
||||
|
||||
if (node == null)
|
||||
return null;
|
||||
|
||||
return GetById(node.Id, type);
|
||||
}
|
||||
|
||||
//PP: wip in progress on the query parser
|
||||
private string ParseXPathQuery(string query, int id)
|
||||
{
|
||||
//no need to parse it
|
||||
if (!query.StartsWith("$"))
|
||||
return query;
|
||||
|
||||
//get full path
|
||||
Func<int, IEnumerable<string>> getPath = delegate(int nodeid){
|
||||
var ent = Services.EntityService.Get(nodeid);
|
||||
return ent.Path.Split(',').Reverse();
|
||||
};
|
||||
|
||||
//get nearest published item
|
||||
Func<IEnumerable<string>, int> getClosestPublishedAncestor = (path =>
|
||||
{
|
||||
|
||||
foreach (var _id in path)
|
||||
{
|
||||
var item = Umbraco.TypedContent(int.Parse(_id));
|
||||
|
||||
if (item != null)
|
||||
return item.Id;
|
||||
}
|
||||
return -1;
|
||||
});
|
||||
|
||||
var rootXpath = "descendant::*[@id={0}]";
|
||||
|
||||
//parseable items:
|
||||
var vars = new Dictionary<string, Func<string, string>>();
|
||||
vars.Add("$current", q => {
|
||||
var _id = getClosestPublishedAncestor(getPath(id));
|
||||
return q.Replace("$current", string.Format(rootXpath, _id));
|
||||
});
|
||||
|
||||
vars.Add("$parent", q =>
|
||||
{
|
||||
//remove the first item in the array if its the current node
|
||||
//this happens when current is published, but we are looking for its parent specifically
|
||||
var path = getPath(id);
|
||||
if(path.ElementAt(0) == id.ToString()){
|
||||
path = path.Skip(1);
|
||||
}
|
||||
|
||||
var _id = getClosestPublishedAncestor(path);
|
||||
return q.Replace("$parent", string.Format(rootXpath, _id));
|
||||
});
|
||||
|
||||
|
||||
vars.Add("$site", q =>
|
||||
{
|
||||
var _id = getClosestPublishedAncestor(getPath(id));
|
||||
return q.Replace("$site", string.Format(rootXpath, _id) + "/ancestor-or-self::*[@level = 1]");
|
||||
});
|
||||
|
||||
|
||||
vars.Add("$root", q =>
|
||||
{
|
||||
return q.Replace("$root", string.Empty);
|
||||
});
|
||||
|
||||
|
||||
foreach (var varible in vars)
|
||||
{
|
||||
if (query.StartsWith(varible.Key))
|
||||
{
|
||||
query = varible.Value.Invoke(query);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public EntityBasic GetById(int id, UmbracoEntityTypes type)
|
||||
{
|
||||
return GetResultForId(id, type);
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors.ValueConverters
|
||||
{
|
||||
/// <summary>
|
||||
/// Ensures that no matter what is selected in MNTP that the value results in a string
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// See here for full details:http://issues.umbraco.org/issue/U4-3776
|
||||
/// </remarks>
|
||||
[DefaultPropertyValueConverter]
|
||||
[PropertyValueType(typeof (string))]
|
||||
[PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Request)]
|
||||
public class MntpStringValueConverter : PropertyValueConverterBase
|
||||
{
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
{
|
||||
return propertyType.PropertyEditorAlias == Constants.PropertyEditors.MultiNodeTreePickerAlias;
|
||||
}
|
||||
|
||||
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
if (source == null) return null;
|
||||
return source.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -478,6 +478,10 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
// I'm not sure that _properties contains all properties including those without a value,
|
||||
// neither that GetProperty will return a property without a value vs. null... @zpqrtbnk
|
||||
|
||||
// List of properties that will appear in the XML and do not match
|
||||
// anything in the ContentType, so they must be ignored.
|
||||
private static readonly string[] IgnoredKeys = { "version", "isDoc", "key" };
|
||||
|
||||
public DictionaryPublishedContent(
|
||||
IDictionary<string, string> valueDictionary,
|
||||
Func<DictionaryPublishedContent, IPublishedContent> getParent,
|
||||
@@ -528,8 +532,8 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
{
|
||||
IPublishedProperty property = null;
|
||||
|
||||
// must ignore that one
|
||||
if (i.Key == "version" || i.Key == "isDoc") continue;
|
||||
// must ignore those
|
||||
if (IgnoredKeys.Contains(i.Key)) continue;
|
||||
|
||||
if (i.Key.InvariantStartsWith("__"))
|
||||
{
|
||||
@@ -540,6 +544,8 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
|
||||
{
|
||||
// use property type to ensure proper conversion
|
||||
var propertyType = _contentType.GetPropertyType(i.Key);
|
||||
if (propertyType == null)
|
||||
throw new Exception("Internal error, property '" + i.Key + "' is not a valid property for that type of content.");
|
||||
property = new XmlPublishedProperty(propertyType, false, i.Value); // false :: never preview a media
|
||||
}
|
||||
|
||||
|
||||
@@ -81,10 +81,15 @@ namespace Umbraco.Web.Strategies.DataTypes
|
||||
|
||||
var dimensions = isImageType ? GetDimensions(path, fileSystem) : null;
|
||||
|
||||
// only add dimensions to web images
|
||||
content.getProperty(uploadFieldConfigNode.WidthFieldAlias).Value = isImageType ? dimensions.Item1.ToString(CultureInfo.InvariantCulture) : string.Empty;
|
||||
content.getProperty(uploadFieldConfigNode.HeightFieldAlias).Value = isImageType ? dimensions.Item2.ToString(CultureInfo.InvariantCulture) : string.Empty;
|
||||
content.getProperty(uploadFieldConfigNode.LengthFieldAlias).Value = size == default(long) ? string.Empty : size.ToString(CultureInfo.InvariantCulture);
|
||||
|
||||
if (isImageType)
|
||||
{
|
||||
// only add dimensions to web images
|
||||
content.getProperty(uploadFieldConfigNode.WidthFieldAlias).Value = dimensions.Item1.ToString(CultureInfo.InvariantCulture);
|
||||
content.getProperty(uploadFieldConfigNode.HeightFieldAlias).Value = dimensions.Item2.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
content.getProperty(uploadFieldConfigNode.LengthFieldAlias).Value = size == default(long) ? string.Empty : size.ToString(CultureInfo.InvariantCulture);
|
||||
content.getProperty(uploadFieldConfigNode.ExtensionFieldAlias).Value = string.IsNullOrEmpty(extension) ? string.Empty : extension;
|
||||
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace Umbraco.Web.UI.JavaScript
|
||||
/// <summary>
|
||||
/// Could allow developers to add custom variables on startup
|
||||
/// </summary>
|
||||
public static EventHandler<Dictionary<string, object>> Parsing;
|
||||
public static event EventHandler<Dictionary<string, object>> Parsing;
|
||||
|
||||
internal const string Token = "##Variables##";
|
||||
|
||||
@@ -24,7 +24,8 @@ namespace Umbraco.Web.UI.JavaScript
|
||||
}
|
||||
|
||||
var json = JObject.FromObject(items);
|
||||
return vars.Replace(Token, json.ToString());
|
||||
return vars.Replace(Token, json.ToString());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -397,7 +397,6 @@
|
||||
<Compile Include="PropertyEditors\TagsPropertyEditor.cs" />
|
||||
<Compile Include="PropertyEditors\UploadFileTypeValidator.cs" />
|
||||
<Compile Include="PropertyEditors\UserPickerPropertyEditor.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\MntpStringValueConverter.cs" />
|
||||
<Compile Include="PropertyEditors\ValueConverters\RelatedLinksEditorValueConvertor.cs" />
|
||||
<Compile Include="PropertyEditors\ValueListPreValueEditor.cs" />
|
||||
<Compile Include="PropertyEditors\DropDownPropertyEditor.cs" />
|
||||
|
||||
@@ -64,12 +64,14 @@ namespace Umbraco.Web.WebServices
|
||||
|
||||
// process domains
|
||||
|
||||
foreach (var domain in domains.Where(d => model.Domains.All(m => !m.Name.Equals(d.Name, StringComparison.OrdinalIgnoreCase))))
|
||||
// delete every (non-wildcard) domain, that exists in the DB yet is not in the model
|
||||
foreach (var domain in domains.Where(d => d.IsWildcard == false && model.Domains.All(m => m.Name.Equals(d.Name, StringComparison.OrdinalIgnoreCase) == false)))
|
||||
domain.Delete();
|
||||
|
||||
var names = new List<string>();
|
||||
|
||||
foreach (var domainModel in model.Domains.Where(m => !string.IsNullOrWhiteSpace(m.Name)))
|
||||
// create or update domains in the model
|
||||
foreach (var domainModel in model.Domains.Where(m => string.IsNullOrWhiteSpace(m.Name) == false))
|
||||
{
|
||||
language = languages.FirstOrDefault(l => l.id == domainModel.Lang);
|
||||
if (language == null)
|
||||
@@ -90,7 +92,7 @@ namespace Umbraco.Web.WebServices
|
||||
Domain.MakeNew(name, model.NodeId, domainModel.Lang);
|
||||
}
|
||||
|
||||
model.Valid = model.Domains.All(m => !m.Duplicate);
|
||||
model.Valid = model.Domains.All(m => m.Duplicate == false);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
@@ -497,19 +497,6 @@ namespace umbraco.providers
|
||||
return false;
|
||||
}
|
||||
|
||||
//Due to the way this legacy provider worked, when it 'validated' a password passed in, it would allow
|
||||
// having the already hashed/encrypted password checked directly - this is bad but hey, we gotta support legacy
|
||||
// don't we.
|
||||
|
||||
//So, first we'll check if the user object's db stored password (already hashed/encrypted in the db) matches the password that
|
||||
// has been passed in, if so then we will confirm that it is valid. If it doesn't we'll attempt to hash/encrypt the passed in
|
||||
// password and then validate it - the way it is supposed to be done.
|
||||
|
||||
if (user.Password == password)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return CheckPassword(password, user.Password);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user