diff --git a/src/Umbraco.Core/Models/ContentTypeBase.cs b/src/Umbraco.Core/Models/ContentTypeBase.cs
index 953ef5ccce..00e9c1e30c 100644
--- a/src/Umbraco.Core/Models/ContentTypeBase.cs
+++ b/src/Umbraco.Core/Models/ContentTypeBase.cs
@@ -6,6 +6,7 @@ using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
using Umbraco.Core.Models.EntityBase;
+using Umbraco.Core.Strings;
namespace Umbraco.Core.Models
{
@@ -173,7 +174,8 @@ namespace Umbraco.Core.Models
{
SetPropertyValueAndDetectChanges(o =>
{
- _alias = value.ToSafeAlias();
+ //_alias = value.ToSafeAlias();
+ _alias = value.ToCleanString(CleanStringType.Alias | CleanStringType.UmbracoCase);
return _alias;
}, _alias, AliasSelector);
}
diff --git a/src/Umbraco.Core/Models/PropertyType.cs b/src/Umbraco.Core/Models/PropertyType.cs
index ddc06a5d47..d38a516911 100644
--- a/src/Umbraco.Core/Models/PropertyType.cs
+++ b/src/Umbraco.Core/Models/PropertyType.cs
@@ -5,6 +5,7 @@ using System.Text.RegularExpressions;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Persistence;
using Umbraco.Core.PropertyEditors;
+using Umbraco.Core.Strings;
namespace Umbraco.Core.Models
{
@@ -96,7 +97,7 @@ namespace Umbraco.Core.Models
{
SetPropertyValueAndDetectChanges(o =>
{
- _alias = value;
+ _alias = value.ToCleanString(CleanStringType.Alias | CleanStringType.UmbracoCase);
return _alias;
}, _alias, AliasSelector);
}
diff --git a/src/Umbraco.Core/Strings/CleanStringType.cs b/src/Umbraco.Core/Strings/CleanStringType.cs
index 4c53be4cb8..ea9603ec6f 100644
--- a/src/Umbraco.Core/Strings/CleanStringType.cs
+++ b/src/Umbraco.Core/Strings/CleanStringType.cs
@@ -57,8 +57,9 @@ namespace Umbraco.Core.Strings
///
/// Umbraco "safe alias" case.
///
- /// This is for backward compatibility. Casing is unchanged within terms,
- /// and is pascal otherwise.
+ /// Uppercases the first char of each term except for the first
+ /// char of the string, everything else including the first char of the
+ /// string is unchanged.
UmbracoCase = 0x20,
diff --git a/src/Umbraco.Core/Strings/DefaultShortStringHelper.cs b/src/Umbraco.Core/Strings/DefaultShortStringHelper.cs
index 526706aa3a..84233e59bf 100644
--- a/src/Umbraco.Core/Strings/DefaultShortStringHelper.cs
+++ b/src/Umbraco.Core/Strings/DefaultShortStringHelper.cs
@@ -287,7 +287,7 @@ namespace Umbraco.Core.Strings
var UMBRACO_FORCE_SAFE_ALIAS = {0};
var UMBRACO_FORCE_SAFE_ALIAS_URL = '{1}';
var UMBRACO_FORCE_SAFE_ALIAS_TIMEOUT = 666;
-var UMBRACO_FORCE_SAFE_ALIAS_TIMEOUTS = {{ }};
+var UMBRACO_FORCE_SAFE_ALIAS_TMKEY = 'safe-alias-tmout';
function getSafeAliasFromServer(value, callback) {{
$.getJSON(UMBRACO_FORCE_SAFE_ALIAS_URL + 'ToSafeAlias?value=' + encodeURIComponent(value), function(json) {{
@@ -295,28 +295,30 @@ function getSafeAliasFromServer(value, callback) {{
}});
}}
-function getSafeAlias(id, value, immediate, callback) {{
+function getSafeAlias(input, value, immediate, callback) {{
if (!UMBRACO_FORCE_SAFE_ALIAS) {{
callback(value);
return;
}}
- if (UMBRACO_FORCE_SAFE_ALIAS_TIMEOUTS[id]) clearTimeout(UMBRACO_FORCE_SAFE_ALIAS_TIMEOUTS[id]);
- UMBRACO_FORCE_SAFE_ALIAS_TIMEOUTS[id] = setTimeout(function() {{
- UMBRACO_FORCE_SAFE_ALIAS_TIMEOUTS[id] = null;
+ var timeout = input.data(UMBRACO_FORCE_SAFE_ALIAS_TMKEY);
+ if (timeout) clearTimeout(timeout);
+ input.data(UMBRACO_FORCE_SAFE_ALIAS_TMKEY, setTimeout(function() {{
+ input.removeData(UMBRACO_FORCE_SAFE_ALIAS_TMKEY);
getSafeAliasFromServer(value, function(alias) {{ callback(alias); }});
- }}, UMBRACO_FORCE_SAFE_ALIAS_TIMEOUT);
+ }}, UMBRACO_FORCE_SAFE_ALIAS_TIMEOUT));
}}
-function validateSafeAlias(id, value, immediate, callback) {{
+function validateSafeAlias(input, value, immediate, callback) {{
if (!UMBRACO_FORCE_SAFE_ALIAS) {{
callback(true);
return;
}}
- if (UMBRACO_FORCE_SAFE_ALIAS_TIMEOUTS[id]) clearTimeout(UMBRACO_FORCE_SAFE_ALIAS_TIMEOUTS[id]);
- UMBRACO_FORCE_SAFE_ALIAS_TIMEOUTS[id] = setTimeout(function() {{
- UMBRACO_FORCE_SAFE_ALIAS_TIMEOUTS[id] = null;
+ var timeout = input.data(UMBRACO_FORCE_SAFE_ALIAS_TMKEY);
+ if (timeout) clearTimeout(timeout);
+ input.data(UMBRACO_FORCE_SAFE_ALIAS_TMKEY, setTimeout(function() {{
+ input.removeData(UMBRACO_FORCE_SAFE_ALIAS_TMKEY);
getSafeAliasFromServer(value, function(alias) {{ callback(value.toLowerCase() == alias.toLowerCase()); }});
- }}, UMBRACO_FORCE_SAFE_ALIAS_TIMEOUT);
+ }}, UMBRACO_FORCE_SAFE_ALIAS_TIMEOUT));
}}
";
diff --git a/src/Umbraco.Core/Strings/LegacyShortStringHelper.cs b/src/Umbraco.Core/Strings/LegacyShortStringHelper.cs
index 1c780703f4..901c9ee299 100644
--- a/src/Umbraco.Core/Strings/LegacyShortStringHelper.cs
+++ b/src/Umbraco.Core/Strings/LegacyShortStringHelper.cs
@@ -74,11 +74,11 @@ function safeAlias(alias) {{
return alias;
}}
-function getSafeAlias(id, value, immediate, callback) {{
+function getSafeAlias(input, value, immediate, callback) {{
callback(safeAlias(value));
}}
-function validateSafeAlias(id, value, immediate, callback) {{
+function validateSafeAlias(input, value, immediate, callback) {{
callback(value == safeAlias(value));
}}
diff --git a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx
index 3a9bd18b96..6c8d26b4d6 100644
--- a/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx
+++ b/src/Umbraco.Web.UI/umbraco/controls/ContentTypeControlNew.ascx
@@ -114,7 +114,7 @@
checkAlias('.prop-alias');
- duplicatePropertyNameAsSafeAlias('ul.addNewProperty .prop-name', 'ul.addNewProperty .prop-alias');
+ duplicatePropertyNameAsSafeAlias('ul.addNewProperty');
jQuery(".picker-icons").click(function(){
var that = this;
diff --git a/src/Umbraco.Web.UI/umbraco_client/GenericProperty/genericProperty.js b/src/Umbraco.Web.UI/umbraco_client/GenericProperty/genericProperty.js
index 5242c9d5aa..77bfa813d9 100644
--- a/src/Umbraco.Web.UI/umbraco_client/GenericProperty/genericProperty.js
+++ b/src/Umbraco.Web.UI/umbraco_client/GenericProperty/genericProperty.js
@@ -12,31 +12,35 @@ function expandCollapse(theId) {
document.getElementById("desc" + theId).style.display = 'block';
}
}
-function duplicatePropertyNameAsSafeAlias(nameId, aliasId) {
- var input = $(aliasId);
-
- $(nameId).keyup(function(event) {
- var value = $(this).val();
- getSafeAlias(aliasId, value, false, function (alias) {
- input.val(alias);
+function duplicatePropertyNameAsSafeAlias(propertySelector) {
+ $(propertySelector).each(function() {
+ var prop = $(this);
+ var inputName = prop.find('.prop-name');
+ var inputAlias = prop.find('.prop-alias');
+ inputName.on('input', function (event) {
+ getSafeAlias(inputAlias, inputName.val(), false, function (alias) {
+ inputAlias.val(alias);
+ });
+ }).on('blur', function (event) {
+ $(this).off('input');
});
});
}
-function checkAlias(aliasId) {
- $(aliasId).keyup(function (event) {
+function checkAlias(aliasSelector) {
+ $(aliasSelector).keyup(function (event) {
var input = $(this);
var value = input.val();
- validateSafeAlias(aliasId, value, false, function (isSafe) {
- input.toggleClass('aliasValidationError', !isSafe);
+ validateSafeAlias(input, value, false, function (isSafe) {
+ input.toggleClass('highlight-error', !isSafe);
});
}).blur(function(event) {
var input = $(this);
var value = input.val();
- getSafeAlias(aliasId, value, true, function (alias) {
+ getSafeAlias(input, value, true, function (alias) {
if (value.toLowerCase() != alias.toLowerCase())
input.val(alias);
- input.removeClass('aliasValidationError');
+ input.removeClass('highlight-error');
});
});
}
diff --git a/src/Umbraco.Web/WebServices/CoreStringsController.cs b/src/Umbraco.Web/WebServices/CoreStringsController.cs
index 78eb449273..6da704a520 100644
--- a/src/Umbraco.Web/WebServices/CoreStringsController.cs
+++ b/src/Umbraco.Web/WebServices/CoreStringsController.cs
@@ -20,9 +20,11 @@ namespace Umbraco.Web.WebServices
[HttpGet]
public JsonResult ToSafeAlias(string value, bool camelCase = true)
{
+ // always return a proper camel-cased alias
+ // when checking... javascript does a case-unsensitive comparison
return value == null
? Json(new {error = "no value."}, JsonRequestBehavior.AllowGet)
- : Json(new { alias = value.ToSafeAlias(camelCase) }, JsonRequestBehavior.AllowGet);
+ : Json(new { alias = value.ToCleanString(CleanStringType.Alias | CleanStringType.CamelCase) }, JsonRequestBehavior.AllowGet);
}
[HttpGet]
diff --git a/src/Umbraco.Web/umbraco.presentation/macro.cs b/src/Umbraco.Web/umbraco.presentation/macro.cs
index 5934b6e7e7..7f58c326b3 100644
--- a/src/Umbraco.Web/umbraco.presentation/macro.cs
+++ b/src/Umbraco.Web/umbraco.presentation/macro.cs
@@ -216,8 +216,8 @@ namespace umbraco
if (CacheByPersonalization)
{
- var currentMember = Member.GetCurrentMember();
- id.AppendFormat("m{0}-", currentMember == null ? 0 : currentMember.Id);
+ int currentMember = Member.CurrentMemberId();
+ id.AppendFormat("m{0}-", currentMember);
}
foreach (var prop in model.Properties)
@@ -525,7 +525,7 @@ namespace umbraco
if (Model.CacheDuration > 0)
{
// do not add to cache if there's no member and it should cache by personalization
- if (!Model.CacheByMember || (Model.CacheByMember && Member.GetCurrentMember() != null))
+ if (!Model.CacheByMember || (Model.CacheByMember && Member.IsLoggedOn()))
{
if (macroControl != null)
{
diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs
index 6f68024c79..7a94afced9 100644
--- a/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs
+++ b/src/Umbraco.Web/umbraco.presentation/umbraco/controls/ContentTypeControlNew.ascx.cs
@@ -293,7 +293,7 @@ namespace umbraco.controls
global::Umbraco.Web.UmbracoContext.Current = asyncState.UmbracoContext;
_contentType.ContentTypeItem.Name = txtName.Text;
- _contentType.ContentTypeItem.Alias = txtAlias.Text;
+ _contentType.ContentTypeItem.Alias = txtAlias.Text; // raw, contentType.Alias takes care of it
_contentType.ContentTypeItem.Icon = tb_icon.Value;
_contentType.ContentTypeItem.Description = description.Text;
//_contentType.ContentTypeItem.Thumbnail = ddlThumbnails.SelectedValue;
@@ -832,7 +832,9 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }});
GenericProperty gpData = gp.GenricPropertyControl;
if (string.IsNullOrEmpty(gpData.Name.Trim()) == false && string.IsNullOrEmpty(gpData.Alias.Trim()) == false)
{
- var propertyTypeAlias = Casing.SafeAliasWithForcingCheck(gpData.Alias.Trim());
+ // when creating a property don't do anything special, propertyType.Alias will take care of it
+ // don't enforce camel here because the user might have changed what the CoreStringsController returned
+ var propertyTypeAlias = gpData.Alias;
if (contentTypeItem.PropertyTypeExists(propertyTypeAlias) == false)
{
//Find the DataTypeDefinition that the PropertyType should be based on
@@ -889,6 +891,7 @@ jQuery(document).ready(function() {{ refreshDropDowns(); }});
var propertyType = contentTypeItem.PropertyTypes.First(x => x.Alias == gpw.PropertyType.Alias);
if (propertyType == null) continue;
var dataTypeDefinition = ApplicationContext.Current.Services.DataTypeService.GetDataTypeDefinitionById(gpw.GenricPropertyControl.Type);
+ // when saving, respect user's casing, so do nothing here as propertyType takes care of it
propertyType.Alias = gpw.GenricPropertyControl.Alias;
propertyType.Name = gpw.GenricPropertyControl.Name;
propertyType.Description = gpw.GenricPropertyControl.Description;
diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/create/nodetypeTasks.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/create/nodetypeTasks.cs
index 9c20f3b889..0b54756b74 100644
--- a/src/Umbraco.Web/umbraco.presentation/umbraco/create/nodetypeTasks.cs
+++ b/src/Umbraco.Web/umbraco.presentation/umbraco/create/nodetypeTasks.cs
@@ -5,6 +5,7 @@ using System.Web.Security;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Models;
+using Umbraco.Core.Strings;
using Umbraco.Web.UI;
using umbraco.BusinessLogic;
using umbraco.DataLayer;
@@ -26,7 +27,9 @@ namespace umbraco
? new ContentType(-1)
: new ContentType(ApplicationContext.Current.Services.ContentTypeService.GetContentType(parentId));
contentType.CreatorId = User.Id;
- contentType.Alias = Alias.Replace("'", "''");
+ // when creating a content type, enforce PascalCase
+ // preserve separator because contentType.Alias will re-alias it
+ contentType.Alias = Alias.ToCleanString(CleanStringType.Alias | CleanStringType.PascalCase, ' ');
contentType.Name = Alias.Replace("'", "''");
contentType.Icon = ".sprTreeFolder";