Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7f02bc7d1d | |||
| 44b6738b0d | |||
| fbb19cba0b | |||
| 84554101f2 | |||
| 8a3b2e038c | |||
| 296d7964ae | |||
| ed5effd190 | |||
| 57e58c6cf7 | |||
| 34e45abcc7 | |||
| b3497011e8 | |||
| a398881fa1 | |||
| 2cf3a7831c | |||
| 0138091a6c | |||
| 6c0fb2f849 | |||
| e495faf83c | |||
| 8721423f40 | |||
| 49b3351c72 | |||
| faef449750 | |||
| 4a24064783 | |||
| 0ab84fc443 |
@@ -203,6 +203,24 @@ namespace Umbraco.Core
|
||||
/// <remarks>Must be a valid <see cref="ValueTypes"/> value.</remarks>
|
||||
public const string DataValueType = "umbracoDataValueType";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines Umbraco's built-in property editor groups.
|
||||
/// </summary>
|
||||
public static class Groups
|
||||
{
|
||||
public const string Common = "Common";
|
||||
|
||||
public const string Lists = "Lists";
|
||||
|
||||
public const string Media = "Media";
|
||||
|
||||
public const string People = "People";
|
||||
|
||||
public const string Pickers = "Pickers";
|
||||
|
||||
public const string RichContent = "Rich Content";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Umbraco.Core.PropertyEditors
|
||||
// defaults
|
||||
Type = type;
|
||||
Icon = Constants.Icons.PropertyEditor;
|
||||
Group = "common";
|
||||
Group = Constants.PropertyEditors.Groups.Common;
|
||||
|
||||
// assign properties based on the attribute, if it is found
|
||||
Attribute = GetType().GetCustomAttribute<DataEditorAttribute>(false);
|
||||
|
||||
@@ -121,7 +121,7 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// Gets or sets an optional group.
|
||||
/// </summary>
|
||||
/// <remarks>The group can be used for example to group the editors by category.</remarks>
|
||||
public string Group { get; set; } = "common";
|
||||
public string Group { get; set; } = Constants.PropertyEditors.Groups.Common;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the value editor is deprecated.
|
||||
|
||||
@@ -5,7 +5,11 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// <summary>
|
||||
/// Represents a property editor for label properties.
|
||||
/// </summary>
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.Label, "Label", "readonlyvalue", Icon = "icon-readonly")]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.Label,
|
||||
"Label",
|
||||
"readonlyvalue",
|
||||
Icon = "icon-readonly")]
|
||||
public class LabelPropertyEditor : DataEditor
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace Umbraco.Examine
|
||||
continue;
|
||||
case string strVal:
|
||||
{
|
||||
if (strVal.IsNullOrWhiteSpace()) return;
|
||||
if (strVal.IsNullOrWhiteSpace()) continue;
|
||||
var key = $"{keyVal.Key}{cultureSuffix}";
|
||||
if (values.TryGetValue(key, out var v))
|
||||
values[key] = new List<object>(v) { val }.ToArray();
|
||||
|
||||
@@ -81,6 +81,19 @@ namespace Umbraco.Tests.Routing
|
||||
Assert.AreEqual(expected, resolvedUrl);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_Media_Url_Returns_Absolute_Url_If_Stored_Url_Is_Absolute()
|
||||
{
|
||||
const string expected = "http://localhost/media/rfeiw584/test.jpg";
|
||||
|
||||
var umbracoContext = GetUmbracoContext("http://localhost", mediaUrlProviders: new[] { _mediaUrlProvider });
|
||||
var publishedContent = CreatePublishedContent(Constants.PropertyEditors.Aliases.UploadField, expected, null);
|
||||
|
||||
var resolvedUrl = umbracoContext.UrlProvider.GetMediaUrl(publishedContent, UrlMode.Relative);
|
||||
|
||||
Assert.AreEqual(expected, resolvedUrl);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_Media_Url_Returns_Empty_String_When_PropertyType_Is_Not_Supported()
|
||||
{
|
||||
|
||||
@@ -25,19 +25,23 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting
|
||||
public async Task<Tuple<HttpResponseMessage, string>> Execute(string controllerName, string actionName, HttpMethod method,
|
||||
HttpContent content = null,
|
||||
MediaTypeWithQualityHeaderValue mediaTypeHeader = null,
|
||||
bool assertOkResponse = true)
|
||||
bool assertOkResponse = true, object routeDefaults = null, string url = null)
|
||||
{
|
||||
if (mediaTypeHeader == null)
|
||||
{
|
||||
mediaTypeHeader = new MediaTypeWithQualityHeaderValue("application/json");
|
||||
}
|
||||
if (routeDefaults == null)
|
||||
{
|
||||
routeDefaults = new { controller = controllerName, action = actionName, id = RouteParameter.Optional };
|
||||
}
|
||||
|
||||
var startup = new TestStartup(
|
||||
configuration =>
|
||||
{
|
||||
configuration.Routes.MapHttpRoute("Default",
|
||||
routeTemplate: "{controller}/{action}/{id}",
|
||||
defaults: new { controller = controllerName, action = actionName, id = RouteParameter.Optional });
|
||||
defaults: routeDefaults);
|
||||
},
|
||||
_controllerFactory);
|
||||
|
||||
@@ -45,7 +49,7 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting
|
||||
{
|
||||
var request = new HttpRequestMessage
|
||||
{
|
||||
RequestUri = new Uri("https://testserver/"),
|
||||
RequestUri = new Uri("https://testserver/" + (url ?? "")),
|
||||
Method = method
|
||||
};
|
||||
|
||||
|
||||
@@ -243,6 +243,7 @@
|
||||
<Compile Include="Cache\FullDataSetCachePolicyTests.cs" />
|
||||
<Compile Include="Cache\SingleItemsOnlyCachePolicyTests.cs" />
|
||||
<Compile Include="Collections\DeepCloneableListTests.cs" />
|
||||
<Compile Include="Web\Controllers\AuthenticationControllerTests.cs" />
|
||||
<Compile Include="Web\Controllers\BackOfficeControllerUnitTests.cs" />
|
||||
<Compile Include="CoreThings\DelegateExtensionsTests.cs" />
|
||||
<Compile Include="Web\Controllers\ContentControllerTests.cs" />
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading;
|
||||
using System.Web;
|
||||
using System.Web.Hosting;
|
||||
using System.Web.Http;
|
||||
using Moq;
|
||||
using Newtonsoft.Json;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Mappers;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.ControllerTesting;
|
||||
using Umbraco.Tests.Testing;
|
||||
using Umbraco.Web;
|
||||
using Umbraco.Web.Editors;
|
||||
using Umbraco.Web.Features;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using IUser = Umbraco.Core.Models.Membership.IUser;
|
||||
|
||||
namespace Umbraco.Tests.Web.Controllers
|
||||
{
|
||||
[TestFixture]
|
||||
[UmbracoTest(Database = UmbracoTestOptions.Database.None)]
|
||||
public class AuthenticationControllerTests : TestWithDatabaseBase
|
||||
{
|
||||
protected override void ComposeApplication(bool withApplication)
|
||||
{
|
||||
base.ComposeApplication(withApplication);
|
||||
//if (!withApplication) return;
|
||||
|
||||
// replace the true IUserService implementation with a mock
|
||||
// so that each test can configure the service to their liking
|
||||
Composition.RegisterUnique(f => Mock.Of<IUserService>());
|
||||
|
||||
// kill the true IEntityService too
|
||||
Composition.RegisterUnique(f => Mock.Of<IEntityService>());
|
||||
|
||||
Composition.RegisterUnique<UmbracoFeatures>();
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public async System.Threading.Tasks.Task GetCurrentUser_Fips()
|
||||
{
|
||||
ApiController CtrlFactory(HttpRequestMessage message, IUmbracoContextAccessor umbracoContextAccessor, UmbracoHelper helper)
|
||||
{
|
||||
//setup some mocks
|
||||
var userServiceMock = Mock.Get(Current.Services.UserService);
|
||||
userServiceMock.Setup(service => service.GetUserById(It.IsAny<int>()))
|
||||
.Returns(() => null);
|
||||
|
||||
if (Thread.GetDomain().GetData(".appPath") != null)
|
||||
{
|
||||
HttpContext.Current = new HttpContext(new SimpleWorkerRequest("", "", new StringWriter()));
|
||||
}
|
||||
else
|
||||
{
|
||||
var baseDir = IOHelper.MapPath("", false).TrimEnd(IOHelper.DirSepChar);
|
||||
HttpContext.Current = new HttpContext(new SimpleWorkerRequest("/", baseDir, "", "", new StringWriter()));
|
||||
}
|
||||
IOHelper.ForceNotHosted = true;
|
||||
var usersController = new AuthenticationController(
|
||||
Factory.GetInstance<IGlobalSettings>(),
|
||||
umbracoContextAccessor,
|
||||
Factory.GetInstance<ISqlContext>(),
|
||||
Factory.GetInstance<ServiceContext>(),
|
||||
Factory.GetInstance<AppCaches>(),
|
||||
Factory.GetInstance<IProfilingLogger>(),
|
||||
Factory.GetInstance<IRuntimeState>(),
|
||||
helper);
|
||||
return usersController;
|
||||
}
|
||||
|
||||
Mock.Get(Current.SqlContext)
|
||||
.Setup(x => x.Query<IUser>())
|
||||
.Returns(new Query<IUser>(Current.SqlContext));
|
||||
|
||||
var syntax = new SqlCeSyntaxProvider();
|
||||
|
||||
Mock.Get(Current.SqlContext)
|
||||
.Setup(x => x.SqlSyntax)
|
||||
.Returns(syntax);
|
||||
|
||||
var mappers = new MapperCollection(new[]
|
||||
{
|
||||
new UserMapper(new Lazy<ISqlContext>(() => Current.SqlContext), new ConcurrentDictionary<Type, ConcurrentDictionary<string, string>>())
|
||||
});
|
||||
|
||||
Mock.Get(Current.SqlContext)
|
||||
.Setup(x => x.Mappers)
|
||||
.Returns(mappers);
|
||||
|
||||
// Testing what happens if the system were configured to only use FIPS-compliant algorithms
|
||||
var typ = typeof(CryptoConfig);
|
||||
var flds = typ.GetFields(BindingFlags.Static | BindingFlags.NonPublic);
|
||||
var haveFld = flds.FirstOrDefault(f => f.Name == "s_haveFipsAlgorithmPolicy");
|
||||
var isFld = flds.FirstOrDefault(f => f.Name == "s_fipsAlgorithmPolicy");
|
||||
var originalFipsValue = CryptoConfig.AllowOnlyFipsAlgorithms;
|
||||
|
||||
try
|
||||
{
|
||||
if (!originalFipsValue)
|
||||
{
|
||||
haveFld.SetValue(null, true);
|
||||
isFld.SetValue(null, true);
|
||||
}
|
||||
|
||||
var runner = new TestRunner(CtrlFactory);
|
||||
var response = await runner.Execute("Authentication", "GetCurrentUser", HttpMethod.Get);
|
||||
|
||||
var obj = JsonConvert.DeserializeObject<UserDetail>(response.Item2);
|
||||
Assert.AreEqual(-1, obj.UserId);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!originalFipsValue)
|
||||
{
|
||||
haveFld.SetValue(null, false);
|
||||
isFld.SetValue(null, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Formatting;
|
||||
using System.Reflection;
|
||||
using System.Security.Cryptography;
|
||||
using System.Web.Http;
|
||||
using Moq;
|
||||
using Newtonsoft.Json;
|
||||
@@ -155,7 +157,7 @@ namespace Umbraco.Tests.Web.Controllers
|
||||
var runner = new TestRunner(CtrlFactory);
|
||||
var response = await runner.Execute("Users", "GetPagedUsers", HttpMethod.Get);
|
||||
|
||||
var obj = JsonConvert.DeserializeObject<PagedResult<UserDisplay>>(response.Item2);
|
||||
var obj = JsonConvert.DeserializeObject<PagedResult<UserBasic>>(response.Item2);
|
||||
Assert.AreEqual(0, obj.TotalItems);
|
||||
}
|
||||
|
||||
@@ -190,9 +192,100 @@ namespace Umbraco.Tests.Web.Controllers
|
||||
var runner = new TestRunner(CtrlFactory);
|
||||
var response = await runner.Execute("Users", "GetPagedUsers", HttpMethod.Get);
|
||||
|
||||
var obj = JsonConvert.DeserializeObject<PagedResult<UserDisplay>>(response.Item2);
|
||||
var obj = JsonConvert.DeserializeObject<PagedResult<UserBasic>>(response.Item2);
|
||||
Assert.AreEqual(10, obj.TotalItems);
|
||||
Assert.AreEqual(10, obj.Items.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async System.Threading.Tasks.Task GetPagedUsers_Fips()
|
||||
{
|
||||
await RunFipsTest("GetPagedUsers", mock =>
|
||||
{
|
||||
var users = MockedUser.CreateMulipleUsers(10);
|
||||
long outVal = 10;
|
||||
mock.Setup(service => service.GetAll(
|
||||
It.IsAny<long>(), It.IsAny<int>(), out outVal, It.IsAny<string>(), It.IsAny<Direction>(),
|
||||
It.IsAny<UserState[]>(), It.IsAny<string[]>(), It.IsAny<string[]>(), It.IsAny<IQuery<IUser>>()))
|
||||
.Returns(() => users);
|
||||
}, response =>
|
||||
{
|
||||
var obj = JsonConvert.DeserializeObject<PagedResult<UserBasic>>(response.Item2);
|
||||
Assert.AreEqual(10, obj.TotalItems);
|
||||
Assert.AreEqual(10, obj.Items.Count());
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async System.Threading.Tasks.Task GetById_Fips()
|
||||
{
|
||||
const int mockUserId = 1234;
|
||||
var user = MockedUser.CreateUser();
|
||||
|
||||
await RunFipsTest("GetById", mock =>
|
||||
{
|
||||
mock.Setup(service => service.GetUserById(1234))
|
||||
.Returns((int i) => i == mockUserId ? user : null);
|
||||
}, response =>
|
||||
{
|
||||
var obj = JsonConvert.DeserializeObject<UserDisplay>(response.Item2);
|
||||
Assert.AreEqual(user.Username, obj.Username);
|
||||
Assert.AreEqual(user.Email, obj.Email);
|
||||
}, new { controller = "Users", action = "GetById" }, $"Users/GetById/{mockUserId}");
|
||||
}
|
||||
|
||||
|
||||
private async System.Threading.Tasks.Task RunFipsTest(string action, Action<Mock<IUserService>> userServiceSetup,
|
||||
Action<Tuple<HttpResponseMessage, string>> verification,
|
||||
object routeDefaults = null, string url = null)
|
||||
{
|
||||
ApiController CtrlFactory(HttpRequestMessage message, IUmbracoContextAccessor umbracoContextAccessor, UmbracoHelper helper)
|
||||
{
|
||||
//setup some mocks
|
||||
var userServiceMock = Mock.Get(Current.Services.UserService);
|
||||
userServiceSetup(userServiceMock);
|
||||
|
||||
var usersController = new UsersController(
|
||||
Factory.GetInstance<IGlobalSettings>(),
|
||||
umbracoContextAccessor,
|
||||
Factory.GetInstance<ISqlContext>(),
|
||||
Factory.GetInstance<ServiceContext>(),
|
||||
Factory.GetInstance<AppCaches>(),
|
||||
Factory.GetInstance<IProfilingLogger>(),
|
||||
Factory.GetInstance<IRuntimeState>(),
|
||||
helper);
|
||||
return usersController;
|
||||
}
|
||||
|
||||
// Testing what happens if the system were configured to only use FIPS-compliant algorithms
|
||||
var typ = typeof(CryptoConfig);
|
||||
var flds = typ.GetFields(BindingFlags.Static | BindingFlags.NonPublic);
|
||||
var haveFld = flds.FirstOrDefault(f => f.Name == "s_haveFipsAlgorithmPolicy");
|
||||
var isFld = flds.FirstOrDefault(f => f.Name == "s_fipsAlgorithmPolicy");
|
||||
var originalFipsValue = CryptoConfig.AllowOnlyFipsAlgorithms;
|
||||
|
||||
try
|
||||
{
|
||||
if (!originalFipsValue)
|
||||
{
|
||||
haveFld.SetValue(null, true);
|
||||
isFld.SetValue(null, true);
|
||||
}
|
||||
|
||||
MockForGetPagedUsers();
|
||||
|
||||
var runner = new TestRunner(CtrlFactory);
|
||||
var response = await runner.Execute("Users", action, HttpMethod.Get, routeDefaults: routeDefaults, url: url);
|
||||
verification(response);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!originalFipsValue)
|
||||
{
|
||||
haveFld.SetValue(null, false);
|
||||
isFld.SetValue(null, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,13 +16,31 @@ module.exports = {
|
||||
//processed in the js task
|
||||
js: {
|
||||
preview: { files: ["./src/preview/**/*.js"], out: "umbraco.preview.js" },
|
||||
installer: { files: ["./src/installer/**/*.js"], out: "umbraco.installer.js" },
|
||||
controllers: { files: ["./src/{views,controllers}/**/*.controller.js"], out: "umbraco.controllers.js" },
|
||||
directives: { files: ["./src/common/directives/**/*.js"], out: "umbraco.directives.js" },
|
||||
installer: { files: ["./src/installer/**/*.js"], out: "umbraco.installer.js" },
|
||||
filters: { files: ["./src/common/filters/**/*.js"], out: "umbraco.filters.js" },
|
||||
resources: { files: ["./src/common/resources/**/*.js"], out: "umbraco.resources.js" },
|
||||
services: { files: ["./src/common/services/**/*.js"], out: "umbraco.services.js" },
|
||||
security: { files: ["./src/common/interceptors/**/*.js"], out: "umbraco.interceptors.js" }
|
||||
security: { files: ["./src/common/interceptors/**/*.js"], out: "umbraco.interceptors.js" },
|
||||
|
||||
//the controllers for views
|
||||
controllers: {
|
||||
files: [
|
||||
"./src/views/**/*.controller.js",
|
||||
"./src/*.controller.js"
|
||||
], out: "umbraco.controllers.js"
|
||||
},
|
||||
|
||||
//directives/components
|
||||
// - any JS file found in common / directives or common/ components
|
||||
// - any JS file found inside views that has the suffix .directive.js or .component.js
|
||||
directives: {
|
||||
files: [
|
||||
"./src/common/directives/_module.js",
|
||||
"./src/{common/directives,common/components}/**/*.js",
|
||||
"./src/{views}/**/*.{directive,component}.js"
|
||||
],
|
||||
out: "umbraco.directives.js"
|
||||
},
|
||||
},
|
||||
|
||||
//selectors for copying all views into the build
|
||||
@@ -34,7 +52,7 @@ module.exports = {
|
||||
|
||||
//globs for file-watching
|
||||
globs:{
|
||||
views: "./src/views/**/*.html",
|
||||
views: ["./src/views/**/*.html", "./src/common/directives/**/*.html", "./src/common/components/**/*.html" ],
|
||||
less: "./src/less/**/*.less",
|
||||
js: "./src/*.js",
|
||||
lib: "./lib/**/*",
|
||||
|
||||
@@ -23,7 +23,7 @@ module.exports = function(files, out) {
|
||||
// sort files in stream by path or any custom sort comparator
|
||||
task = task.pipe(babel())
|
||||
.pipe(sort())
|
||||
.pipe(embedTemplates({ basePath: "./src/" }))
|
||||
.pipe(embedTemplates({ basePath: "./src/", minimize:{ loose: true } }))
|
||||
.pipe(concat(out))
|
||||
.pipe(wrap('(function(){\n%= body %\n})();'))
|
||||
.pipe(gulp.dest(config.root + config.targets.js));
|
||||
|
||||
@@ -133,7 +133,7 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
* ##usage
|
||||
* <pre>
|
||||
* //get media by id
|
||||
* entityResource.getEntityById(0, "Media")
|
||||
* entityResource.getById(0, "Media")
|
||||
* .then(function(ent) {
|
||||
* var myDoc = ent;
|
||||
* alert('its here!');
|
||||
@@ -204,7 +204,7 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
* ##usage
|
||||
* <pre>
|
||||
* //Get templates for ids
|
||||
* entityResource.getEntitiesByIds( [1234,2526,28262], "Template")
|
||||
* entityResource.getByIds( [1234,2526,28262], "Template")
|
||||
* .then(function(templateArray) {
|
||||
* var myDoc = contentArray;
|
||||
* alert('they are here!');
|
||||
|
||||
@@ -261,7 +261,7 @@ When building a custom infinite editor view you can use the same components as a
|
||||
*/
|
||||
unbindKeyboardShortcuts();
|
||||
|
||||
// set flag so we know when the editor is open in "infinie mode"
|
||||
// set flag so we know when the editor is open in "infinite mode"
|
||||
editor.infiniteMode = true;
|
||||
|
||||
editors.push(editor);
|
||||
|
||||
@@ -94,6 +94,7 @@
|
||||
font-size: 14px;
|
||||
color: @black;
|
||||
margin-left: 10px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
small {
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
</div>
|
||||
|
||||
<div class="text-center" ng-if="(availableItems | compareArrays:selectedItems:'alias').length === 0">
|
||||
<small><localize key="general_all">Akk</localize> {{itemLabel}}s <localize key="grid_areAdded">are added</localize></small>
|
||||
<small><localize key="general_all">All</localize> {{itemLabel}}s <localize key="grid_areAdded">are added</localize></small>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -94,6 +94,11 @@ function contentCreateController($scope,
|
||||
navigationService.hideDialog(showMenu);
|
||||
};
|
||||
|
||||
$scope.editContentType = function() {
|
||||
$location.path("/settings/documenttypes/edit/" + $scope.contentTypeId).search("view", "permissions");
|
||||
close();
|
||||
}
|
||||
|
||||
$scope.createBlank = createBlank;
|
||||
$scope.createOrSelectBlueprintIfAny = createOrSelectBlueprintIfAny;
|
||||
$scope.createFromBlueprint = createFromBlueprint;
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
<p class="abstract" ng-if="!hasSettingsAccess"><localize key="create_noDocumentTypesWithNoSettingsAccess"/></p>
|
||||
<div ng-if="hasSettingsAccess">
|
||||
<p class="abstract"><localize key="create_noDocumentTypes" /></p>
|
||||
<button class="btn umb-outline" href="#settings/documentTypes/edit/{{contentTypeId}}?view=permissions" ng-click="close()">
|
||||
<button class="btn umb-outline" ng-click="editContentType()">
|
||||
<localize key="create_noDocumentTypesEditPermissions"/>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
<ul class="umb-actions umb-actions-child">
|
||||
<li class="umb-action" ng-repeat="documentType in vm.documentTypes | orderBy:'name':false">
|
||||
<a href="" class="umb-action-link" ng-click="vm.createBlueprint(documentType)" prevent-default>
|
||||
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.createBlueprint(documentType)" prevent-default>
|
||||
<i class="large icon {{documentType.icon}}"></i>
|
||||
<span class="menu-label">
|
||||
{{documentType.name}}
|
||||
@@ -19,7 +19,7 @@
|
||||
{{documentType.description}}
|
||||
</small>
|
||||
</span>
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -6,20 +6,20 @@
|
||||
|
||||
<ul class="umb-actions umb-actions-child">
|
||||
<li data-element="action-data-type" class="umb-action">
|
||||
<a href="" class="umb-action-link" ng-click="createDataType()" umb-auto-focus>
|
||||
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="createDataType()" umb-auto-focus>
|
||||
<i class="large icon icon-autofill"></i>
|
||||
<span class="menu-label">
|
||||
<localize key="create_newDataType">New data type</localize>
|
||||
</span>
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
<li data-element="action-folder" class="umb-action">
|
||||
<a href="" class="umb-action-link" ng-click="showCreateFolder()">
|
||||
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="showCreateFolder()">
|
||||
<i class="large icon icon-folder"></i>
|
||||
<span class="menu-label">
|
||||
<localize key="create_newFolder">New folder</localize>...
|
||||
</span>
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -7,36 +7,36 @@
|
||||
|
||||
<ul class="umb-actions umb-actions-child">
|
||||
<li data-element="action-documentType" class="umb-action" ng-hide="model.disableTemplates">
|
||||
<a href="" ng-click="createDocType()" class="umb-action-link" umb-auto-focus>
|
||||
<button href="" ng-click="createDocType()" class="umb-action-link umb-outline btn-reset" umb-auto-focus>
|
||||
<i class="large icon icon-item-arrangement"></i>
|
||||
<span class="menu-label">
|
||||
<localize key="content_documentType">Document type</localize>
|
||||
</span>
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
<li data-element="action-documentTypeWithoutTemplate" class="umb-action">
|
||||
<a href="" ng-click="createComponent()" class="umb-action-link">
|
||||
<button href="" ng-click="createComponent()" class="umb-action-link umb-outline btn-reset">
|
||||
<i class="large icon icon-item-arrangement"></i>
|
||||
<span class="menu-label">
|
||||
<localize ng-if="model.disableTemplates === false" key="create_documentTypeWithoutTemplate"></localize>
|
||||
<localize ng-if="model.disableTemplates === true" key="content_documentType">Document type></localize>
|
||||
</span>
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
<li data-element="action-documentTypeCollection" class="umb-action">
|
||||
<a href="" ng-click="showCreateDocTypeCollection()" class="umb-action-link">
|
||||
<button href="" ng-click="showCreateDocTypeCollection()" class="umb-action-link umb-outline btn-reset">
|
||||
<i class="large icon icon-thumbnail-list"></i>
|
||||
<span class="menu-label">
|
||||
Document Type Collection...
|
||||
<!-- <localize key="content_documentType_collection">Document Type Collection</localize>-->
|
||||
</span>
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
<li data-element="action-folder" ng-if="model.allowCreateFolder" class="umb-action">
|
||||
<a href="" ng-click="showCreateFolder()" class="umb-action-link">
|
||||
<button href="" ng-click="showCreateFolder()" class="umb-action-link umb-outline btn-reset">
|
||||
<i class="large icon icon-folder"></i>
|
||||
<span class="menu-label"><localize key="general_folder"></localize>...</span>
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -17,13 +17,13 @@
|
||||
<ul class="umb-actions umb-actions-child">
|
||||
|
||||
<li data-element="action-{{docType.alias}}" class="umb-action" ng-repeat="docType in allowedTypes">
|
||||
<a ng-href="" ng-click="createMediaItem(docType)" class="umb-action-link" prevent-default>
|
||||
<button ng-click="createMediaItem(docType)" class="umb-action-link umb-outline btn-reset" prevent-default>
|
||||
<i class="large icon {{docType.icon}}"></i>
|
||||
<span class="menu-label">
|
||||
{{docType.name}}
|
||||
<small>{{docType.description}}</small>
|
||||
</span>
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
<!--
|
||||
<li class="add">
|
||||
|
||||
@@ -7,19 +7,19 @@
|
||||
|
||||
<ul class="umb-actions umb-actions-child">
|
||||
<li class="umb-action">
|
||||
<a href="" class="umb-action-link" ng-click="createMediaType()" umb-auto-focus>
|
||||
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="createMediaType()" umb-auto-focus>
|
||||
<i class="large icon icon-item-arrangement"></i>
|
||||
<span class="menu-label">
|
||||
<localize key="general_new">New</localize>
|
||||
<localize key="content_mediatype">Media type</localize>
|
||||
</span>
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
<li class="umb-action">
|
||||
<a href="" class="umb-action-link" ng-click="showCreateFolder()">
|
||||
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="showCreateFolder()">
|
||||
<i class="large icon icon-folder"></i>
|
||||
<span class="menu-label"><localize key="general_folder"></localize>...</span>
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -6,13 +6,13 @@
|
||||
<ul class="umb-actions umb-actions-child">
|
||||
|
||||
<li class="umb-action" ng-repeat="docType in allowedTypes">
|
||||
<a class="umb-action-link" href="#member/member/edit/{{currentNode.id}}?doctype={{docType.alias}}&create=true" ng-click="hideActions()">
|
||||
<button class="umb-action-link umb-outline btn-reset" href="#member/member/edit/{{currentNode.id}}?doctype={{docType.alias}}&create=true" ng-click="hideActions()">
|
||||
<i class="large icon {{docType.icon}}"></i>
|
||||
<span class="menu-label">
|
||||
{{docType.name}}
|
||||
<small>{{docType.description}}</small>
|
||||
</span>
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -5,13 +5,13 @@
|
||||
|
||||
<ul class="umb-actions umb-actions-child">
|
||||
<li class="umb-action">
|
||||
<a href="" class="umb-action-link" ng-click="showCreateFolder()">
|
||||
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="showCreateFolder()">
|
||||
<i class="large icon icon-folder"></i>
|
||||
<span class="menu-label"><localize key="general_folder"></localize></span>
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
<li class="umb-action">
|
||||
<a href="" class="umb-action-link" ng-click="createMemberType()">
|
||||
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="createMemberType()">
|
||||
|
||||
<i class="large icon icon-item-arrangement"></i>
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<localize key="content_memberType">Member type</localize>
|
||||
</span>
|
||||
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -11,28 +11,28 @@
|
||||
|
||||
<ul class="umb-actions umb-actions-child">
|
||||
<li class="umb-action">
|
||||
<a href="" class="umb-action-link" ng-click="vm.createFile()" umb-auto-focus>
|
||||
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.createFile()" umb-auto-focus>
|
||||
<i class="large icon-article"></i>
|
||||
<span class="menu-label"><localize key="create_newPartialViewMacro">New partial view macro</localize></span>
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
<li class="umb-action">
|
||||
<a href="" class="umb-action-link" ng-click="vm.createFileWithoutMacro()">
|
||||
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.createFileWithoutMacro()">
|
||||
<i class="large icon icon-article"></i>
|
||||
<span class="menu-label"><localize key="create_newPartialViewMacroNoMacro">New partial view macro (without macro)</localize></span>
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
<li class="umb-action">
|
||||
<a href="" class="umb-action-link" ng-click="vm.showCreateFromSnippet()">
|
||||
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.showCreateFromSnippet()">
|
||||
<i class="large icon icon-article"></i>
|
||||
<span class="menu-label"><localize key="create_newPartialViewMacroFromSnippet">>New partial view macro from snippet</localize>...</span>
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
<li class="umb-action">
|
||||
<a href="" class="umb-action-link" ng-click="vm.showCreateFolder()">
|
||||
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.showCreateFolder()">
|
||||
<i class="large icon icon-folder"></i>
|
||||
<span class="menu-label"><localize key="general_folder"></localize>...</span>
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -44,10 +44,10 @@
|
||||
|
||||
<ul class="umb-actions umb-actions-child">
|
||||
<li class="umb-action" ng-repeat="snippet in vm.snippets">
|
||||
<a href="" class="umb-action-link" ng-click="vm.createFileFromSnippet(snippet)" style="padding-top: 6px; padding-bottom: 6px;">
|
||||
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.createFileFromSnippet(snippet)" style="padding-top: 6px; padding-bottom: 6px;">
|
||||
<i class="icon-article icon" style="font-size: 20px;"></i>
|
||||
<span class="menu-label" style="margin-left: 0; padding-left: 5px;">{{ snippet.name }}</span>
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -10,22 +10,22 @@
|
||||
<div ng-if="!vm.showSnippets">
|
||||
<ul class="umb-actions umb-actions-child">
|
||||
<li class="umb-action">
|
||||
<a href="" class="umb-action-link" ng-click="vm.createPartialView()" umb-auto-focus>
|
||||
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.createPartialView()" umb-auto-focus>
|
||||
<i class="large icon icon-article"></i>
|
||||
<span class="menu-label"><localize key="create_newEmptyPartialView">New empty partial view</localize></span>
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
<li class="umb-action">
|
||||
<a href="" class="umb-action-link" ng-click="vm.showCreateFromSnippet()">
|
||||
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.showCreateFromSnippet()">
|
||||
<i class="large icon icon-article"></i>
|
||||
<span class="menu-label"><localize key="create_newPartialViewFromSnippet">New partial view from snippet</localize>...</span>
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
<li class="umb-action">
|
||||
<a href="" class="umb-action-link" ng-click="vm.showCreateFolder()">
|
||||
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.showCreateFolder()">
|
||||
<i class="large icon icon-folder"></i>
|
||||
<span class="menu-label"><localize key="general_folder"></localize>...</span>
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -34,10 +34,10 @@
|
||||
<div ng-if="vm.showSnippets">
|
||||
<ul class="umb-actions umb-actions-child">
|
||||
<li class="umb-action" ng-repeat="snippet in vm.snippets">
|
||||
<a href="" class="umb-action-link" ng-click="vm.createPartialView(snippet)" style="padding-top: 6px; padding-bottom: 6px;">
|
||||
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.createPartialView(snippet)" style="padding-top: 6px; padding-bottom: 6px;">
|
||||
<i class="icon-article icon" style="font-size: 20px;"></i>
|
||||
<span class="menu-label" style="margin-left: 0; padding-left: 5px;">{{ snippet.name }}</span>
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
//TODO: What is this file? Is it used?? I don't think so
|
||||
var uSkyGridConfig = [
|
||||
{
|
||||
|
||||
|
||||
+1
-1
@@ -229,7 +229,7 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
|
||||
|
||||
|
||||
$scope.sortableOptions = {
|
||||
disabled: !$scope.isMultiPicker,
|
||||
disabled: !multiPicker,
|
||||
items: "li:not(.add-wrapper)",
|
||||
cancel: ".unsortable",
|
||||
update: function (e, ui) {
|
||||
|
||||
@@ -7,16 +7,16 @@
|
||||
|
||||
<ul class="umb-actions umb-actions-child">
|
||||
<li class="umb-action">
|
||||
<a href="" class="umb-action-link" umb-auto-focus ng-click="vm.createFile()">
|
||||
<button href="" class="umb-action-link umb-outline btn-reset" umb-auto-focus ng-click="vm.createFile()">
|
||||
<i class="large icon icon-script"></i>
|
||||
<span class="menu-label"><localize key="create_newJavascriptFile">New javascript file</localize></span>
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
<li class="umb-action">
|
||||
<a href="" class="umb-action-link" ng-click="vm.showCreateFolder()">
|
||||
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.showCreateFolder()">
|
||||
<i class="large icon icon-folder"></i>
|
||||
<span class="menu-label"><localize key="general_folder"></localize>...</span>
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -7,22 +7,22 @@
|
||||
|
||||
<ul class="umb-actions umb-actions-child">
|
||||
<li class="umb-action">
|
||||
<a href="" class="umb-action-link" umb-auto-focus ng-click="vm.createFile()">
|
||||
<button href="" class="umb-action-link umb-outline btn-reset" umb-auto-focus ng-click="vm.createFile()">
|
||||
<i class="large icon icon-script"></i>
|
||||
<span class="menu-label"><localize key="create_newStyleSheetFile">New style sheet file</localize></span>
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
<li class="umb-action">
|
||||
<a href="" ng-click="vm.createRichtextStyle()" class="umb-action-link">
|
||||
<button href="" ng-click="vm.createRichtextStyle()" class="umb-action-link umb-outline btn-reset">
|
||||
<i class="large icon icon-script"></i>
|
||||
<span class="menu-label"><localize key="create_newRteStyleSheetFile">New richtext style sheet file</localize></span>
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
<li class="umb-action">
|
||||
<a href="" class="umb-action-link" ng-click="vm.showCreateFolder()">
|
||||
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.showCreateFolder()">
|
||||
<i class="large icon icon-folder"></i>
|
||||
<span class="menu-label"><localize key="general_folder"></localize>...</span>
|
||||
</a>
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
@@ -90,6 +90,7 @@
|
||||
ng-repeat="node in model.user.startContentIds"
|
||||
icon="node.icon"
|
||||
name="node.name"
|
||||
allow-remove="true"
|
||||
on-remove="model.removeSelectedItem($index, model.user.startContentIds)">
|
||||
</umb-node-preview>
|
||||
|
||||
@@ -114,6 +115,7 @@
|
||||
ng-repeat="node in model.user.startMediaIds"
|
||||
icon="node.icon"
|
||||
name="node.name"
|
||||
allow-remove="true"
|
||||
on-remove="model.removeSelectedItem($index, model.user.startMediaIds)">
|
||||
</umb-node-preview>
|
||||
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
|
||||
/**
|
||||
* @ngdoc controller
|
||||
* @name Umbraco.MainController
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* The main application controller
|
||||
*
|
||||
*/
|
||||
function MainController($scope, $location, appState, treeService, notificationsService,
|
||||
userService, historyService, updateChecker, navigationService, eventsService,
|
||||
tmhDynamicLocale, localStorageService, editorService, overlayService) {
|
||||
|
||||
//the null is important because we do an explicit bool check on this in the view
|
||||
$scope.authenticated = null;
|
||||
$scope.touchDevice = appState.getGlobalState("touchDevice");
|
||||
$scope.infiniteMode = false;
|
||||
$scope.overlay = {};
|
||||
$scope.drawer = {};
|
||||
$scope.search = {};
|
||||
$scope.login = {};
|
||||
$scope.tabbingActive = false;
|
||||
|
||||
// There are a number of ways to detect when a focus state should be shown when using the tab key and this seems to be the simplest solution.
|
||||
// For more information about this approach, see https://hackernoon.com/removing-that-ugly-focus-ring-and-keeping-it-too-6c8727fefcd2
|
||||
function handleFirstTab(evt) {
|
||||
if (evt.keyCode === 9) {
|
||||
$scope.tabbingActive = true;
|
||||
$scope.$digest();
|
||||
window.removeEventListener('keydown', handleFirstTab);
|
||||
window.addEventListener('mousedown', disableTabbingActive);
|
||||
}
|
||||
}
|
||||
|
||||
function disableTabbingActive(evt) {
|
||||
$scope.tabbingActive = false;
|
||||
$scope.$digest();
|
||||
window.removeEventListener('mousedown', disableTabbingActive);
|
||||
window.addEventListener("keydown", handleFirstTab);
|
||||
}
|
||||
|
||||
window.addEventListener("keydown", handleFirstTab);
|
||||
|
||||
|
||||
$scope.removeNotification = function (index) {
|
||||
notificationsService.remove(index);
|
||||
};
|
||||
|
||||
$scope.closeSearch = function() {
|
||||
appState.setSearchState("show", false);
|
||||
};
|
||||
|
||||
$scope.showLoginScreen = function(isTimedOut) {
|
||||
$scope.login.isTimedOut = isTimedOut;
|
||||
$scope.login.show = true;
|
||||
};
|
||||
|
||||
$scope.hideLoginScreen = function() {
|
||||
$scope.login.show = false;
|
||||
};
|
||||
|
||||
var evts = [];
|
||||
|
||||
//when a user logs out or timesout
|
||||
evts.push(eventsService.on("app.notAuthenticated", function (evt, data) {
|
||||
$scope.authenticated = null;
|
||||
$scope.user = null;
|
||||
const isTimedOut = data && data.isTimedOut ? true : false;
|
||||
$scope.showLoginScreen(isTimedOut);
|
||||
}));
|
||||
|
||||
evts.push(eventsService.on("app.userRefresh", function(evt) {
|
||||
userService.refreshCurrentUser().then(function(data) {
|
||||
$scope.user = data;
|
||||
|
||||
//Load locale file
|
||||
if ($scope.user.locale) {
|
||||
tmhDynamicLocale.set($scope.user.locale);
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
//when the app is ready/user is logged in, setup the data
|
||||
evts.push(eventsService.on("app.ready", function (evt, data) {
|
||||
|
||||
$scope.authenticated = data.authenticated;
|
||||
$scope.user = data.user;
|
||||
|
||||
updateChecker.check().then(function (update) {
|
||||
if (update && update !== "null") {
|
||||
if (update.type !== "None") {
|
||||
var notification = {
|
||||
headline: "Update available",
|
||||
message: "Click to download",
|
||||
sticky: true,
|
||||
type: "info",
|
||||
url: update.url
|
||||
};
|
||||
notificationsService.add(notification);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
//if the user has changed we need to redirect to the root so they don't try to continue editing the
|
||||
//last item in the URL (NOTE: the user id can equal zero, so we cannot just do !data.lastUserId since that will resolve to true)
|
||||
if (data.lastUserId !== undefined && data.lastUserId !== null && data.lastUserId !== data.user.id) {
|
||||
|
||||
var section = appState.getSectionState("currentSection");
|
||||
if (section) {
|
||||
//if there's a section already assigned, reload it so the tree is cleared
|
||||
navigationService.reloadSection(section);
|
||||
}
|
||||
|
||||
$location.path("/").search("");
|
||||
historyService.removeAll();
|
||||
treeService.clearCache();
|
||||
editorService.closeAll();
|
||||
overlayService.close();
|
||||
|
||||
//if the user changed, clearout local storage too - could contain sensitive data
|
||||
localStorageService.clearAll();
|
||||
}
|
||||
|
||||
//if this is a new login (i.e. the user entered credentials), then clear out local storage - could contain sensitive data
|
||||
if (data.loginType === "credentials") {
|
||||
localStorageService.clearAll();
|
||||
}
|
||||
|
||||
//Load locale file
|
||||
if ($scope.user.locale) {
|
||||
tmhDynamicLocale.set($scope.user.locale);
|
||||
}
|
||||
|
||||
}));
|
||||
|
||||
// events for search
|
||||
evts.push(eventsService.on("appState.searchState.changed", function (e, args) {
|
||||
if (args.key === "show") {
|
||||
$scope.search.show = args.value;
|
||||
}
|
||||
}));
|
||||
|
||||
// events for drawer
|
||||
// manage the help dialog by subscribing to the showHelp appState
|
||||
evts.push(eventsService.on("appState.drawerState.changed", function (e, args) {
|
||||
// set view
|
||||
if (args.key === "view") {
|
||||
$scope.drawer.view = args.value;
|
||||
}
|
||||
// set custom model
|
||||
if (args.key === "model") {
|
||||
$scope.drawer.model = args.value;
|
||||
}
|
||||
// show / hide drawer
|
||||
if (args.key === "showDrawer") {
|
||||
$scope.drawer.show = args.value;
|
||||
}
|
||||
}));
|
||||
|
||||
// events for overlays
|
||||
evts.push(eventsService.on("appState.overlay", function (name, args) {
|
||||
$scope.overlay = args;
|
||||
}));
|
||||
|
||||
// events for tours
|
||||
evts.push(eventsService.on("appState.tour.start", function (name, args) {
|
||||
$scope.tour = args;
|
||||
$scope.tour.show = true;
|
||||
}));
|
||||
|
||||
evts.push(eventsService.on("appState.tour.end", function () {
|
||||
$scope.tour = null;
|
||||
}));
|
||||
|
||||
evts.push(eventsService.on("appState.tour.complete", function () {
|
||||
$scope.tour = null;
|
||||
}));
|
||||
|
||||
// events for backdrop
|
||||
evts.push(eventsService.on("appState.backdrop", function (name, args) {
|
||||
$scope.backdrop = args;
|
||||
}));
|
||||
|
||||
// event for infinite editors
|
||||
evts.push(eventsService.on("appState.editors.open", function (name, args) {
|
||||
$scope.infiniteMode = args && args.editors.length > 0 ? true : false;
|
||||
}));
|
||||
|
||||
evts.push(eventsService.on("appState.editors.close", function (name, args) {
|
||||
$scope.infiniteMode = args && args.editors.length > 0 ? true : false;
|
||||
}));
|
||||
|
||||
//ensure to unregister from all events!
|
||||
$scope.$on('$destroy', function () {
|
||||
for (var e in evts) {
|
||||
eventsService.unsubscribe(evts[e]);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
//register it
|
||||
angular.module('umbraco').controller("Umbraco.MainController", MainController).
|
||||
config(function (tmhDynamicLocaleProvider) {
|
||||
//Set url for locale files
|
||||
tmhDynamicLocaleProvider.localeLocationPattern('lib/angular-i18n/angular-locale_{{locale}}.js');
|
||||
});
|
||||
@@ -0,0 +1,517 @@
|
||||
|
||||
/**
|
||||
* @ngdoc controller
|
||||
* @name Umbraco.NavigationController
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* Handles the section area of the app
|
||||
*
|
||||
* @param {navigationService} navigationService A reference to the navigationService
|
||||
*/
|
||||
function NavigationController($scope, $rootScope, $location, $log, $q, $routeParams, $timeout, $cookies, treeService, appState, navigationService, keyboardService, historyService, eventsService, angularHelper, languageResource, contentResource, editorState) {
|
||||
|
||||
//this is used to trigger the tree to start loading once everything is ready
|
||||
var treeInitPromise = $q.defer();
|
||||
|
||||
$scope.treeApi = {};
|
||||
|
||||
//Bind to the main tree events
|
||||
$scope.onTreeInit = function () {
|
||||
|
||||
$scope.treeApi.callbacks.treeNodeExpanded(nodeExpandedHandler);
|
||||
|
||||
//when a tree is loaded into a section, we need to put it into appState
|
||||
$scope.treeApi.callbacks.treeLoaded(function (args) {
|
||||
appState.setTreeState("currentRootNode", args.tree);
|
||||
});
|
||||
|
||||
//when a tree node is synced this event will fire, this allows us to set the currentNode
|
||||
$scope.treeApi.callbacks.treeSynced(function (args) {
|
||||
|
||||
if (args.activate === undefined || args.activate === true) {
|
||||
//set the current selected node
|
||||
appState.setTreeState("selectedNode", args.node);
|
||||
//when a node is activated, this is the same as clicking it and we need to set the
|
||||
//current menu item to be this node as well.
|
||||
//appState.setMenuState("currentNode", args.node);// Niels: No, we are setting it from the dialog.
|
||||
}
|
||||
});
|
||||
|
||||
//this reacts to the options item in the tree
|
||||
$scope.treeApi.callbacks.treeOptionsClick(function (args) {
|
||||
args.event.stopPropagation();
|
||||
args.event.preventDefault();
|
||||
|
||||
//Set the current action node (this is not the same as the current selected node!)
|
||||
//appState.setMenuState("currentNode", args.node);// Niels: No, we are setting it from the dialog.
|
||||
|
||||
if (args.event && args.event.altKey) {
|
||||
args.skipDefault = true;
|
||||
}
|
||||
|
||||
navigationService.showMenu(args);
|
||||
});
|
||||
|
||||
$scope.treeApi.callbacks.treeNodeAltSelect(function (args) {
|
||||
args.event.stopPropagation();
|
||||
args.event.preventDefault();
|
||||
|
||||
args.skipDefault = true;
|
||||
navigationService.showMenu(args);
|
||||
});
|
||||
|
||||
//this reacts to tree items themselves being clicked
|
||||
//the tree directive should not contain any handling, simply just bubble events
|
||||
$scope.treeApi.callbacks.treeNodeSelect(function (args) {
|
||||
var n = args.node;
|
||||
args.event.stopPropagation();
|
||||
args.event.preventDefault();
|
||||
|
||||
if (n.metaData && n.metaData["jsClickCallback"] && angular.isString(n.metaData["jsClickCallback"]) && n.metaData["jsClickCallback"] !== "") {
|
||||
//this is a legacy tree node!
|
||||
var jsPrefix = "javascript:";
|
||||
var js;
|
||||
if (n.metaData["jsClickCallback"].startsWith(jsPrefix)) {
|
||||
js = n.metaData["jsClickCallback"].substr(jsPrefix.length);
|
||||
}
|
||||
else {
|
||||
js = n.metaData["jsClickCallback"];
|
||||
}
|
||||
try {
|
||||
var func = eval(js);
|
||||
//this is normally not necessary since the eval above should execute the method and will return nothing.
|
||||
if (func != null && (typeof func === "function")) {
|
||||
func.call();
|
||||
}
|
||||
}
|
||||
catch (ex) {
|
||||
$log.error("Error evaluating js callback from legacy tree node: " + ex);
|
||||
}
|
||||
}
|
||||
else if (n.routePath) {
|
||||
//add action to the history service
|
||||
historyService.add({ name: n.name, link: n.routePath, icon: n.icon });
|
||||
|
||||
//put this node into the tree state
|
||||
appState.setTreeState("selectedNode", args.node);
|
||||
//when a node is clicked we also need to set the active menu node to this node
|
||||
//appState.setMenuState("currentNode", args.node);
|
||||
|
||||
//not legacy, lets just set the route value and clear the query string if there is one.
|
||||
$location.path(n.routePath);
|
||||
navigationService.clearSearch();
|
||||
}
|
||||
else if (n.section) {
|
||||
$location.path(n.section);
|
||||
navigationService.clearSearch();
|
||||
}
|
||||
|
||||
navigationService.hideNavigation();
|
||||
});
|
||||
|
||||
return treeInitPromise.promise;
|
||||
}
|
||||
|
||||
//set up our scope vars
|
||||
$scope.showContextMenuDialog = false;
|
||||
$scope.showContextMenu = false;
|
||||
$scope.showSearchResults = false;
|
||||
$scope.menuDialogTitle = null;
|
||||
$scope.menuActions = [];
|
||||
$scope.menuNode = null;
|
||||
$scope.languages = [];
|
||||
$scope.selectedLanguage = {};
|
||||
$scope.page = {};
|
||||
$scope.page.languageSelectorIsOpen = false;
|
||||
|
||||
$scope.currentSection = null;
|
||||
$scope.customTreeParams = null;
|
||||
$scope.treeCacheKey = "_";
|
||||
$scope.showNavigation = appState.getGlobalState("showNavigation");
|
||||
// tracks all expanded paths so when the language is switched we can resync it with the already loaded paths
|
||||
var expandedPaths = [];
|
||||
|
||||
//trigger search with a hotkey:
|
||||
keyboardService.bind("ctrl+shift+s", function () {
|
||||
navigationService.showSearch();
|
||||
});
|
||||
|
||||
//// TODO: remove this it's not a thing
|
||||
//$scope.selectedId = navigationService.currentId;
|
||||
|
||||
var isInit = false;
|
||||
var evts = [];
|
||||
|
||||
//Listen for global state changes
|
||||
evts.push(eventsService.on("appState.globalState.changed", function (e, args) {
|
||||
if (args.key === "showNavigation") {
|
||||
$scope.showNavigation = args.value;
|
||||
}
|
||||
}));
|
||||
|
||||
//Listen for menu state changes
|
||||
evts.push(eventsService.on("appState.menuState.changed", function (e, args) {
|
||||
if (args.key === "showMenuDialog") {
|
||||
$scope.showContextMenuDialog = args.value;
|
||||
}
|
||||
if (args.key === "dialogTemplateUrl") {
|
||||
$scope.dialogTemplateUrl = args.value;
|
||||
}
|
||||
if (args.key === "showMenu") {
|
||||
$scope.showContextMenu = args.value;
|
||||
}
|
||||
if (args.key === "dialogTitle") {
|
||||
$scope.menuDialogTitle = args.value;
|
||||
}
|
||||
if (args.key === "menuActions") {
|
||||
$scope.menuActions = args.value;
|
||||
}
|
||||
if (args.key === "currentNode") {
|
||||
$scope.menuNode = args.value;
|
||||
}
|
||||
}));
|
||||
|
||||
//Listen for tree state changes
|
||||
evts.push(eventsService.on("appState.treeState.changed", function (e, args) {
|
||||
if (args.key === "currentRootNode") {
|
||||
|
||||
//if the changed state is the currentRootNode, determine if this is a full screen app
|
||||
if (args.value.root && args.value.root.containsTrees === false) {
|
||||
$rootScope.emptySection = true;
|
||||
}
|
||||
else {
|
||||
$rootScope.emptySection = false;
|
||||
}
|
||||
}
|
||||
|
||||
}));
|
||||
|
||||
//Listen for section state changes
|
||||
evts.push(eventsService.on("appState.sectionState.changed", function (e, args) {
|
||||
|
||||
//section changed
|
||||
if (args.key === "currentSection" && $scope.currentSection != args.value) {
|
||||
//before loading the main tree we need to ensure that the nav is ready
|
||||
navigationService.waitForNavReady().then(() => {
|
||||
$scope.currentSection = args.value;
|
||||
//load the tree
|
||||
configureTreeAndLanguages();
|
||||
$scope.treeApi.load({ section: $scope.currentSection, customTreeParams: $scope.customTreeParams, cacheKey: $scope.treeCacheKey });
|
||||
});
|
||||
}
|
||||
|
||||
//show/hide search results
|
||||
if (args.key === "showSearchResults") {
|
||||
$scope.showSearchResults = args.value;
|
||||
}
|
||||
|
||||
}));
|
||||
|
||||
// Listen for language updates
|
||||
evts.push(eventsService.on("editors.languages.languageDeleted", function (e, args) {
|
||||
loadLanguages().then(function (languages) {
|
||||
$scope.languages = languages;
|
||||
});
|
||||
}));
|
||||
|
||||
//Emitted when a language is created or an existing one saved/edited
|
||||
evts.push(eventsService.on("editors.languages.languageSaved", function (e, args) {
|
||||
if(args.isNew){
|
||||
//A new language has been created - reload languages for tree
|
||||
loadLanguages().then(function (languages) {
|
||||
$scope.languages = languages;
|
||||
});
|
||||
}
|
||||
else if(args.language.isDefault){
|
||||
//A language was saved and was set to be the new default (refresh the tree, so its at the top)
|
||||
loadLanguages().then(function (languages) {
|
||||
$scope.languages = languages;
|
||||
});
|
||||
}
|
||||
}));
|
||||
|
||||
//when a user logs out or timesout
|
||||
evts.push(eventsService.on("app.notAuthenticated", function () {
|
||||
$scope.authenticated = false;
|
||||
}));
|
||||
|
||||
//when the application is ready and the user is authorized, setup the data
|
||||
//this will occur anytime a new user logs in!
|
||||
evts.push(eventsService.on("app.ready", function (evt, data) {
|
||||
$scope.authenticated = true;
|
||||
ensureInit();
|
||||
}));
|
||||
|
||||
// event for infinite editors
|
||||
evts.push(eventsService.on("appState.editors.open", function (name, args) {
|
||||
$scope.infiniteMode = args && args.editors.length > 0 ? true : false;
|
||||
}));
|
||||
|
||||
evts.push(eventsService.on("appState.editors.close", function (name, args) {
|
||||
$scope.infiniteMode = args && args.editors.length > 0 ? true : false;
|
||||
}));
|
||||
|
||||
evts.push(eventsService.on("treeService.removeNode", function (e, args) {
|
||||
//check to see if the current page has been removed
|
||||
|
||||
var currentEditorState = editorState.getCurrent()
|
||||
if (currentEditorState && currentEditorState.id.toString() === args.node.id.toString()) {
|
||||
//current page is loaded, so navigate to root
|
||||
var section = appState.getSectionState("currentSection");
|
||||
$location.path("/" + section);
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Based on the current state of the application, this configures the scope variables that control the main tree and language drop down
|
||||
*/
|
||||
function configureTreeAndLanguages() {
|
||||
|
||||
//create the custom query string param for this tree, this is currently only relevant for content
|
||||
if ($scope.currentSection === "content") {
|
||||
|
||||
//must use $location here because $routeParams isn't available until after the route change
|
||||
var mainCulture = $location.search().mculture;
|
||||
//select the current language if set in the query string
|
||||
if (mainCulture && $scope.languages && $scope.languages.length > 1) {
|
||||
var found = _.find($scope.languages, function (l) {
|
||||
return l.culture.toLowerCase() === mainCulture.toLowerCase();
|
||||
});
|
||||
if (found) {
|
||||
//set the route param
|
||||
found.active = true;
|
||||
$scope.selectedLanguage = found;
|
||||
}
|
||||
}
|
||||
|
||||
var queryParams = {};
|
||||
if ($scope.selectedLanguage && $scope.selectedLanguage.culture) {
|
||||
queryParams["culture"] = $scope.selectedLanguage.culture;
|
||||
}
|
||||
var queryString = $.param(queryParams); //create the query string from the params object
|
||||
}
|
||||
|
||||
if (queryString) {
|
||||
$scope.customTreeParams = queryString;
|
||||
$scope.treeCacheKey = queryString; // this tree uses caching but we need to change it's cache key per lang
|
||||
}
|
||||
else {
|
||||
$scope.treeCacheKey = "_"; // this tree uses caching, there's no lang selected so use the default
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the app is ready and sets up the navigation (should only be called once)
|
||||
*/
|
||||
function ensureInit() {
|
||||
|
||||
//only run once ever!
|
||||
if (isInit) {
|
||||
return;
|
||||
}
|
||||
|
||||
isInit = true;
|
||||
|
||||
var navInit = false;
|
||||
|
||||
//$routeParams will be populated after $routeChangeSuccess since this controller is used outside ng-view,
|
||||
//* we listen for the first route change with a section to setup the navigation.
|
||||
//* we listen for all route changes to track the current section.
|
||||
$rootScope.$on('$routeChangeSuccess', function () {
|
||||
|
||||
//only continue if there's a section available
|
||||
if ($routeParams.section) {
|
||||
|
||||
if (!navInit) {
|
||||
navInit = true;
|
||||
initNav();
|
||||
}
|
||||
|
||||
//keep track of the current section when it changes
|
||||
if ($scope.currentSection != $routeParams.section) {
|
||||
appState.setSectionState("currentSection", $routeParams.section);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* This loads the language data, if the are no variant content types configured this will return no languages
|
||||
*/
|
||||
function loadLanguages() {
|
||||
|
||||
return contentResource.allowsCultureVariation().then(function (b) {
|
||||
if (b === true) {
|
||||
return languageResource.getAll()
|
||||
} else {
|
||||
return $q.when([]); //resolve an empty collection
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Called once during init to initialize the navigation/tree/languages
|
||||
*/
|
||||
function initNav() {
|
||||
// load languages
|
||||
loadLanguages().then(function (languages) {
|
||||
|
||||
$scope.languages = languages;
|
||||
|
||||
if ($scope.languages.length > 1) {
|
||||
//if there's already one set, check if it exists
|
||||
var currCulture = null;
|
||||
var mainCulture = $location.search().mculture;
|
||||
if (mainCulture) {
|
||||
currCulture = _.find($scope.languages, function (l) {
|
||||
return l.culture.toLowerCase() === mainCulture.toLowerCase();
|
||||
});
|
||||
}
|
||||
if (!currCulture) {
|
||||
// no culture in the request, let's look for one in the cookie that's set when changing language
|
||||
var defaultCulture = $cookies.get("UMB_MCULTURE");
|
||||
if (!defaultCulture || !_.find($scope.languages, function (l) {
|
||||
return l.culture.toLowerCase() === defaultCulture.toLowerCase();
|
||||
})) {
|
||||
// no luck either, look for the default language
|
||||
var defaultLang = _.find($scope.languages, function (l) {
|
||||
return l.isDefault;
|
||||
});
|
||||
if (defaultLang) {
|
||||
defaultCulture = defaultLang.culture;
|
||||
}
|
||||
}
|
||||
$location.search("mculture", defaultCulture ? defaultCulture : null);
|
||||
}
|
||||
}
|
||||
|
||||
$scope.currentSection = $routeParams.section;
|
||||
|
||||
configureTreeAndLanguages();
|
||||
|
||||
//resolve the tree promise, set it's property values for loading the tree which will make the tree load
|
||||
treeInitPromise.resolve({
|
||||
section: $scope.currentSection,
|
||||
customTreeParams: $scope.customTreeParams,
|
||||
cacheKey: $scope.treeCacheKey,
|
||||
|
||||
//because angular doesn't return a promise for the resolve method, we need to resort to some hackery, else
|
||||
//like normal JS promises we could do resolve(...).then()
|
||||
onLoaded: function () {
|
||||
|
||||
//the nav is ready, let the app know
|
||||
eventsService.emit("app.navigationReady", { treeApi: $scope.treeApi });
|
||||
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
function nodeExpandedHandler(args) {
|
||||
//store the reference to the expanded node path
|
||||
if (args.node) {
|
||||
treeService._trackExpandedPaths(args.node, expandedPaths);
|
||||
}
|
||||
}
|
||||
|
||||
$scope.selectLanguage = function (language) {
|
||||
|
||||
$location.search("mculture", language.culture);
|
||||
// add the selected culture to a cookie so the user will log back into the same culture later on (cookie lifetime = one year)
|
||||
var expireDate = new Date();
|
||||
expireDate.setDate(expireDate.getDate() + 365);
|
||||
$cookies.put("UMB_MCULTURE", language.culture, {path: "/", expires: expireDate});
|
||||
|
||||
// close the language selector
|
||||
$scope.page.languageSelectorIsOpen = false;
|
||||
|
||||
configureTreeAndLanguages(); //re-bind language to the query string and update the tree params
|
||||
|
||||
//reload the tree with it's updated querystring args
|
||||
$scope.treeApi.load({ section: $scope.currentSection, customTreeParams: $scope.customTreeParams, cacheKey: $scope.treeCacheKey }).then(function () {
|
||||
|
||||
//re-sync to currently edited node
|
||||
var currNode = appState.getTreeState("selectedNode");
|
||||
//create the list of promises
|
||||
var promises = [];
|
||||
//starting with syncing to the currently selected node if there is one
|
||||
if (currNode) {
|
||||
var path = treeService.getPath(currNode);
|
||||
promises.push($scope.treeApi.syncTree({ path: path, activate: true }));
|
||||
}
|
||||
// TODO: If we want to keep all paths expanded ... but we need more testing since we need to deal with unexpanding
|
||||
//for (var i = 0; i < expandedPaths.length; i++) {
|
||||
// promises.push($scope.treeApi.syncTree({ path: expandedPaths[i], activate: false, forceReload: true }));
|
||||
//}
|
||||
//execute them sequentially
|
||||
|
||||
// set selected language to active
|
||||
angular.forEach($scope.languages, function(language){
|
||||
language.active = false;
|
||||
});
|
||||
language.active = true;
|
||||
|
||||
angularHelper.executeSequentialPromises(promises);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
//this reacts to the options item in the tree
|
||||
// TODO: migrate to nav service
|
||||
// TODO: is this used?
|
||||
$scope.searchShowMenu = function (ev, args) {
|
||||
//always skip default
|
||||
args.skipDefault = true;
|
||||
navigationService.showMenu(args);
|
||||
};
|
||||
|
||||
// TODO: migrate to nav service
|
||||
// TODO: is this used?
|
||||
$scope.searchHide = function () {
|
||||
navigationService.hideSearch();
|
||||
};
|
||||
|
||||
//the below assists with hiding/showing the tree
|
||||
var treeActive = false;
|
||||
|
||||
//Sets a service variable as soon as the user hovers the navigation with the mouse
|
||||
//used by the leaveTree method to delay hiding
|
||||
$scope.enterTree = function (event) {
|
||||
treeActive = true;
|
||||
};
|
||||
|
||||
// Hides navigation tree, with a short delay, is cancelled if the user moves the mouse over the tree again
|
||||
$scope.leaveTree = function (event) {
|
||||
//this is a hack to handle IE touch events which freaks out due to no mouse events so the tree instantly shuts down
|
||||
if (!event) {
|
||||
return;
|
||||
}
|
||||
if (!appState.getGlobalState("touchDevice")) {
|
||||
treeActive = false;
|
||||
$timeout(function () {
|
||||
if (!treeActive) {
|
||||
navigationService.hideTree();
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.toggleLanguageSelector = function () {
|
||||
$scope.page.languageSelectorIsOpen = !$scope.page.languageSelectorIsOpen;
|
||||
};
|
||||
|
||||
//ensure to unregister from all events!
|
||||
$scope.$on('$destroy', function () {
|
||||
for (var e in evts) {
|
||||
eventsService.unsubscribe(evts[e]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//register it
|
||||
angular.module('umbraco').controller("Umbraco.NavigationController", NavigationController);
|
||||
@@ -301,7 +301,7 @@ namespace Umbraco.Web.Models.Mapping
|
||||
target.Avatars = source.GetUserAvatarUrls(_appCaches.RuntimeCache);
|
||||
target.Culture = source.GetUserCulture(_textService, _globalSettings).ToString();
|
||||
target.Email = source.Email;
|
||||
target.EmailHash = source.Email.ToLowerInvariant().Trim().ToMd5();
|
||||
target.EmailHash = source.Email.ToLowerInvariant().Trim().GenerateHash();
|
||||
target.Id = source.Id;
|
||||
target.Key = source.Key;
|
||||
target.LastLoginDate = source.LastLoginDate == default ? null : (DateTime?) source.LastLoginDate;
|
||||
|
||||
@@ -8,7 +8,12 @@ namespace Umbraco.Web.PropertyEditors
|
||||
/// <summary>
|
||||
/// A property editor to allow multiple checkbox selection of pre-defined items.
|
||||
/// </summary>
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.CheckBoxList, "Checkbox list", "checkboxlist", Icon="icon-bulleted-list", Group="lists")]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.CheckBoxList,
|
||||
"Checkbox list",
|
||||
"checkboxlist",
|
||||
Icon = "icon-bulleted-list",
|
||||
Group = Constants.PropertyEditors.Groups.Lists)]
|
||||
public class CheckBoxListPropertyEditor : DataEditor
|
||||
{
|
||||
private readonly ILocalizedTextService _textService;
|
||||
|
||||
@@ -4,7 +4,12 @@ using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.ColorPicker, "Color Picker", "colorpicker", Icon="icon-colorpicker", Group="Pickers")]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.ColorPicker,
|
||||
"Color Picker",
|
||||
"colorpicker",
|
||||
Icon = "icon-colorpicker",
|
||||
Group = Constants.PropertyEditors.Groups.Pickers)]
|
||||
public class ColorPickerPropertyEditor : DataEditor
|
||||
{
|
||||
public ColorPickerPropertyEditor(ILogger logger)
|
||||
|
||||
@@ -8,7 +8,13 @@ namespace Umbraco.Web.PropertyEditors
|
||||
/// <summary>
|
||||
/// Content property editor that stores UDI
|
||||
/// </summary>
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.ContentPicker, EditorType.PropertyValue | EditorType.MacroParameter, "Content Picker", "contentpicker", ValueType = ValueTypes.String, Group = "Pickers")]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.ContentPicker,
|
||||
EditorType.PropertyValue | EditorType.MacroParameter,
|
||||
"Content Picker",
|
||||
"contentpicker",
|
||||
ValueType = ValueTypes.String,
|
||||
Group = Constants.PropertyEditors.Groups.Pickers)]
|
||||
public class ContentPickerPropertyEditor : DataEditor
|
||||
{
|
||||
public ContentPickerPropertyEditor(ILogger logger)
|
||||
|
||||
@@ -7,7 +7,12 @@ namespace Umbraco.Web.PropertyEditors
|
||||
/// <summary>
|
||||
/// Represents a date and time property editor.
|
||||
/// </summary>
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.DateTime, "Date/Time", "datepicker", ValueType = ValueTypes.DateTime, Icon="icon-time")]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.DateTime,
|
||||
"Date/Time",
|
||||
"datepicker",
|
||||
ValueType = ValueTypes.DateTime,
|
||||
Icon = "icon-time")]
|
||||
public class DateTimePropertyEditor : DataEditor
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -8,7 +8,12 @@ namespace Umbraco.Web.PropertyEditors
|
||||
/// <summary>
|
||||
/// Represents a decimal property and parameter editor.
|
||||
/// </summary>
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.Decimal, EditorType.PropertyValue | EditorType.MacroParameter, "Decimal", "decimal", ValueType = ValueTypes.Decimal)]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.Decimal,
|
||||
EditorType.PropertyValue | EditorType.MacroParameter,
|
||||
"Decimal",
|
||||
"decimal",
|
||||
ValueType = ValueTypes.Decimal)]
|
||||
public class DecimalPropertyEditor : DataEditor
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -5,7 +5,12 @@ using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.DropDownListFlexible, "Dropdown", "dropdownFlexible", Group = "lists", Icon = "icon-indent")]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.DropDownListFlexible,
|
||||
"Dropdown",
|
||||
"dropdownFlexible",
|
||||
Group = Constants.PropertyEditors.Groups.Lists,
|
||||
Icon = "icon-indent")]
|
||||
public class DropDownFlexiblePropertyEditor : DataEditor
|
||||
{
|
||||
private readonly ILocalizedTextService _textService;
|
||||
|
||||
@@ -5,7 +5,12 @@ using Umbraco.Core.PropertyEditors.Validators;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.EmailAddress, EditorType.PropertyValue | EditorType.MacroParameter, "Email address", "email", Icon="icon-message")]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.EmailAddress,
|
||||
EditorType.PropertyValue | EditorType.MacroParameter,
|
||||
"Email address",
|
||||
"email",
|
||||
Icon = "icon-message")]
|
||||
public class EmailAddressPropertyEditor : DataEditor
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -12,7 +12,12 @@ using Umbraco.Web.Media;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.UploadField, "File upload", "fileupload", Icon = "icon-download-alt", Group = "media")]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.UploadField,
|
||||
"File upload",
|
||||
"fileupload",
|
||||
Group = Constants.PropertyEditors.Groups.Media,
|
||||
Icon = "icon-download-alt")]
|
||||
public class FileUploadPropertyEditor : DataEditor
|
||||
{
|
||||
private readonly IMediaFileSystem _mediaFileSystem;
|
||||
|
||||
@@ -12,7 +12,14 @@ namespace Umbraco.Web.PropertyEditors
|
||||
/// <summary>
|
||||
/// Represents a grid property and parameter editor.
|
||||
/// </summary>
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.Grid, "Grid layout", "grid", HideLabel = true, ValueType = ValueTypes.Json, Group="rich content", Icon="icon-layout")]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.Grid,
|
||||
"Grid layout",
|
||||
"grid",
|
||||
HideLabel = true,
|
||||
ValueType = ValueTypes.Json,
|
||||
Icon = "icon-layout",
|
||||
Group = Constants.PropertyEditors.Groups.RichContent)]
|
||||
public class GridPropertyEditor : DataEditor
|
||||
{
|
||||
public GridPropertyEditor(ILogger logger)
|
||||
|
||||
@@ -19,7 +19,14 @@ namespace Umbraco.Web.PropertyEditors
|
||||
/// <summary>
|
||||
/// Represents an image cropper property editor.
|
||||
/// </summary>
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.ImageCropper, "Image Cropper", "imagecropper", ValueType = ValueTypes.Json, HideLabel = false, Group="media", Icon="icon-crop")]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.ImageCropper,
|
||||
"Image Cropper",
|
||||
"imagecropper",
|
||||
ValueType = ValueTypes.Json,
|
||||
HideLabel = false,
|
||||
Group = Constants.PropertyEditors.Groups.Media,
|
||||
Icon = "icon-crop")]
|
||||
public class ImageCropperPropertyEditor : DataEditor
|
||||
{
|
||||
private readonly IMediaFileSystem _mediaFileSystem;
|
||||
|
||||
@@ -8,7 +8,12 @@ namespace Umbraco.Web.PropertyEditors
|
||||
/// <summary>
|
||||
/// Represents an integer property and parameter editor.
|
||||
/// </summary>
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.Integer, EditorType.PropertyValue | EditorType.MacroParameter, "Numeric", "integer", ValueType = ValueTypes.Integer)]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.Integer,
|
||||
EditorType.PropertyValue | EditorType.MacroParameter,
|
||||
"Numeric",
|
||||
"integer",
|
||||
ValueType = ValueTypes.Integer)]
|
||||
public class IntegerPropertyEditor : DataEditor
|
||||
{
|
||||
public IntegerPropertyEditor(ILogger logger)
|
||||
|
||||
@@ -8,7 +8,13 @@ namespace Umbraco.Web.PropertyEditors
|
||||
/// <summary>
|
||||
/// Represents a list-view editor.
|
||||
/// </summary>
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.ListView, "List view", "listview", HideLabel = true, Group = "lists", Icon = Constants.Icons.ListView)]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.ListView,
|
||||
"List view",
|
||||
"listview",
|
||||
HideLabel = true,
|
||||
Group = Constants.PropertyEditors.Groups.Lists,
|
||||
Icon = Constants.Icons.ListView)]
|
||||
public class ListViewPropertyEditor : DataEditor
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -5,7 +5,14 @@ using Umbraco.Core.PropertyEditors;
|
||||
namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
// TODO: MacroContainerPropertyEditor is deprecated, but what's the alternative?
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.MacroContainer, "(Obsolete) Macro Picker", "macrocontainer", ValueType = ValueTypes.Text, Group = "rich content", Icon = Constants.Icons.Macro, IsDeprecated = true)]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.MacroContainer,
|
||||
"(Obsolete) Macro Picker",
|
||||
"macrocontainer",
|
||||
ValueType = ValueTypes.Text,
|
||||
Group = Constants.PropertyEditors.Groups.RichContent,
|
||||
Icon = Constants.Icons.Macro,
|
||||
IsDeprecated = true)]
|
||||
public class MacroContainerPropertyEditor : DataEditor
|
||||
{
|
||||
public MacroContainerPropertyEditor(ILogger logger)
|
||||
|
||||
@@ -7,7 +7,13 @@ namespace Umbraco.Web.PropertyEditors
|
||||
/// <summary>
|
||||
/// Represents a markdown editor.
|
||||
/// </summary>
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.MarkdownEditor, "Markdown editor", "markdowneditor", ValueType = ValueTypes.Text, Icon="icon-code", Group="rich content")]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.MarkdownEditor,
|
||||
"Markdown editor",
|
||||
"markdowneditor",
|
||||
ValueType = ValueTypes.Text,
|
||||
Group = Constants.PropertyEditors.Groups.RichContent,
|
||||
Icon = "icon-code")]
|
||||
public class MarkdownPropertyEditor : DataEditor
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -7,8 +7,14 @@ namespace Umbraco.Web.PropertyEditors
|
||||
/// <summary>
|
||||
/// Represents a media picker property editor.
|
||||
/// </summary>
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.MediaPicker, EditorType.PropertyValue | EditorType.MacroParameter,
|
||||
"Media Picker", "mediapicker", ValueType = ValueTypes.Text, Group = "media", Icon = Constants.Icons.MediaImage)]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.MediaPicker,
|
||||
EditorType.PropertyValue | EditorType.MacroParameter,
|
||||
"Media Picker",
|
||||
"mediapicker",
|
||||
ValueType = ValueTypes.Text,
|
||||
Group = Constants.PropertyEditors.Groups.Media,
|
||||
Icon = Constants.Icons.MediaImage)]
|
||||
public class MediaPickerPropertyEditor : DataEditor
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -4,7 +4,13 @@ using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.MemberGroupPicker, "Member Group Picker", "membergrouppicker", ValueType = ValueTypes.Text, Group = "People", Icon = Constants.Icons.MemberGroup)]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.MemberGroupPicker,
|
||||
"Member Group Picker",
|
||||
"membergrouppicker",
|
||||
ValueType = ValueTypes.Text,
|
||||
Group = Constants.PropertyEditors.Groups.People,
|
||||
Icon = Constants.Icons.MemberGroup)]
|
||||
public class MemberGroupPickerPropertyEditor : DataEditor
|
||||
{
|
||||
public MemberGroupPickerPropertyEditor(ILogger logger)
|
||||
|
||||
@@ -4,7 +4,13 @@ using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.MemberPicker, "Member Picker", "memberpicker", ValueType = ValueTypes.String, Group = "People", Icon = Constants.Icons.Member)]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.MemberPicker,
|
||||
"Member Picker",
|
||||
"memberpicker",
|
||||
ValueType = ValueTypes.String,
|
||||
Group = Constants.PropertyEditors.Groups.People,
|
||||
Icon = Constants.Icons.Member)]
|
||||
public class MemberPickerPropertyEditor : DataEditor
|
||||
{
|
||||
public MemberPickerPropertyEditor(ILogger logger)
|
||||
|
||||
@@ -4,7 +4,13 @@ using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.MultiNodeTreePicker, "Multinode Treepicker", "contentpicker", ValueType = ValueTypes.Text, Group = "pickers", Icon = "icon-page-add")]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.MultiNodeTreePicker,
|
||||
"Multinode Treepicker",
|
||||
"contentpicker",
|
||||
ValueType = ValueTypes.Text,
|
||||
Group = Constants.PropertyEditors.Groups.Pickers,
|
||||
Icon = "icon-page-add")]
|
||||
public class MultiNodeTreePickerPropertyEditor : DataEditor
|
||||
{
|
||||
public MultiNodeTreePickerPropertyEditor(ILogger logger)
|
||||
|
||||
@@ -7,7 +7,14 @@ using Umbraco.Web.PublishedCache;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.MultiUrlPicker, EditorType.PropertyValue, "Multi Url Picker", "multiurlpicker", ValueType = ValueTypes.Json, Group = "pickers", Icon = "icon-link")]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.MultiUrlPicker,
|
||||
EditorType.PropertyValue,
|
||||
"Multi Url Picker",
|
||||
"multiurlpicker",
|
||||
ValueType = ValueTypes.Json,
|
||||
Group = Constants.PropertyEditors.Groups.Pickers,
|
||||
Icon = "icon-link")]
|
||||
public class MultiUrlPickerPropertyEditor : DataEditor
|
||||
{
|
||||
private readonly IEntityService _entityService;
|
||||
|
||||
@@ -13,7 +13,13 @@ namespace Umbraco.Web.PropertyEditors
|
||||
/// <summary>
|
||||
/// Represents a multiple text string property editor.
|
||||
/// </summary>
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.MultipleTextstring, "Repeatable textstrings", "multipletextbox", ValueType = ValueTypes.Text, Icon="icon-ordered-list", Group="lists")]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.MultipleTextstring,
|
||||
"Repeatable textstrings",
|
||||
"multipletextbox",
|
||||
ValueType = ValueTypes.Text,
|
||||
Group = Constants.PropertyEditors.Groups.Lists,
|
||||
Icon = "icon-ordered-list")]
|
||||
public class MultipleTextStringPropertyEditor : DataEditor
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -18,7 +18,13 @@ namespace Umbraco.Web.PropertyEditors
|
||||
/// <summary>
|
||||
/// Represents a nested content property editor.
|
||||
/// </summary>
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.NestedContent, "Nested Content", "nestedcontent", ValueType = "JSON", Group = "lists", Icon = "icon-thumbnail-list")]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.NestedContent,
|
||||
"Nested Content",
|
||||
"nestedcontent",
|
||||
ValueType = ValueTypes.Json,
|
||||
Group = Constants.PropertyEditors.Groups.Lists,
|
||||
Icon = "icon-thumbnail-list")]
|
||||
public class NestedContentPropertyEditor : DataEditor
|
||||
{
|
||||
private readonly Lazy<PropertyEditorCollection> _propertyEditors;
|
||||
|
||||
@@ -6,7 +6,11 @@ namespace Umbraco.Web.PropertyEditors.ParameterEditors
|
||||
/// <summary>
|
||||
/// Represents a content type parameter editor.
|
||||
/// </summary>
|
||||
[DataEditor("contentType", EditorType.MacroParameter, "Content Type Picker", "entitypicker")]
|
||||
[DataEditor(
|
||||
"contentType",
|
||||
EditorType.MacroParameter,
|
||||
"Content Type Picker",
|
||||
"entitypicker")]
|
||||
public class ContentTypeParameterEditor : DataEditor
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
+5
-1
@@ -7,7 +7,11 @@ namespace Umbraco.Web.PropertyEditors.ParameterEditors
|
||||
/// <summary>
|
||||
/// Represents a parameter editor of some sort.
|
||||
/// </summary>
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.MultiNodeTreePicker, EditorType.MacroParameter, "Multiple Content Picker", "contentpicker")]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.MultiNodeTreePicker,
|
||||
EditorType.MacroParameter,
|
||||
"Multiple Content Picker",
|
||||
"contentpicker")]
|
||||
public class MultipleContentPickerParameterEditor : DataEditor
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
+5
-1
@@ -3,7 +3,11 @@ using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors.ParameterEditors
|
||||
{
|
||||
[DataEditor("contentTypeMultiple", EditorType.MacroParameter, "Multiple Content Type Picker", "entitypicker")]
|
||||
[DataEditor(
|
||||
"contentTypeMultiple",
|
||||
EditorType.MacroParameter,
|
||||
"Multiple Content Type Picker",
|
||||
"entitypicker")]
|
||||
public class MultipleContentTypeParameterEditor : DataEditor
|
||||
{
|
||||
public MultipleContentTypeParameterEditor(ILogger logger)
|
||||
|
||||
+5
-1
@@ -3,7 +3,11 @@ using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors.ParameterEditors
|
||||
{
|
||||
[DataEditor("tabPickerMultiple", EditorType.MacroParameter, "Multiple Tab Picker", "entitypicker")]
|
||||
[DataEditor(
|
||||
"tabPickerMultiple",
|
||||
EditorType.MacroParameter,
|
||||
"Multiple Tab Picker",
|
||||
"entitypicker")]
|
||||
public class MultiplePropertyGroupParameterEditor : DataEditor
|
||||
{
|
||||
public MultiplePropertyGroupParameterEditor(ILogger logger)
|
||||
|
||||
+5
-1
@@ -3,7 +3,11 @@ using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors.ParameterEditors
|
||||
{
|
||||
[DataEditor("propertyTypePickerMultiple", EditorType.MacroParameter, "Multiple Property Type Picker", "entitypicker")]
|
||||
[DataEditor(
|
||||
"propertyTypePickerMultiple",
|
||||
EditorType.MacroParameter,
|
||||
"Multiple Property Type Picker",
|
||||
"entitypicker")]
|
||||
public class MultiplePropertyTypeParameterEditor : DataEditor
|
||||
{
|
||||
public MultiplePropertyTypeParameterEditor(ILogger logger)
|
||||
|
||||
@@ -3,7 +3,11 @@ using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors.ParameterEditors
|
||||
{
|
||||
[DataEditor("tabPicker", EditorType.MacroParameter, "Tab Picker", "entitypicker")]
|
||||
[DataEditor(
|
||||
"tabPicker",
|
||||
EditorType.MacroParameter,
|
||||
"Tab Picker",
|
||||
"entitypicker")]
|
||||
public class PropertyGroupParameterEditor : DataEditor
|
||||
{
|
||||
public PropertyGroupParameterEditor(ILogger logger)
|
||||
|
||||
@@ -3,7 +3,11 @@ using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors.ParameterEditors
|
||||
{
|
||||
[DataEditor("propertyTypePicker", EditorType.MacroParameter, "Property Type Picker", "entitypicker")]
|
||||
[DataEditor(
|
||||
"propertyTypePicker",
|
||||
EditorType.MacroParameter,
|
||||
"Property Type Picker",
|
||||
"entitypicker")]
|
||||
public class PropertyTypeParameterEditor : DataEditor
|
||||
{
|
||||
public PropertyTypeParameterEditor(ILogger logger)
|
||||
|
||||
@@ -8,7 +8,13 @@ namespace Umbraco.Web.PropertyEditors
|
||||
/// <summary>
|
||||
/// A property editor to allow the individual selection of pre-defined items.
|
||||
/// </summary>
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.RadioButtonList, "Radio button list", "radiobuttons", ValueType = ValueTypes.String, Group="lists", Icon="icon-target")]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.RadioButtonList,
|
||||
"Radio button list",
|
||||
"radiobuttons",
|
||||
ValueType = ValueTypes.String,
|
||||
Group = Constants.PropertyEditors.Groups.Lists,
|
||||
Icon = "icon-target")]
|
||||
public class RadioButtonsPropertyEditor : DataEditor
|
||||
{
|
||||
private readonly ILocalizedTextService _textService;
|
||||
|
||||
@@ -15,7 +15,14 @@ namespace Umbraco.Web.PropertyEditors
|
||||
/// <summary>
|
||||
/// Represents a rich text property editor.
|
||||
/// </summary>
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.TinyMce, "Rich Text Editor", "rte", ValueType = ValueTypes.Text, HideLabel = false, Group="Rich Content", Icon="icon-browser-window")]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.TinyMce,
|
||||
"Rich Text Editor",
|
||||
"rte",
|
||||
ValueType = ValueTypes.Text,
|
||||
HideLabel = false,
|
||||
Group = Constants.PropertyEditors.Groups.RichContent,
|
||||
Icon = "icon-browser-window")]
|
||||
public class RichTextPropertyEditor : DataEditor
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -7,7 +7,11 @@ namespace Umbraco.Web.PropertyEditors
|
||||
/// <summary>
|
||||
/// Represents a slider editor.
|
||||
/// </summary>
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.Slider, "Slider", "slider", Icon = "icon-navigation-horizontal")]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.Slider,
|
||||
"Slider",
|
||||
"slider",
|
||||
Icon = "icon-navigation-horizontal")]
|
||||
public class SliderPropertyEditor : DataEditor
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -15,7 +15,11 @@ namespace Umbraco.Web.PropertyEditors
|
||||
/// Represents a tags property editor.
|
||||
/// </summary>
|
||||
[TagsPropertyEditor]
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.Tags, "Tags", "tags", Icon="icon-tags")]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.Tags,
|
||||
"Tags",
|
||||
"tags",
|
||||
Icon = "icon-tags")]
|
||||
public class TagsPropertyEditor : DataEditor
|
||||
{
|
||||
private readonly ManifestValueValidatorCollection _validators;
|
||||
|
||||
@@ -7,7 +7,13 @@ namespace Umbraco.Web.PropertyEditors
|
||||
/// <summary>
|
||||
/// Represents a textarea property and parameter editor.
|
||||
/// </summary>
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.TextArea, EditorType.PropertyValue | EditorType.MacroParameter, "Textarea", "textarea", ValueType = ValueTypes.Text, Icon="icon-application-window-alt")]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.TextArea,
|
||||
EditorType.PropertyValue | EditorType.MacroParameter,
|
||||
"Textarea",
|
||||
"textarea",
|
||||
ValueType = ValueTypes.Text,
|
||||
Icon = "icon-application-window-alt")]
|
||||
public class TextAreaPropertyEditor : DataEditor
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -7,7 +7,12 @@ namespace Umbraco.Web.PropertyEditors
|
||||
/// <summary>
|
||||
/// Represents a textbox property and parameter editor.
|
||||
/// </summary>
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.TextBox, EditorType.PropertyValue | EditorType.MacroParameter, "Textbox", "textbox", Group = "Common")]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.TextBox,
|
||||
EditorType.PropertyValue | EditorType.MacroParameter,
|
||||
"Textbox",
|
||||
"textbox",
|
||||
Group = Constants.PropertyEditors.Groups.Common)]
|
||||
public class TextboxPropertyEditor : DataEditor
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -7,7 +7,14 @@ namespace Umbraco.Web.PropertyEditors
|
||||
/// <summary>
|
||||
/// Represents a checkbox property and parameter editor.
|
||||
/// </summary>
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.Boolean, EditorType.PropertyValue | EditorType.MacroParameter, "Checkbox", "boolean", ValueType = ValueTypes.Integer, Group = "Common", Icon="icon-checkbox")]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.Boolean,
|
||||
EditorType.PropertyValue | EditorType.MacroParameter,
|
||||
"Checkbox",
|
||||
"boolean",
|
||||
ValueType = ValueTypes.Integer,
|
||||
Group = Constants.PropertyEditors.Groups.Common,
|
||||
Icon = "icon-checkbox")]
|
||||
public class TrueFalsePropertyEditor : DataEditor
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -6,7 +6,13 @@ using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Web.PropertyEditors
|
||||
{
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.UserPicker, "User picker", "entitypicker", ValueType = ValueTypes.Integer, Group = "People", Icon = Constants.Icons.User)]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.UserPicker,
|
||||
"User picker",
|
||||
"entitypicker",
|
||||
ValueType = ValueTypes.Integer,
|
||||
Group = Constants.PropertyEditors.Groups.People,
|
||||
Icon = Constants.Icons.User)]
|
||||
public class UserPickerPropertyEditor : DataEditor
|
||||
{
|
||||
public UserPickerPropertyEditor(ILogger logger)
|
||||
|
||||
@@ -45,6 +45,10 @@ namespace Umbraco.Web.Routing
|
||||
if (string.IsNullOrEmpty(path))
|
||||
return null;
|
||||
|
||||
// the stored path is absolute so we just return it as is
|
||||
if(Uri.IsWellFormedUriString(path, UriKind.Absolute))
|
||||
return new Uri(path);
|
||||
|
||||
Uri uri;
|
||||
|
||||
if (current == null)
|
||||
|
||||
Reference in New Issue
Block a user