Compare commits
130 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9a2e14d8f6 | |||
| 7d8a6e28fa | |||
| 6a9c56df58 | |||
| 078f4a506e | |||
| a54170b915 | |||
| 757ba890f5 | |||
| a127dac03a | |||
| 77ec2d7a9c | |||
| 0d55f0ed86 | |||
| 6a7ac205bc | |||
| 1cb2139137 | |||
| b9179f4140 | |||
| bae1ee508b | |||
| 20b6a78af1 | |||
| 014b407abb | |||
| 5aa16a6636 | |||
| 7206bba46a | |||
| af9db94fb6 | |||
| d2014be81b | |||
| 01b8b3b508 | |||
| 734125fa25 | |||
| 76678f538d | |||
| 7fe23fdf4c | |||
| c956c12cdf | |||
| 8706feb882 | |||
| c8364986a2 | |||
| 4d24150bdc | |||
| a16c4b4da9 | |||
| 75a312c309 | |||
| aa6505d7f6 | |||
| 6ed7af28bc | |||
| 526f4c147a | |||
| bb0df72dc7 | |||
| 3cba5677bf | |||
| c4f88ab528 | |||
| 7bc9584940 | |||
| 17be4b4253 | |||
| 2db196af6a | |||
| b4b27cd1f8 | |||
| a2cc052944 | |||
| 4d8a4f0b12 | |||
| 743f37c45f | |||
| 1ba45969ee | |||
| 349d6f69b3 | |||
| 9431a70156 | |||
| ab780f72a4 | |||
| 7d01be305f | |||
| 694b932e37 | |||
| a4f6334761 | |||
| 9316e7c3f6 | |||
| 8bc6c17921 | |||
| 1161c7e6da | |||
| 93db3eb2ee | |||
| b7b166562f | |||
| e3c4c91de1 | |||
| f79849cf8a | |||
| f0b27e1507 | |||
| 42e92a4e74 | |||
| 2c363a5d37 | |||
| 738e9282b6 | |||
| 20fa1efc8e | |||
| 718f2deb47 | |||
| 1cea5d156a | |||
| 109d4c7708 | |||
| 8306be60de | |||
| 27d0cb742b | |||
| 62a250cd83 | |||
| 6f94d608db | |||
| 854e9873c8 | |||
| 2a6d5eaddf | |||
| 3d7ddb58c2 | |||
| 4c7496840d | |||
| d816103981 | |||
| b38ccc12f6 | |||
| e1deba5b95 | |||
| 5bce4e856a | |||
| 6f4cb1e609 | |||
| 033cbbc8f6 | |||
| 7ee3cfca5c | |||
| e9b478c186 | |||
| 21e784424f | |||
| 155355aa00 | |||
| abf6917b1c | |||
| 40ad701f7f | |||
| a8113f926c | |||
| 3c527396de | |||
| 59bf66dcd1 | |||
| c125042a86 | |||
| 85ea472129 | |||
| f541b50b82 | |||
| 5767ea97d1 | |||
| e1fa7a3271 | |||
| c2e97e28ce | |||
| eda9bab02f | |||
| ce3cecbec9 | |||
| ef5faae254 | |||
| 547473e92c | |||
| 9857059906 | |||
| 7f7b054c14 | |||
| a40d95250e | |||
| 1e6004d3fa | |||
| 0671403732 | |||
| 8e00914370 | |||
| 104c369bcc | |||
| 4c02cf2921 | |||
| 74470b8e8f | |||
| de92147ec0 | |||
| c2b7d2c89d | |||
| d0fe30f08b | |||
| d22ae1244e | |||
| fa48d73630 | |||
| be332d310f | |||
| d97bbb59dc | |||
| 3702ec484b | |||
| d8d4ec1a73 | |||
| 32cb89bba1 | |||
| 863f041fc9 | |||
| 5a83719dfc | |||
| 1b1940fe6a | |||
| 7dd07b9f9c | |||
| 29652bb880 | |||
| 62b7420eaa | |||
| 333f17976b | |||
| 45981b0431 | |||
| 531ff0aab4 | |||
| ebf3fd1135 | |||
| 85157612f4 | |||
| f57205dab9 | |||
| b6ccab10b3 | |||
| b0f614c891 |
+2
-1
@@ -62,4 +62,5 @@ VersionInfo.cs
|
||||
.builds
|
||||
.svn
|
||||
.hg
|
||||
.hgignore
|
||||
.hgignore
|
||||
app/Umbraco/.vs/config/applicationhost.config
|
||||
+5
-2
@@ -85,6 +85,7 @@ module.exports = function(grunt) {
|
||||
'app/controllers/controller_versioned.js',
|
||||
'app/controllers/config.controller.js',
|
||||
'app/controllers/config.dialog.controller.js',
|
||||
'app/controllers/config.global.controller.js',
|
||||
'app/directives/archetypeproperty.js',
|
||||
'app/directives/archetypesubmitwatcher.js',
|
||||
'app/directives/archetypecustomview.js',
|
||||
@@ -95,7 +96,8 @@ module.exports = function(grunt) {
|
||||
'app/resources/archetypePropertyEditorResource.js',
|
||||
'app/services/archetypeService.js',
|
||||
'app/services/archetypeLabelService.js',
|
||||
'app/services/archetypeCacheService.js'
|
||||
'app/services/archetypeCacheService.js',
|
||||
'app/services/archetypeGlobalConfigService.js'
|
||||
],
|
||||
dest: '<%= basePath %>/js/archetype.js'
|
||||
}
|
||||
@@ -269,7 +271,8 @@ module.exports = function(grunt) {
|
||||
'app/controllers/*.js',
|
||||
'!app/controllers/controller.js',
|
||||
'!app/controllers/config.controller.js',
|
||||
'!app/controllers/config.dialog.controller.js'
|
||||
'!app/controllers/config.dialog.controller.js',
|
||||
'!app/controllers/config.global.controller.js'
|
||||
],
|
||||
less: [
|
||||
'app/less/*.less',
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Imulus
|
||||
Copyright (c) 2016 Kevin Giszewski LLC
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
|
||||
@@ -10,17 +10,23 @@ Install the selected <a href='https://github.com/imulus/Archetype/releases'>rele
|
||||
## Official Docs ##
|
||||
https://github.com/kgiszewski/ArchetypeManual
|
||||
|
||||
Get up and running in 15 minutes! https://www.youtube.com/watch?v=79LksNwGjLk
|
||||
|
||||
##News and Updates##
|
||||
## News and Updates ##
|
||||
Follow us on Twitter https://twitter.com/ArchetypeKit
|
||||
|
||||
##Core Team##
|
||||
## Core Team ##
|
||||
* Kevin Giszewski (founder/project lead) - University of Notre Dame - https://kevin.giszewski.com/
|
||||
* Tom Fulton (founder) - Tonic - http://hellotonic.com/
|
||||
* Lee Kelleher - Umbrella - http://www.umbrellainc.co.uk/
|
||||
* Matt Brailsford - The Outfield - http://www.theoutfield.co.uk/
|
||||
* Kenn Jacobsen - Vertica - http://kennjacobsen.dk/
|
||||
|
||||
## Donate!
|
||||
[](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=KBKWLURGLGU6L)
|
||||
|
||||
This project is funded by the core team members' time only. We don't charge for Archetype but it does take quite a bit of effort to keep it up-to-date with Umbraco core changes. If you're making a few bucks off of Archetype, we wouldn't refuse a donation :)
|
||||
|
||||
## Contribute ##
|
||||
|
||||
Want to contribute to Archetype? You'll want to use Grunt (our task runner) to help you integrate with a local copy of Umbraco.
|
||||
|
||||
@@ -263,6 +263,7 @@
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="PropertyValueConverter\PropertyValueConverterTests.cs" />
|
||||
<Compile Include="PublishedContent\ArchetypePublishedContentTests.cs" />
|
||||
<Compile Include="PublishedContent\TypeConverterTests.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Archetype.Models;
|
||||
using Archetype.PropertyConverters;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Archetype.Tests.PublishedContent
|
||||
{
|
||||
[TestFixture]
|
||||
public class TypeConverterTests
|
||||
{
|
||||
private ArchetypeModel _archetype;
|
||||
|
||||
[TestFixtureSetUp]
|
||||
public void Init()
|
||||
{
|
||||
var archetypeJson = System.IO.File.ReadAllText("..\\..\\Data\\sample-1.json");
|
||||
var converter = new ArchetypeValueConverter();
|
||||
|
||||
_archetype = (ArchetypeModel)converter.ConvertDataToSource(null, archetypeJson, false);
|
||||
}
|
||||
|
||||
[TestCase(typeof(ArchetypeModel), true)]
|
||||
[TestCase(typeof(ArchetypePublishedContentSet), true)]
|
||||
[TestCase(typeof(IEnumerable<IPublishedContent>), true)]
|
||||
[TestCase(typeof(string), true)]
|
||||
[TestCase(typeof(int), false)]
|
||||
[TestCase(typeof(ArchetypeFieldsetModel), false)]
|
||||
public void ArchetypeModel_ConvertsTo_EnumerablePublishedContent(Type destinationType, bool expected)
|
||||
{
|
||||
Assert.IsNotNull(_archetype);
|
||||
|
||||
var attempt = _archetype.TryConvertTo(destinationType);
|
||||
|
||||
Assert.That(attempt.Success, Is.EqualTo(expected));
|
||||
|
||||
if (attempt.Success)
|
||||
{
|
||||
Assert.IsNotNull(attempt.Result);
|
||||
Assert.That(attempt.Result, Is.InstanceOf(destinationType));
|
||||
}
|
||||
}
|
||||
|
||||
[TestCase(typeof(ArchetypeFieldsetModel), true)]
|
||||
[TestCase(typeof(ArchetypePublishedContent), true)]
|
||||
[TestCase(typeof(IPublishedContent), true)]
|
||||
[TestCase(typeof(string), true)]
|
||||
[TestCase(typeof(int), false)]
|
||||
[TestCase(typeof(ArchetypeModel), false)]
|
||||
public void ArchetypeFieldsetModel_ConvertsTo_PublishedContent(Type destinationType, bool expected)
|
||||
{
|
||||
CollectionAssert.IsNotEmpty(_archetype.Fieldsets);
|
||||
|
||||
var attempt = _archetype.First().TryConvertTo(destinationType);
|
||||
|
||||
Assert.That(attempt.Success, Is.EqualTo(expected));
|
||||
|
||||
if (attempt.Success)
|
||||
{
|
||||
Assert.IsNotNull(attempt.Result);
|
||||
Assert.That(attempt.Result, Is.InstanceOf(destinationType));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Reflection;
|
||||
using System.Web.Http;
|
||||
using AutoMapper;
|
||||
using Umbraco.Core.Models;
|
||||
@@ -11,12 +9,14 @@ using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.Editors;
|
||||
using Archetype.Extensions;
|
||||
using Archetype.Models;
|
||||
|
||||
namespace Archetype.Api
|
||||
{
|
||||
/// <summary>
|
||||
/// Controller that handles datatype related interactions.
|
||||
/// </summary>
|
||||
/// <seealso cref="Umbraco.Web.Editors.UmbracoAuthorizedJsonController" />
|
||||
[PluginController("ArchetypeApi")]
|
||||
public class ArchetypeDataTypeController : UmbracoAuthorizedJsonController
|
||||
{
|
||||
@@ -24,14 +24,14 @@ namespace Archetype.Api
|
||||
{
|
||||
return
|
||||
global::Umbraco.Core.PropertyEditors.PropertyEditorResolver.Current.PropertyEditors
|
||||
.Select(x => new {defaultPreValues = x.DefaultPreValuesForArchetype(), alias = x.Alias, view = x.ValueEditor.View});
|
||||
.Select(x => new { defaultPreValues = x.DefaultPreValuesForArchetype(), alias = x.Alias, view = x.ValueEditor.View });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets all datatypes.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public object GetAll()
|
||||
public object GetAll()
|
||||
{
|
||||
var dataTypes = Services.DataTypeService.GetAllDataTypeDefinitions();
|
||||
return dataTypes.Select(t => new { guid = t.Key, name = t.Name });
|
||||
@@ -68,11 +68,14 @@ namespace Archetype.Api
|
||||
public object GetByGuid(Guid guid, string contentTypeAlias, string propertyTypeAlias, string archetypeAlias, int nodeId)
|
||||
{
|
||||
var dataType = Services.DataTypeService.GetDataTypeDefinitionById(guid);
|
||||
|
||||
if (dataType == null)
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
var dataTypeDisplay = Mapper.Map<IDataTypeDefinition, DataTypeDisplay>(dataType);
|
||||
|
||||
return new { selectedEditor = dataTypeDisplay.SelectedEditor, preValues = dataTypeDisplay.PreValues, contentTypeAlias = contentTypeAlias, propertyTypeAlias = propertyTypeAlias, archetypeAlias = archetypeAlias, nodeId = nodeId };
|
||||
}
|
||||
|
||||
@@ -82,19 +85,58 @@ namespace Archetype.Api
|
||||
/// <returns></returns>
|
||||
public object GetDllVersion()
|
||||
{
|
||||
return new {dllVersion = _version()};
|
||||
return new { dllVersion = ArchetypeHelper.Instance.DllVersion() };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the DLL version from the file.
|
||||
/// Globals the settings.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private string _version()
|
||||
/// <returns>System.Object.</returns>
|
||||
[HttpGet]
|
||||
public object GlobalSettings()
|
||||
{
|
||||
var asm = Assembly.GetExecutingAssembly();
|
||||
var fvi = FileVersionInfo.GetVersionInfo(asm.Location);
|
||||
return new
|
||||
{
|
||||
isCheckingForUpdates = ArchetypeGlobalSettings.Instance.CheckForUpdates
|
||||
};
|
||||
}
|
||||
|
||||
return fvi.FileVersion;
|
||||
/// <summary>
|
||||
/// Sets the check for updates.
|
||||
/// </summary>
|
||||
/// <param name="isChecking">if set to <c>true</c> [is checking].</param>
|
||||
[HttpPost]
|
||||
public void SetCheckForUpdates([FromBody] bool isChecking)
|
||||
{
|
||||
ArchetypeGlobalSettings.Instance.CheckForUpdates = isChecking;
|
||||
ArchetypeGlobalSettings.Instance.Save();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks for updates.
|
||||
/// </summary>
|
||||
/// <returns>System.Object.</returns>
|
||||
[HttpPost]
|
||||
public object CheckForUpdates()
|
||||
{
|
||||
if (!ArchetypeGlobalSettings.Instance.CheckForUpdates)
|
||||
{
|
||||
return new
|
||||
{
|
||||
isUpdateAvailable = false
|
||||
};
|
||||
}
|
||||
|
||||
var updateNotificationModel = ArchetypeHelper.Instance.CheckForUpdates();
|
||||
|
||||
return new
|
||||
{
|
||||
isUpdateAvailable = updateNotificationModel.IsUpdateAvailable,
|
||||
headline = updateNotificationModel.Headline,
|
||||
type = updateNotificationModel.Type,
|
||||
message = updateNotificationModel.Message,
|
||||
url = updateNotificationModel.Url
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,6 +129,7 @@
|
||||
<Private>False</Private>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.0, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
|
||||
<Private>False</Private>
|
||||
@@ -238,6 +239,8 @@
|
||||
<Compile Include="Extensions\ArchetypePropertyModelExtensions.cs" />
|
||||
<Compile Include="Extensions\PropertyEditorExtensions.cs" />
|
||||
<Compile Include="Extensions\StringExtensions.cs" />
|
||||
<Compile Include="Models\ArchetypeConfigFileModel.cs" />
|
||||
<Compile Include="Models\ArchetypeGlobalSettings.cs" />
|
||||
<Compile Include="Models\ArchetypeModel.cs" />
|
||||
<Compile Include="Models\ArchetypePreValue.cs" />
|
||||
<Compile Include="Models\ArchetypePreValueFieldset.cs" />
|
||||
@@ -248,10 +251,13 @@
|
||||
<Compile Include="Models\ArchetypePublishedContent.cs" />
|
||||
<Compile Include="Models\ArchetypePublishedContentSet.cs" />
|
||||
<Compile Include="Models\ArchetypePublishedProperty.cs" />
|
||||
<Compile Include="Models\ArchetypeUpdateNotification.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Properties\VersionInfo.cs" />
|
||||
<Compile Include="PropertyConverters\ArchetypeValueConverter.cs" />
|
||||
<Compile Include="PropertyEditors\ArchetypePropertyEditor.cs" />
|
||||
<Compile Include="TypeConverters\ArchetypeFieldsetModelConverter.cs" />
|
||||
<Compile Include="TypeConverters\ArchetypeModelConverter.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
|
||||
@@ -12,5 +12,8 @@
|
||||
public const string CacheKey_DataTypeByGuid = "";
|
||||
|
||||
public const string CacheKey_PreValueFromDataTypeId = "Archetype_GetArchetypePreValueFromDataTypeId_";
|
||||
|
||||
public const string UmbracoVersionAlias = "umbracoConfigurationStatus";
|
||||
public const string NotificationUrl = "https://api.gizmo42.com/v1/archetype/check-for-updates";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,21 @@
|
||||
using System;
|
||||
using System.Configuration;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using Archetype.Models;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using System.Reflection;
|
||||
using System.Diagnostics;
|
||||
using System.Net;
|
||||
|
||||
/// <summary>
|
||||
/// The Extensions namespace.
|
||||
/// </summary>
|
||||
namespace Archetype.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
@@ -14,20 +23,52 @@ namespace Archetype.Extensions
|
||||
/// </summary>
|
||||
public class ArchetypeHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// The json settings
|
||||
/// </summary>
|
||||
protected JsonSerializerSettings _jsonSettings;
|
||||
/// <summary>
|
||||
/// The application
|
||||
/// </summary>
|
||||
protected ApplicationContext _app;
|
||||
|
||||
private static readonly ArchetypeHelper _instance = new ArchetypeHelper();
|
||||
|
||||
internal static ArchetypeHelper Instance { get { return _instance; } }
|
||||
/// <summary>
|
||||
/// The pad lock
|
||||
/// </summary>
|
||||
private static readonly object _padLock = new object();
|
||||
/// <summary>
|
||||
/// The instance
|
||||
/// </summary>
|
||||
private static ArchetypeHelper _instance = new ArchetypeHelper();
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ArchetypeHelper"/> class.
|
||||
/// Gets the instance.
|
||||
/// </summary>
|
||||
internal ArchetypeHelper()
|
||||
/// <value>The instance.</value>
|
||||
internal static ArchetypeHelper Instance {
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
lock (_padLock)
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = new ArchetypeHelper();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ArchetypeHelper" /> class.
|
||||
/// </summary>
|
||||
private ArchetypeHelper()
|
||||
{
|
||||
var dcr = new Newtonsoft.Json.Serialization.DefaultContractResolver();
|
||||
dcr.DefaultMembersSearchFlags |= System.Reflection.BindingFlags.NonPublic;
|
||||
dcr.DefaultMembersSearchFlags |= BindingFlags.NonPublic;
|
||||
|
||||
_jsonSettings = new JsonSerializerSettings { ContractResolver = dcr };
|
||||
_app = ApplicationContext.Current;
|
||||
@@ -36,9 +77,7 @@ namespace Archetype.Extensions
|
||||
/// <summary>
|
||||
/// Gets the json serializer settings.
|
||||
/// </summary>
|
||||
/// <value>
|
||||
/// The json serializer settings.
|
||||
/// </value>
|
||||
/// <value>The json serializer settings.</value>
|
||||
internal JsonSerializerSettings JsonSerializerSettings { get { return _jsonSettings; } }
|
||||
|
||||
/// <summary>
|
||||
@@ -46,7 +85,7 @@ namespace Archetype.Extensions
|
||||
/// </summary>
|
||||
/// <param name="sourceJson">The source JSON.</param>
|
||||
/// <param name="dataTypePreValues">The data type pre values.</param>
|
||||
/// <returns></returns>
|
||||
/// <returns>ArchetypeModel.</returns>
|
||||
internal ArchetypeModel DeserializeJsonToArchetype(string sourceJson, PreValueCollection dataTypePreValues)
|
||||
{
|
||||
try
|
||||
@@ -78,7 +117,7 @@ namespace Archetype.Extensions
|
||||
/// <param name="sourceJson">The source JSON.</param>
|
||||
/// <param name="dataTypeId">The data type identifier.</param>
|
||||
/// <param name="hostContentType">Type of the host content.</param>
|
||||
/// <returns></returns>
|
||||
/// <returns>ArchetypeModel.</returns>
|
||||
internal ArchetypeModel DeserializeJsonToArchetype(string sourceJson, int dataTypeId, PublishedContentType hostContentType = null)
|
||||
{
|
||||
try
|
||||
@@ -98,7 +137,7 @@ namespace Archetype.Extensions
|
||||
|
||||
return archetype;
|
||||
}
|
||||
catch
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new ArchetypeModel();
|
||||
}
|
||||
@@ -108,21 +147,66 @@ namespace Archetype.Extensions
|
||||
/// Determines whether datatypeId has had it's PVC overridden.
|
||||
/// </summary>
|
||||
/// <param name="dataTypeId">The data type identifier.</param>
|
||||
/// <returns></returns>
|
||||
/// <returns><c>true</c> if [is property value converter overridden] [the specified data type identifier]; otherwise, <c>false</c>.</returns>
|
||||
internal bool IsPropertyValueConverterOverridden(int dataTypeId)
|
||||
{
|
||||
var prevalues = GetArchetypePreValueFromDataTypeId(dataTypeId);
|
||||
|
||||
if (prevalues == null)
|
||||
return false;
|
||||
|
||||
return prevalues.OverrideDefaultPropertyValueConverter;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks for updates.
|
||||
/// </summary>
|
||||
/// <returns>ArchetypeUpdateNotification.</returns>
|
||||
internal ArchetypeUpdateNotification CheckForUpdates()
|
||||
{
|
||||
try
|
||||
{
|
||||
using (var client = new HttpClient())
|
||||
{
|
||||
var content = new StringContent(JsonConvert.SerializeObject(new
|
||||
{
|
||||
umbracoVersion = ConfigurationManager.AppSettings[Constants.UmbracoVersionAlias],
|
||||
archetypeVersion = DllVersion(),
|
||||
id = ArchetypeGlobalSettings.Instance.Id
|
||||
}), Encoding.UTF8, "application/json");
|
||||
|
||||
client.DefaultRequestHeaders.Add("x-api-key-id", ArchetypeGlobalSettings.Instance.ApiKey.ToString());
|
||||
|
||||
var response = client.PostAsync(new Uri(Constants.NotificationUrl), content).Result;
|
||||
|
||||
if (response.StatusCode == HttpStatusCode.OK)
|
||||
{
|
||||
var responseString = response.Content.ReadAsStringAsync().Result;
|
||||
|
||||
return JsonConvert.DeserializeObject<ArchetypeUpdateNotification>(responseString);
|
||||
}
|
||||
|
||||
return new ArchetypeUpdateNotification
|
||||
{
|
||||
IsUpdateAvailable = false
|
||||
};
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//if anything goes wrong let's make sure we don't break their site
|
||||
return new ArchetypeUpdateNotification
|
||||
{
|
||||
IsUpdateAvailable = false
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the archetype pre value from data type identifier.
|
||||
/// </summary>
|
||||
/// <param name="dataTypeId">The data type identifier.</param>
|
||||
/// <returns></returns>
|
||||
/// <returns>ArchetypePreValue.</returns>
|
||||
private ArchetypePreValue GetArchetypePreValueFromDataTypeId(int dataTypeId)
|
||||
{
|
||||
return _app.ApplicationCache.RuntimeCache.GetCacheItem(
|
||||
@@ -147,7 +231,7 @@ namespace Archetype.Extensions
|
||||
/// Gets the archetype pre value from pre values collection.
|
||||
/// </summary>
|
||||
/// <param name="dataTypePreValues">The data type pre values.</param>
|
||||
/// <returns></returns>
|
||||
/// <returns>ArchetypePreValue.</returns>
|
||||
private ArchetypePreValue GetArchetypePreValueFromPreValuesCollection(PreValueCollection dataTypePreValues)
|
||||
{
|
||||
var preValueAsString = dataTypePreValues.PreValuesAsDictionary.First().Value.Value;
|
||||
@@ -159,7 +243,7 @@ namespace Archetype.Extensions
|
||||
/// Gets the data type by unique identifier.
|
||||
/// </summary>
|
||||
/// <param name="guid">The unique identifier.</param>
|
||||
/// <returns></returns>
|
||||
/// <returns>IDataTypeDefinition.</returns>
|
||||
internal IDataTypeDefinition GetDataTypeByGuid(Guid guid)
|
||||
{
|
||||
return (IDataTypeDefinition)ApplicationContext.Current.ApplicationCache.RuntimeCache.GetCacheItem(
|
||||
@@ -172,6 +256,7 @@ namespace Archetype.Extensions
|
||||
/// </summary>
|
||||
/// <param name="archetype">The Archetype to add the additional metadata to</param>
|
||||
/// <param name="preValue">The configuration of the Archetype</param>
|
||||
/// <param name="hostContentType">Type of the host content.</param>
|
||||
private void RetrieveAdditionalProperties(ref ArchetypeModel archetype, ArchetypePreValue preValue, PublishedContentType hostContentType = null)
|
||||
{
|
||||
foreach (var fieldset in preValue.Fieldsets)
|
||||
@@ -197,7 +282,6 @@ namespace Archetype.Extensions
|
||||
/// <summary>
|
||||
/// Retrieves additional metadata that isn't available on the stored model of an ArchetypePreValue
|
||||
/// </summary>
|
||||
/// <param name="archetype">The Archetype to add the additional metadata to</param>
|
||||
/// <param name="preValue">The configuration of the Archetype</param>
|
||||
private void RetrieveAdditionalProperties(ref ArchetypePreValue preValue)
|
||||
{
|
||||
@@ -209,5 +293,18 @@ namespace Archetype.Extensions
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the DLL version from the file.
|
||||
/// </summary>
|
||||
/// <returns>System.String.</returns>
|
||||
internal string DllVersion()
|
||||
{
|
||||
var asm = Assembly.GetExecutingAssembly();
|
||||
var fvi = FileVersionInfo.GetVersionInfo(asm.Location);
|
||||
|
||||
return fvi.FileVersion;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
using System;
|
||||
|
||||
namespace Archetype.Models
|
||||
{
|
||||
public class ArchetypeConfigFileModel
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public bool CheckForUpdates { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,18 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Web.Security;
|
||||
using Archetype.TypeConverters;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core;
|
||||
using System;
|
||||
|
||||
namespace Archetype.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Model that represents a fieldset stored as content JSON.
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(ArchetypeFieldsetModelConverter))]
|
||||
public class ArchetypeFieldsetModel
|
||||
{
|
||||
[JsonProperty("alias")]
|
||||
@@ -29,6 +33,9 @@ namespace Archetype.Models
|
||||
[JsonProperty("expireDate")]
|
||||
public DateTime? ExpireDate { get; set; }
|
||||
|
||||
[JsonProperty("allowedMemberGroups")]
|
||||
public string AllowedMemberGroups { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ArchetypeFieldsetModel"/> class.
|
||||
/// </summary>
|
||||
@@ -59,7 +66,7 @@ namespace Archetype.Models
|
||||
{
|
||||
var property = GetProperty(propertyAlias);
|
||||
|
||||
if (IsEmptyProperty(property))
|
||||
if (IsEmptyProperty(property))
|
||||
{
|
||||
return default(T);
|
||||
}
|
||||
@@ -83,7 +90,7 @@ namespace Archetype.Models
|
||||
{
|
||||
var property = GetProperty(propertyAlias);
|
||||
|
||||
if (IsEmptyProperty(property))
|
||||
if (IsEmptyProperty(property))
|
||||
{
|
||||
return defaultValue;
|
||||
}
|
||||
@@ -96,7 +103,7 @@ namespace Archetype.Models
|
||||
/// </summary>
|
||||
/// <param name="property">The property.</param>
|
||||
/// <returns></returns>
|
||||
private bool IsEmptyProperty(ArchetypePropertyModel property)
|
||||
private bool IsEmptyProperty(ArchetypePropertyModel property)
|
||||
{
|
||||
return (property == null || property.Value == null || string.IsNullOrEmpty(property.Value.ToString()));
|
||||
}
|
||||
@@ -139,11 +146,26 @@ namespace Archetype.Models
|
||||
/// Is this fieldset disabled, either explicitly or by other means?
|
||||
/// </summary>
|
||||
/// <returns>true if this fieldset is disabled, false otherwise</returns>
|
||||
internal bool IsDisabled()
|
||||
internal bool IsAvailable()
|
||||
{
|
||||
return Disabled
|
||||
// explicitly disabled or implicitly disabled through publishing?
|
||||
var disabled = Disabled
|
||||
|| (ReleaseDate.HasValue && ReleaseDate > DateTime.UtcNow)
|
||||
|| (ExpireDate.HasValue && DateTime.UtcNow > ExpireDate);
|
||||
if (disabled)
|
||||
{
|
||||
// yes - the fieldset is not available
|
||||
return false;
|
||||
}
|
||||
// limitation on member group access?
|
||||
if (string.IsNullOrEmpty(AllowedMemberGroups))
|
||||
{
|
||||
// no - the fieldset is available
|
||||
return true;
|
||||
}
|
||||
// maybe - the fieldset is available if the current member is a member of the configured member groups
|
||||
var currentUserGroups = Roles.GetRolesForUser() ?? new string[0];
|
||||
return currentUserGroups.ContainsAny(AllowedMemberGroups.Split(','));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Archetype.Models
|
||||
{
|
||||
public class ArchetypeGlobalSettings
|
||||
{
|
||||
public bool CheckForUpdates { get; set; }
|
||||
public Guid Id { get; set; }
|
||||
|
||||
public Guid ApiKey = _getApiKey();
|
||||
|
||||
private static ArchetypeGlobalSettings _instance;
|
||||
|
||||
private static string _pathToConfig = @"~/Config/Archetype.config.js";
|
||||
|
||||
private static readonly string _mappedPathToConfig = IOHelper.MapPath(_pathToConfig);
|
||||
|
||||
private static object _padLock = new object();
|
||||
|
||||
private ArchetypeGlobalSettings()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public static ArchetypeGlobalSettings Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
lock (_padLock)
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = new ArchetypeGlobalSettings();
|
||||
|
||||
_loadSettingsFromConfigFile();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
lock (_padLock)
|
||||
{
|
||||
//write to JSON
|
||||
var configFileModel = new ArchetypeConfigFileModel
|
||||
{
|
||||
Id = _instance.Id,
|
||||
CheckForUpdates = _instance.CheckForUpdates
|
||||
};
|
||||
|
||||
var serializedJson = JsonConvert.SerializeObject(configFileModel, Formatting.Indented);
|
||||
|
||||
File.WriteAllText(_mappedPathToConfig, serializedJson);
|
||||
}
|
||||
}
|
||||
|
||||
private static void _loadSettingsFromConfigFile()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(_mappedPathToConfig))
|
||||
{
|
||||
//load
|
||||
var deserializedConfigFile = JsonConvert.DeserializeObject<ArchetypeConfigFileModel>(File.ReadAllText(_mappedPathToConfig));
|
||||
|
||||
if (deserializedConfigFile != null)
|
||||
{
|
||||
_instance.Id = deserializedConfigFile.Id;
|
||||
_instance.CheckForUpdates = deserializedConfigFile.CheckForUpdates;
|
||||
}
|
||||
else
|
||||
{
|
||||
_createNewConfigFile("Config file model was null!");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_createNewConfigFile("Config file was missing!");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Error<ArchetypeGlobalSettings>(ex.Message, ex);
|
||||
|
||||
_createNewConfigFile("Exception!");
|
||||
}
|
||||
}
|
||||
|
||||
private static void _createNewConfigFile(string reason)
|
||||
{
|
||||
//write a new file with defaults
|
||||
LogHelper.Info<ArchetypeGlobalSettings>(string.Format("Generating a new config file reason: {0}", reason));
|
||||
|
||||
_instance.Id = Guid.NewGuid();
|
||||
_instance.CheckForUpdates = true;
|
||||
_instance.Save();
|
||||
}
|
||||
|
||||
private static Guid _getApiKey()
|
||||
{
|
||||
//this is just obfuscation and an attempt to keep out most but not the determined hacker
|
||||
var array = new []
|
||||
{
|
||||
"RTA4MUZDRjA=",
|
||||
"NzkzQS1BRDIw",
|
||||
"OTI3QjFDNjkwQTYy",
|
||||
"MjI0OQ=="
|
||||
};
|
||||
|
||||
return new Guid(string.Format("{0}-{1}-{3}-{2}",
|
||||
_decodeBase64(array[0]),
|
||||
_decodeBase64(array[1]),
|
||||
_decodeBase64(array[2]),
|
||||
_decodeBase64(array[3])
|
||||
));
|
||||
}
|
||||
|
||||
private static string _decodeBase64(string input)
|
||||
{
|
||||
return Encoding.UTF8.GetString(Convert.FromBase64String(input));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using Archetype.TypeConverters;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
@@ -11,6 +13,7 @@ namespace Archetype.Models
|
||||
/// Model that represents an entire Archetype.
|
||||
/// </summary>
|
||||
[JsonObject]
|
||||
[TypeConverter(typeof(ArchetypeModelConverter))]
|
||||
public class ArchetypeModel : IEnumerable<ArchetypeFieldsetModel>
|
||||
{
|
||||
[JsonProperty("fieldsets")]
|
||||
@@ -32,7 +35,7 @@ namespace Archetype.Models
|
||||
/// </returns>
|
||||
public IEnumerator<ArchetypeFieldsetModel> GetEnumerator()
|
||||
{
|
||||
return this.Fieldsets.Where(f => f.IsDisabled() == false).GetEnumerator();
|
||||
return this.Fieldsets.Where(f => f.IsAvailable()).GetEnumerator();
|
||||
}
|
||||
|
||||
//possibly obsolete?
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
@@ -25,6 +25,9 @@ namespace Archetype.Models
|
||||
[JsonProperty("enableCollapsing")]
|
||||
public bool EnableCollapsing { get; set; }
|
||||
|
||||
[JsonProperty("enableMultipleOpen")]
|
||||
public bool EnableMultipleOpen { get; set; }
|
||||
|
||||
[JsonProperty("enableCloning")]
|
||||
public bool EnableCloning { get; set; }
|
||||
|
||||
@@ -34,12 +37,21 @@ namespace Archetype.Models
|
||||
[JsonProperty("enablePublishing")]
|
||||
public bool EnablePublishing { get; set; }
|
||||
|
||||
[JsonProperty("enableCrossDragging")]
|
||||
public bool EnableCrossDragging { get; set; }
|
||||
|
||||
[JsonProperty("enableMemberGroups")]
|
||||
public bool EnableMemberGroups { get; set; }
|
||||
|
||||
[JsonProperty("hideFieldsetControls")]
|
||||
public bool HideFieldsetControls { get; set; }
|
||||
|
||||
[JsonProperty("hidePropertyLabel")]
|
||||
public bool HidePropertyLabel { get; set; }
|
||||
|
||||
[JsonProperty("minFieldsets", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public int MinFieldsets { get; set; }
|
||||
|
||||
[JsonProperty("maxFieldsets", NullValueHandling = NullValueHandling.Ignore)]
|
||||
public int MaxFieldsets { get; set; }
|
||||
|
||||
|
||||
@@ -26,6 +26,9 @@ namespace Archetype.Models
|
||||
[JsonProperty("label")]
|
||||
public string Label { get; set; }
|
||||
|
||||
[JsonProperty("previewImage")]
|
||||
public string PreviewImage { get; set; }
|
||||
|
||||
[JsonProperty("properties")]
|
||||
public IEnumerable<ArchetypePreValueProperty> Properties { get; set; }
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ namespace Archetype.Models
|
||||
|
||||
public bool IsDraft
|
||||
{
|
||||
get { return _fieldset.IsDisabled(); }
|
||||
get { return _fieldset.IsAvailable() == false; }
|
||||
}
|
||||
|
||||
public PublishedItemType ItemType
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Archetype.Models
|
||||
var count = archetype.Fieldsets.Count();
|
||||
|
||||
_items = archetype.Fieldsets
|
||||
.Where(x => x.IsDisabled() == false)
|
||||
.Where(x => x.IsAvailable())
|
||||
.Select(x => new ArchetypePublishedContent(x, this))
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using Archetype.Extensions;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
|
||||
@@ -24,14 +25,22 @@ namespace Archetype.Models
|
||||
_property = property;
|
||||
_rawValue = property.Value;
|
||||
|
||||
_propertyType = property.CreateDummyPropertyType();
|
||||
// #418 - need to wrap this in a try/catch to prevent orphaned properties from breaking everything
|
||||
try
|
||||
{
|
||||
_propertyType = property.CreateDummyPropertyType();
|
||||
|
||||
if (_propertyType != null)
|
||||
{
|
||||
_sourceValue = new Lazy<object>(() => _propertyType.ConvertDataToSource(_rawValue, preview));
|
||||
_objectValue = new Lazy<object>(() => _propertyType.ConvertSourceToObject(_sourceValue.Value, preview));
|
||||
_xpathValue = new Lazy<object>(() => _propertyType.ConvertSourceToXPath(_sourceValue.Value, preview));
|
||||
}
|
||||
if (_propertyType != null)
|
||||
{
|
||||
_sourceValue = new Lazy<object>(() => _propertyType.ConvertDataToSource(_rawValue, preview));
|
||||
_objectValue = new Lazy<object>(() => _propertyType.ConvertSourceToObject(_sourceValue.Value, preview));
|
||||
_xpathValue = new Lazy<object>(() => _propertyType.ConvertSourceToXPath(_sourceValue.Value, preview));
|
||||
}
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
LogHelper.Warn<ArchetypePublishedProperty>(string.Format("Could not create an IPublishedProperty for property: {0} - the error was: {1}", property.Alias, ex.Message));
|
||||
}
|
||||
}
|
||||
|
||||
internal ArchetypePropertyModel ArchetypeProperty
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Archetype.Models
|
||||
{
|
||||
public class ArchetypeUpdateNotification
|
||||
{
|
||||
public bool IsUpdateAvailable { get; set; }
|
||||
public string Headline { get; set; }
|
||||
public string Type { get; set; }
|
||||
public string Message { get; set; }
|
||||
public string Url { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@ using System.Runtime.InteropServices;
|
||||
[assembly: AssemblyTitle("Archetype")]
|
||||
[assembly: AssemblyDescription("Archetype's supporting code library for Umbraco")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("Imulus")]
|
||||
[assembly: AssemblyCompany("Kevin Giszewski LLC")]
|
||||
[assembly: AssemblyProduct("Archetype")]
|
||||
[assembly: AssemblyCopyright("MIT Licensed")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using System.Reflection;
|
||||
|
||||
[assembly: AssemblyVersion("1.13.0")]
|
||||
[assembly: AssemblyFileVersion("1.13.0")]
|
||||
[assembly: AssemblyVersion("1.16.0")]
|
||||
[assembly: AssemblyFileVersion("1.16.0")]
|
||||
|
||||
@@ -206,13 +206,28 @@ namespace Archetype.PropertyEditors
|
||||
else if (propDef.EditorState != null && propDef.EditorState.FileNames != null && propDef.EditorState.FileNames.Any())
|
||||
{
|
||||
// pass the uploaded files that belongs to this property (if any) to the value editor
|
||||
var propertyFiles = propDef.EditorState.FileNames.Select(f => uploadedFiles.FirstOrDefault(u => u.FileName == f)).Where(f => f != null).ToList();
|
||||
var propertyFiles = propDef.EditorState.FileNames.Select(fileName =>
|
||||
uploadedFiles.FirstOrDefault(u => u.FileName != null &&
|
||||
// #384, #389 and #394 - look for "safe" file names (using the ToSafeFileName() extension)
|
||||
// - for backwards compatibility we'll look for the raw filename as well as the "safe" file name
|
||||
(u.FileName.Equals(fileName, StringComparison.OrdinalIgnoreCase) || u.FileName.Equals(fileName.ToSafeFileName(), StringComparison.OrdinalIgnoreCase))
|
||||
)
|
||||
).Where(f => f != null).ToList();
|
||||
if(propertyFiles.Any())
|
||||
{
|
||||
additionalData["files"] = propertyFiles;
|
||||
}
|
||||
}
|
||||
}
|
||||
// #397 - pass along "cuid" and "puid" (part of the Umbraco 7.6 scheme)
|
||||
if(editorValue.AdditionalData.ContainsKey("cuid"))
|
||||
{
|
||||
additionalData["cuid"] = editorValue.AdditionalData["cuid"];
|
||||
}
|
||||
if(editorValue.AdditionalData.ContainsKey("puid"))
|
||||
{
|
||||
additionalData["puid"] = editorValue.AdditionalData["puid"];
|
||||
}
|
||||
var propData = new ContentPropertyData(propDef.Value, preValues, additionalData);
|
||||
var propEditor = PropertyEditorResolver.Current.GetByAlias(dtd.PropertyEditorAlias);
|
||||
// make sure to send the current property value (if any) to the PE ValueEditor
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using Archetype.Extensions;
|
||||
using Archetype.Models;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Archetype.TypeConverters
|
||||
{
|
||||
public class ArchetypeFieldsetModelConverter : TypeConverter
|
||||
{
|
||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
||||
{
|
||||
if (destinationType == typeof(IPublishedContent) ||
|
||||
destinationType == typeof(ArchetypePublishedContent))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (destinationType == typeof(string))
|
||||
{
|
||||
// NOTE: The converter needs to return false here, otherwise `ArchetypeHelper.DeserializeJsonToArchetype` fails.
|
||||
return false;
|
||||
}
|
||||
|
||||
return base.CanConvertTo(context, destinationType);
|
||||
}
|
||||
|
||||
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
|
||||
{
|
||||
if (value is ArchetypeFieldsetModel && (destinationType == typeof(IPublishedContent) || destinationType == typeof(ArchetypePublishedContent)))
|
||||
{
|
||||
return ((ArchetypeFieldsetModel)value).ToPublishedContent();
|
||||
}
|
||||
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using Archetype.Extensions;
|
||||
using Archetype.Models;
|
||||
using Umbraco.Core.Models;
|
||||
|
||||
namespace Archetype.TypeConverters
|
||||
{
|
||||
public class ArchetypeModelConverter : TypeConverter
|
||||
{
|
||||
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
|
||||
{
|
||||
if (destinationType == typeof(ArchetypePublishedContentSet) ||
|
||||
destinationType == typeof(IEnumerable<IPublishedContent>))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.CanConvertTo(context, destinationType);
|
||||
}
|
||||
|
||||
public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
|
||||
{
|
||||
if (value is ArchetypeModel && (destinationType == typeof(ArchetypePublishedContentSet) || destinationType == typeof(IEnumerable<IPublishedContent>)))
|
||||
{
|
||||
return ((ArchetypeModel)value).ToPublishedContentSet();
|
||||
}
|
||||
|
||||
return base.ConvertTo(context, culture, value, destinationType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
angular.module("umbraco").controller("Imulus.ArchetypeConfigController", function ($scope, $http, assetsService, dialogService, archetypePropertyEditorResource) {
|
||||
angular.module("umbraco").controller("Imulus.ArchetypeConfigController", function ($scope, $http, assetsService, dialogService, archetypePropertyEditorResource, archetypeGlobalConfigService, notificationsService) {
|
||||
|
||||
//$scope.model.value = "";
|
||||
//console.log($scope.model.value);
|
||||
@@ -6,7 +6,7 @@ angular.module("umbraco").controller("Imulus.ArchetypeConfigController", functio
|
||||
//define empty items
|
||||
var newPropertyModel = '{"alias": "", "remove": false, "collapse": false, "label": "", "helpText": "", "dataTypeGuid": "0cc0eba1-9960-42c9-bf9b-60e150b429ae", "value": ""}';
|
||||
var newFieldsetModel = '{"alias": "", "remove": false, "collapse": false, "labelTemplate": "", "icon": "", "label": "", "properties": [' + newPropertyModel + '], "group": null}';
|
||||
var defaultFieldsetConfigModel = JSON.parse('{"showAdvancedOptions": false, "startWithAddButton": false, "hideFieldsetToolbar": false, "enableMultipleFieldsets": false, "hideFieldsetControls": false, "hidePropertyLabel": false, "maxFieldsets": null, "enableCollapsing": true, "enableCloning": false, "enableDisabling": true, "enableDeepDatatypeRequests": false, "enablePublishing": false, "fieldsets": [' + newFieldsetModel + '], "fieldsetGroups": []}');
|
||||
var defaultFieldsetConfigModel = JSON.parse('{"showAdvancedOptions": false, "startWithAddButton": false, "hideFieldsetToolbar": false, "enableMultipleFieldsets": false, "hideFieldsetControls": false, "hidePropertyLabel": false, "maxFieldsets": null, "enableCollapsing": true, "enableMultipleOpen": true, "enableCloning": false, "enableDisabling": true, "enableDeepDatatypeRequests": false, "enablePublishing": false, "enableMemberGroups": false, "enableCrossDragging": false, "fieldsets": [' + newFieldsetModel + '], "fieldsetGroups": []}');
|
||||
|
||||
//ini the model
|
||||
$scope.model.value = $scope.model.value || defaultFieldsetConfigModel;
|
||||
@@ -16,6 +16,17 @@ angular.module("umbraco").controller("Imulus.ArchetypeConfigController", functio
|
||||
archetypePropertyEditorResource.getDllVersion().then(function(data){
|
||||
$scope.dllVersion = data.dllVersion;
|
||||
});
|
||||
|
||||
archetypeGlobalConfigService.checkForUpdates().then(function(data) {
|
||||
if(data.isUpdateAvailable) {
|
||||
notificationsService.add({
|
||||
headline: data.headline,
|
||||
type: data.type,
|
||||
message: data.message,
|
||||
url: data.url
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
//ini the render model
|
||||
initConfigRenderModel();
|
||||
@@ -47,6 +58,12 @@ angular.module("umbraco").controller("Imulus.ArchetypeConfigController", functio
|
||||
}
|
||||
};
|
||||
|
||||
// added to track loaded fieldsets
|
||||
$scope.loadedFieldsets = [];
|
||||
$scope.isLoaded = function (fieldset) {
|
||||
return $scope.loadedFieldsets.indexOf(fieldset) >= 0;
|
||||
}
|
||||
|
||||
//function that determines how to manage expanding/collapsing fieldsets
|
||||
$scope.focusFieldset = function(fieldset){
|
||||
var iniState;
|
||||
@@ -60,6 +77,7 @@ angular.module("umbraco").controller("Imulus.ArchetypeConfigController", functio
|
||||
if($scope.archetypeConfigRenderModel.fieldsets.length == 1 && fieldset.remove == false)
|
||||
{
|
||||
fieldset.collapse = false;
|
||||
$scope.loadedFieldsets.push(fieldset);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -70,12 +88,14 @@ angular.module("umbraco").controller("Imulus.ArchetypeConfigController", functio
|
||||
else
|
||||
{
|
||||
fieldset.collapse = false;
|
||||
$scope.loadedFieldsets.push(fieldset);
|
||||
}
|
||||
});
|
||||
|
||||
if(iniState)
|
||||
{
|
||||
fieldset.collapse = !iniState;
|
||||
$scope.loadedFieldsets.push(fieldset);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,27 +143,20 @@ angular.module("umbraco").controller("Imulus.ArchetypeConfigController", functio
|
||||
|
||||
//watch for changes
|
||||
$scope.$watch('archetypeConfigRenderModel', function (v) {
|
||||
//console.log(v);
|
||||
if (typeof v === 'string') {
|
||||
$scope.archetypeConfigRenderModel = JSON.parse(v);
|
||||
$scope.archetypeConfigRenderModel.toString = stringify;
|
||||
}
|
||||
});
|
||||
|
||||
$scope.autoPopulateAlias = function(s) {
|
||||
var modelType = s.hasOwnProperty('fieldset') ? 'fieldset' : 'property';
|
||||
var modelProperty = s[modelType];
|
||||
|
||||
if (!modelProperty.aliasIsDirty) {
|
||||
$scope.autoPopulateAlias = function (modelProperty) {
|
||||
if (modelProperty && !modelProperty.aliasIsDirty) {
|
||||
modelProperty.alias = modelProperty.label.toUmbracoAlias();
|
||||
}
|
||||
}
|
||||
|
||||
$scope.markAliasDirty = function(s) {
|
||||
var modelType = s.hasOwnProperty('fieldset') ? 'fieldset' : 'property';
|
||||
var modelProperty = s[modelType];
|
||||
|
||||
if (!modelProperty.aliasIsDirty) {
|
||||
$scope.markAliasDirty = function (modelProperty) {
|
||||
if (modelProperty && !modelProperty.aliasIsDirty) {
|
||||
modelProperty.aliasIsDirty = true;;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
angular.module('umbraco').controller('ArchetypeConfigOptionsController', function ($scope) {
|
||||
|
||||
//handles a fieldset group add
|
||||
$scope.addFieldsetGroup = function () {
|
||||
$scope.dialogData.model.fieldsetGroups.push({ name: "" });
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
angular.module('umbraco').controller('ArchetypeConfigGlobalOptionsController', function ($scope, archetypeGlobalConfigService) {
|
||||
$scope.globalSettings = {};
|
||||
|
||||
$scope.confirmCheckNewVersionChange = function() {
|
||||
archetypeGlobalConfigService.setCheckForUpdates($scope.globalSettings.checkForNewVersion);
|
||||
}
|
||||
|
||||
function getGlobalSettings()
|
||||
{
|
||||
archetypeGlobalConfigService.globalSettings().then(function(data) {
|
||||
$scope.globalSettings.checkForNewVersion = data.isCheckingForUpdates;
|
||||
});
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
function init()
|
||||
{
|
||||
getGlobalSettings();
|
||||
}
|
||||
});
|
||||
+402
-53
@@ -1,5 +1,8 @@
|
||||
{{VERSION}}
|
||||
angular.module("umbraco").controller("Imulus.ArchetypeController", function ($scope, $http, $filter, assetsService, angularHelper, notificationsService, $timeout, fileManager, entityResource, archetypeService, archetypeLabelService, archetypeCacheService, archetypePropertyEditorResource) {
|
||||
angular.module("umbraco").controller("Imulus.ArchetypeController", function ($scope, $http, $filter, $interpolate, assetsService, angularHelper, notificationsService, $timeout, fileManager, entityResource, archetypeService, archetypeLabelService, archetypeCacheService, archetypePropertyEditorResource, archetypeLocalizationService) {
|
||||
|
||||
// Variables.
|
||||
var draggedParent;
|
||||
|
||||
//$scope.model.value = "";
|
||||
$scope.model.hideLabel = $scope.model.config.hideLabel == 1;
|
||||
@@ -43,36 +46,211 @@ angular.module("umbraco").controller("Imulus.ArchetypeController", function ($sc
|
||||
return archetypeLabelService.getFieldsetTitle($scope, fieldsetConfigModel, fieldsetIndex);
|
||||
}
|
||||
|
||||
var draggedRteSettings;
|
||||
var rteClass = ".umb-rte textarea";
|
||||
|
||||
//sort config
|
||||
$scope.sortableOptions = {
|
||||
axis: 'y',
|
||||
cursor: "move",
|
||||
handle: ".handle",
|
||||
tolerance: "pointer",
|
||||
activate: function(ev, ui) {
|
||||
|
||||
// Variables.
|
||||
var parentItem = ui.item.parent();
|
||||
var thisElement = parentItem[0];
|
||||
var targetElement = ev.target;
|
||||
var targetItem = angular.element(targetElement);
|
||||
|
||||
// The source of the drag can always be dropped back onto.
|
||||
if (targetElement === thisElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Variables.
|
||||
var sourceScope = ui.item.scope();
|
||||
var targetScope = targetItem.scope();
|
||||
var valid = canMove(sourceScope, targetScope);
|
||||
|
||||
// If the sortable can't be moved to the target Archetype, disable
|
||||
// the target Archetype's sortable temporarily.
|
||||
if (!valid) {
|
||||
var targetSortable = getSortableWidgetInstance(targetItem);
|
||||
targetSortable.disable();
|
||||
parentItem.sortable("refresh");
|
||||
archetypeService.rememberDisabledSortable(targetSortable);
|
||||
}
|
||||
|
||||
},
|
||||
start: function(ev, ui) {
|
||||
draggedRteSettings = {};
|
||||
$(rteClass, ui.item.parent()).each(function () {
|
||||
var id = $(this).attr("id");
|
||||
draggedRteSettings[id] = _.findWhere(tinyMCE.editors, { id: id }).settings;
|
||||
tinymce.execCommand('mceRemoveEditor', false, id);
|
||||
$(this).css("visibility", "hidden");
|
||||
archetypeService.storeEditors(ui.item.parent());
|
||||
$scope.$apply(function() {
|
||||
draggedParent = ui.item.parent();
|
||||
draggedParent.scope().doingSort = true;
|
||||
});
|
||||
},
|
||||
update: function (ev, ui) {
|
||||
|
||||
// Variables.
|
||||
var targetScope = ui.item.sortable.droptarget.scope();
|
||||
var sourceScope = ui.item.scope();
|
||||
var sameScope = sourceScope === targetScope;
|
||||
var sourceIndex = ui.item.sortable.index;
|
||||
|
||||
// Special constraints for when moving between Archetypes.
|
||||
// If sourceScope is populated, we are in the first of the two updates (when
|
||||
// moving between lists, ui-sortable calls the update function twice).
|
||||
if (sourceScope && !sameScope) {
|
||||
|
||||
// Variables.
|
||||
var valid = canMove(sourceScope, targetScope);
|
||||
|
||||
// If update isn't allowed, cancel the drag operation.
|
||||
if (!valid) {
|
||||
ui.item.sortable.cancel();
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear the validations for this item.
|
||||
clearValidations(ui.item.parent());
|
||||
clearValidations(ui.item.sortable.droptarget);
|
||||
|
||||
// Reset "isValid" on the properties and fieldsets.
|
||||
var fieldsetGroups = [
|
||||
$scope.model.value.fieldsets,
|
||||
targetScope.model.value.fieldsets
|
||||
];
|
||||
_.each(fieldsetGroups, function(fieldsets) {
|
||||
recurseProperties(function(property, fieldset) {
|
||||
property.isValid = true;
|
||||
fieldset.isValid = true;
|
||||
}, fieldsets);
|
||||
});
|
||||
|
||||
// Move the activated fieldset to the target Archetype.
|
||||
var movedFieldset = $scope.model.value.fieldsets[sourceIndex];
|
||||
var loadedIndex = $scope.loadedFieldsets.indexOf(movedFieldset);
|
||||
if (loadedIndex >= 0) {
|
||||
$scope.loadedFieldsets.splice(loadedIndex, 1);
|
||||
if (targetScope.loadedFieldsets.indexOf(movedFieldset) < 0) {
|
||||
targetScope.loadedFieldsets.push(movedFieldset);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Set scope dirty.
|
||||
$scope.setDirty();
|
||||
|
||||
},
|
||||
stop: function (ev, ui) {
|
||||
$(rteClass, ui.item.parent()).each(function () {
|
||||
var id = $(this).attr("id");
|
||||
draggedRteSettings[id] = draggedRteSettings[id] || _.findWhere(tinyMCE.editors, { id: id }).settings;
|
||||
tinyMCE.execCommand("mceRemoveEditor", false, id);
|
||||
tinyMCE.init(draggedRteSettings[id]);
|
||||
});
|
||||
|
||||
// Done sorting.
|
||||
draggedParent.scope().doingSort = false;
|
||||
|
||||
// Enable disabled sortables.
|
||||
archetypeService.enableSortables();
|
||||
|
||||
// Restore rich text editors.
|
||||
var parent = null;
|
||||
var target = ui.item.sortable.droptarget;
|
||||
if (target) {
|
||||
parent = target.parent();
|
||||
}
|
||||
archetypeService.restoreEditors(parent);
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// Clears the Angular validations in an Archetype.
|
||||
function clearValidations(el) {
|
||||
var combined = $(".archetypeSortable", el).add(el);
|
||||
combined.each(function(index, item) {
|
||||
var $item = angular.element(item);
|
||||
var cont = $item.controller("ngModel");
|
||||
var err = cont.$error;
|
||||
var keys = Object.keys(err);
|
||||
for (var i = 0; i < keys.length; i++) {
|
||||
cont.$setValidity(keys[i], true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Enable cross-archetype dragging?
|
||||
if ($scope.model.config.enableCrossDragging) {
|
||||
$scope.sortableOptions.connectWith = ".archetypeSortable:not(.invalid)";
|
||||
}
|
||||
|
||||
// Checks if the specified model's properties match all of the properties in any of
|
||||
// the specified fieldsets, while also checking if the fieldset aliases match.
|
||||
// This is an indicator of the compatibility of a fieldset model with a collection
|
||||
// of fieldset configurations.
|
||||
function modelMatchesAnyFieldset(model, fieldsets) {
|
||||
|
||||
// Loop through fieldsets to find a match.
|
||||
for (var i = 0; i < fieldsets.length; i++) {
|
||||
var fieldset = fieldsets[i];
|
||||
|
||||
// Confirm that this configured fielset contains exactly
|
||||
// the same properties as those that were supplied.
|
||||
var valid =
|
||||
// Does the alias match?
|
||||
model.alias === fieldset.alias &&
|
||||
// Does this fieldset have all the properties?
|
||||
arePropertiesSubset(model.properties, fieldset.properties) &&
|
||||
// Does the property array have all the fieldset properties?
|
||||
arePropertiesSubset(fieldset.properties, model.properties);
|
||||
|
||||
// Match found?
|
||||
if (valid) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// No match found.
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// Checks if the specified array of fieldsets contains the specified fieldset.
|
||||
function arrayContainsFieldset(fieldset, fieldsets) {
|
||||
for (var i = 0; i < fieldsets.length; i++) {
|
||||
if (fieldsets[i] === fieldset) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Confirms that an array of properties is a subset of another array of properties.
|
||||
function arePropertiesSubset(subset, superset) {
|
||||
|
||||
// Loop through the subset of properties.
|
||||
for (var j = 0; j < subset.length; j++) {
|
||||
var subProperty = subset[j];
|
||||
var matchedProp = false;
|
||||
|
||||
// Loop through the superset to find a matching property from the subset.
|
||||
for (var k = 0; k < superset.length; k++) {
|
||||
var superProperty = superset[k];
|
||||
if (superProperty.alias === subProperty.alias &&
|
||||
superProperty.dataTypeGuid === subProperty.dataTypeGuid) {
|
||||
matchedProp = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If no matching property could be found, the array is not a subset.
|
||||
if (!matchedProp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// The array is a subset.
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
//handles a fieldset add
|
||||
$scope.openFieldsetPicker = function ($index, event) {
|
||||
if ($scope.canAdd() == false) {
|
||||
@@ -86,7 +264,8 @@ angular.module("umbraco").controller("Imulus.ArchetypeController", function ($sc
|
||||
alias: fieldset.alias,
|
||||
label: fieldset.label,
|
||||
icon: (fieldset.icon || "icon-document-dashed-line"), // default icon if none is chosen
|
||||
group: fieldset.group ? fieldset.group.name : null
|
||||
group: fieldset.group ? fieldset.group.name : null,
|
||||
previewImage: fieldset.previewImage
|
||||
});
|
||||
});
|
||||
// sanity check
|
||||
@@ -126,13 +305,22 @@ angular.module("umbraco").controller("Imulus.ArchetypeController", function ($sc
|
||||
|
||||
$scope.closeFieldsetPicker = function () {
|
||||
$scope.overlayMenu.show = false;
|
||||
$scope.overlayMenu.fieldsetPreview = null;
|
||||
};
|
||||
|
||||
$scope.pickFieldset = function (fieldsetAlias, $index) {
|
||||
$scope.closeFieldsetPicker();
|
||||
$scope.addRow(fieldsetAlias, $index);
|
||||
};
|
||||
|
||||
|
||||
$scope.openFieldsetPreview = function (fieldset) {
|
||||
$scope.overlayMenu.fieldsetPreview = fieldset;
|
||||
}
|
||||
|
||||
$scope.closeFieldsetPreview = function () {
|
||||
$scope.overlayMenu.fieldsetPreview = null;
|
||||
}
|
||||
|
||||
$scope.addRow = function (fieldsetAlias, $index) {
|
||||
if ($scope.canAdd()) {
|
||||
if ($scope.model.config.fieldsets) {
|
||||
@@ -155,8 +343,14 @@ angular.module("umbraco").controller("Imulus.ArchetypeController", function ($sc
|
||||
$scope.$broadcast("archetypeAddFieldset", {index: $index, visible: countVisible()});
|
||||
|
||||
newFieldset.collapse = $scope.model.config.enableCollapsing ? true : false;
|
||||
|
||||
// If the fieldset is not collapsed, it should be instantly loaded.
|
||||
if (!newFieldset.collapse) {
|
||||
$scope.loadedFieldsets.push(newFieldset);
|
||||
}
|
||||
|
||||
$scope.focusFieldset(newFieldset);
|
||||
$scope.handleMandatoryValidation();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,6 +360,7 @@ angular.module("umbraco").controller("Imulus.ArchetypeController", function ($sc
|
||||
$scope.setDirty();
|
||||
$scope.model.value.fieldsets.splice($index, 1);
|
||||
$scope.$broadcast("archetypeRemoveFieldset", {index: $index});
|
||||
$scope.handleMandatoryValidation();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,11 +371,24 @@ angular.module("umbraco").controller("Imulus.ArchetypeController", function ($sc
|
||||
|
||||
if(newFieldset) {
|
||||
|
||||
// Regenerate the temporary ID on each nested fieldset.
|
||||
// This is done because no two fieldsets should have the same
|
||||
// temporary ID.
|
||||
recurseProperties(function(property) {
|
||||
archetypeService.ensureTemporaryId(property, true);
|
||||
}, [newFieldset]);
|
||||
|
||||
$scope.model.value.fieldsets.splice($index + 1, 0, newFieldset);
|
||||
|
||||
$scope.setDirty();
|
||||
|
||||
newFieldset.collapse = $scope.model.config.enableCollapsing ? true : false;
|
||||
|
||||
// If the fieldset is not collapsed, it should be instantly loaded.
|
||||
if (!newFieldset.collapse) {
|
||||
$scope.loadedFieldsets.push(newFieldset);
|
||||
}
|
||||
|
||||
$scope.focusFieldset(newFieldset);
|
||||
}
|
||||
}
|
||||
@@ -190,24 +398,27 @@ angular.module("umbraco").controller("Imulus.ArchetypeController", function ($sc
|
||||
fieldset.disabled = !fieldset.disabled;
|
||||
// explicitly set the form as dirty when manipulating the enabled/disabled state of a fieldset
|
||||
$scope.setDirty();
|
||||
$scope.handleMandatoryValidation();
|
||||
}
|
||||
|
||||
//helpers for determining if a user can do something
|
||||
$scope.canAdd = function () {
|
||||
if ($scope.model.config.maxFieldsets)
|
||||
{
|
||||
return countVisible() < $scope.model.config.maxFieldsets;
|
||||
var visibleCount = countVisible();
|
||||
var maxFieldsets = $scope.model.config.maxFieldsets;
|
||||
return visibleCount < maxFieldsets;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
//helper that returns if an item can be removed
|
||||
$scope.canRemove = function () {
|
||||
return countVisible() > 1
|
||||
|| ($scope.model.config.maxFieldsets == 1 && $scope.model.config.fieldsets.length > 1)
|
||||
|| $scope.model.config.startWithAddButton;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.canClone = function () {
|
||||
|
||||
@@ -226,8 +437,16 @@ angular.module("umbraco").controller("Imulus.ArchetypeController", function ($sc
|
||||
//helper that returns if an item can be sorted
|
||||
$scope.canSort = function ()
|
||||
{
|
||||
return countVisible() > 1;
|
||||
}
|
||||
// Sorting can occur if there are multiple fieldsets, or if there is only one
|
||||
// fieldset that can be removed (in which case it can be sorted into an entirely
|
||||
// different Archetype).
|
||||
return countVisible() > 1 || $scope.canRemove();
|
||||
};
|
||||
|
||||
//helper that returns if an item is the last and it's being sorted.
|
||||
$scope.sortingLastItem = function() {
|
||||
return $scope.doingSort && $scope.model.value.fieldsets.length <= 1;
|
||||
};
|
||||
|
||||
//helper that returns if an item can be disabled
|
||||
$scope.canDisable = function () {
|
||||
@@ -246,10 +465,14 @@ angular.module("umbraco").controller("Imulus.ArchetypeController", function ($sc
|
||||
return $scope.model.config.enablePublishing;
|
||||
}
|
||||
|
||||
$scope.canUseMemberGroups = function() {
|
||||
return $scope.model.config.enableMemberGroups;
|
||||
}
|
||||
|
||||
//helper that returns if the "misc fieldset configuration" section should be visible
|
||||
$scope.canConfigure = function () {
|
||||
// currently the only thing in the "misc fieldset configuration" section is the publishing setup
|
||||
return $scope.canPublish();
|
||||
// currently the "misc fieldset configuration" section contains the publishing and the member groups setup
|
||||
return $scope.canPublish() || $scope.canUseMemberGroups();
|
||||
}
|
||||
|
||||
$scope.showDisableIcon = function (fieldset) {
|
||||
@@ -301,10 +524,30 @@ angular.module("umbraco").controller("Imulus.ArchetypeController", function ($sc
|
||||
return $scope.isDisabledByPublishing(fieldset);
|
||||
}
|
||||
|
||||
$scope.numberOfEnabledFieldsets = function () {
|
||||
if (!$scope.model.value.fieldsets) {
|
||||
return 0;
|
||||
}
|
||||
return _.filter($scope.model.value.fieldsets, function (f) {
|
||||
return $scope.isDisabled(f) == false;
|
||||
}).length;
|
||||
}
|
||||
|
||||
//helper, ini the render model from the server (model.value)
|
||||
function init() {
|
||||
$scope.model.value = removeNulls($scope.model.value);
|
||||
addDefaultProperties($scope.model.value.fieldsets);
|
||||
|
||||
$timeout(function () {
|
||||
$scope.handleMandatoryValidation();
|
||||
}, 50);
|
||||
|
||||
// localize the message for minimum fieldsets validation errors
|
||||
archetypeLocalizationService.localize("minFieldsetsMessage").then(function (value) {
|
||||
value = value || "You must add minimum {{minFieldsets}} items";
|
||||
var exp = $interpolate(value);
|
||||
$scope.minFieldsetsMessage = exp({ minFieldsets: $scope.model.config.minFieldsets });
|
||||
});
|
||||
}
|
||||
|
||||
function addDefaultProperties(fieldsets)
|
||||
@@ -338,6 +581,12 @@ angular.module("umbraco").controller("Imulus.ArchetypeController", function ($sc
|
||||
view: "datepicker",
|
||||
value: fromUtc(fieldset.expireDate)
|
||||
};
|
||||
// create model for allowed member groups
|
||||
fieldset.allowedMemberGroupsModel = {
|
||||
alias: _.uniqueId("archetypeAllowedMemberGroups_"),
|
||||
view: "membergrouppicker",
|
||||
value: fieldset.allowedMemberGroups
|
||||
};
|
||||
}
|
||||
|
||||
//helper to get the correct fieldset from config
|
||||
@@ -359,10 +608,10 @@ angular.module("umbraco").controller("Imulus.ArchetypeController", function ($sc
|
||||
{
|
||||
if(typeof fieldset.collapse === "undefined")
|
||||
{
|
||||
fieldset.collapse = true;
|
||||
fieldset.collapse = $scope.model.config.enableCollapsing ? true : false;
|
||||
}
|
||||
return fieldset.collapse;
|
||||
}
|
||||
};
|
||||
|
||||
// added to track loaded fieldsets
|
||||
$scope.loadedFieldsets = [];
|
||||
@@ -378,17 +627,17 @@ angular.module("umbraco").controller("Imulus.ArchetypeController", function ($sc
|
||||
return;
|
||||
}
|
||||
|
||||
var iniState;
|
||||
|
||||
if(fieldset)
|
||||
// collapse all other fieldsets if "multiple open fieldsets" is not enabled
|
||||
if(!$scope.model.config.enableMultipleOpen)
|
||||
{
|
||||
iniState = fieldset.collapse;
|
||||
_.each($scope.model.value.fieldsets, function (f) {
|
||||
if(f != fieldset)
|
||||
{
|
||||
f.collapse = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_.each($scope.model.value.fieldsets, function(fieldset){
|
||||
fieldset.collapse = true;
|
||||
});
|
||||
|
||||
if(!fieldset && $scope.model.value.fieldsets.length == 1)
|
||||
{
|
||||
$scope.model.value.fieldsets[0].collapse = false;
|
||||
@@ -396,16 +645,25 @@ angular.module("umbraco").controller("Imulus.ArchetypeController", function ($sc
|
||||
return;
|
||||
}
|
||||
|
||||
if(iniState && fieldset)
|
||||
if(fieldset)
|
||||
{
|
||||
fieldset.collapse = !iniState;
|
||||
$scope.loadedFieldsets.push(fieldset);
|
||||
fieldset.collapse = !fieldset.collapse;
|
||||
if($scope.loadedFieldsets.indexOf(fieldset) < 0)
|
||||
{
|
||||
$scope.loadedFieldsets.push(fieldset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//ini the fieldset expand/collapse
|
||||
$scope.focusFieldset();
|
||||
|
||||
// Fieldsets which cannot be collapsed should start expanded.
|
||||
_.each($scope.model.value.fieldsets, function(fieldset) {
|
||||
fieldset.collapse = $scope.model.config.enableCollapsing;
|
||||
});
|
||||
$scope.loadedFieldsets = _.where($scope.model.value.fieldsets, { collapse: false });
|
||||
|
||||
//developerMode helpers
|
||||
$scope.model.value.toString = stringify;
|
||||
|
||||
@@ -457,6 +715,9 @@ angular.module("umbraco").controller("Imulus.ArchetypeController", function ($sc
|
||||
$scope.activeSubmitWatcher = 0;
|
||||
|
||||
// init loaded fieldsets tracking
|
||||
_.each($scope.model.value.fieldsets, function (fieldset) {
|
||||
fieldset.collapse = $scope.model.config.enableCollapsing ? true : false;
|
||||
});
|
||||
$scope.loadedFieldsets = _.where($scope.model.value.fieldsets, { collapse: false });
|
||||
|
||||
// create properties needed for the backoffice to work (data that is not serialized to DB)
|
||||
@@ -521,24 +782,21 @@ angular.module("umbraco").controller("Imulus.ArchetypeController", function ($sc
|
||||
|
||||
//helper to lookup validity when given a fieldset
|
||||
$scope.getFieldsetValidity = function (fieldset) {
|
||||
if (fieldset.isValid == false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// recursive validation of nested fieldsets
|
||||
var nestedFieldsetsValid = true;
|
||||
_.each(fieldset.properties, function (property) {
|
||||
if (property != null && property.value != null && property.propertyEditorAlias == "Imulus.Archetype") {
|
||||
_.each(property.value.fieldsets, function (inner) {
|
||||
if ($scope.getFieldsetValidity(inner) == false) {
|
||||
nestedFieldsetsValid = false;
|
||||
}
|
||||
});
|
||||
// Variables.
|
||||
var valid = true;
|
||||
|
||||
// Recursive validation of nested fieldsets.
|
||||
recurseFieldsets(function(item) {
|
||||
if (item.isValid === false) {
|
||||
valid = false;
|
||||
}
|
||||
});
|
||||
}, [fieldset]);
|
||||
|
||||
return nestedFieldsetsValid;
|
||||
}
|
||||
// Were all the nested fieldsets valid?
|
||||
return valid;
|
||||
|
||||
};
|
||||
|
||||
// helper to force the current form into the dirty state
|
||||
$scope.setDirty = function () {
|
||||
@@ -547,6 +805,13 @@ angular.module("umbraco").controller("Imulus.ArchetypeController", function ($sc
|
||||
}
|
||||
}
|
||||
|
||||
$scope.minFieldsetsFulfilled = function () {
|
||||
if (!$scope.model.config.minFieldsets) {
|
||||
return true;
|
||||
}
|
||||
return $scope.numberOfEnabledFieldsets() >= $scope.model.config.minFieldsets;
|
||||
}
|
||||
|
||||
//custom js
|
||||
if ($scope.model.config.customJsPath) {
|
||||
assetsService.loadJs($scope.model.config.customJsPath);
|
||||
@@ -581,9 +846,21 @@ angular.module("umbraco").controller("Imulus.ArchetypeController", function ($sc
|
||||
// extract the publish configuration from the fieldsets (and convert local datetimes to UTC)
|
||||
fieldset.releaseDate = toUtc(fieldset.releaseDateModel.value);
|
||||
fieldset.expireDate = toUtc(fieldset.expireDateModel.value);
|
||||
// extract the allowed member groups
|
||||
fieldset.allowedMemberGroups = fieldset.allowedMemberGroupsModel.value;
|
||||
});
|
||||
});
|
||||
|
||||
// handle mandatory validation of the entire Archetype
|
||||
// - no fieldsets = not valid
|
||||
$scope.handleMandatoryValidation = function() {
|
||||
var valid = true;
|
||||
if ($scope.model.validation && $scope.model.validation.mandatory) {
|
||||
valid = $scope.numberOfEnabledFieldsets() > 0;
|
||||
}
|
||||
$scope.model.mandatoryValidation = valid ? "valid" : null;
|
||||
}
|
||||
|
||||
function toUtc(date) {
|
||||
if (!date) {
|
||||
return null;
|
||||
@@ -597,4 +874,76 @@ angular.module("umbraco").controller("Imulus.ArchetypeController", function ($sc
|
||||
}
|
||||
return moment(moment.utc(date).toDate()).format("YYYY-MM-DD HH:mm:ss")
|
||||
}
|
||||
|
||||
// Serializes and deserializes an item to return a snapshot of that item (e.g., so it is not
|
||||
// changed before being inspected). Useful when troubleshooting.
|
||||
// Modified from: http://stackoverflow.com/a/11616993/2052963
|
||||
function jsonSnapshot(item) {
|
||||
var cache = [];
|
||||
var stringItem = JSON.stringify(item, function(key, value) {
|
||||
if (typeof value === "object" && value !== null) {
|
||||
if (cache.indexOf(value) !== -1) {
|
||||
return "[Removed Circular Reference Item]";
|
||||
}
|
||||
cache.push(value);
|
||||
}
|
||||
return value;
|
||||
});
|
||||
return JSON.parse(stringItem);
|
||||
}
|
||||
|
||||
// Recursively processes each Archetype fieldset.
|
||||
function recurseFieldsets(fn, fieldsets) {
|
||||
if (!fieldsets || !fieldsets.length) {
|
||||
return;
|
||||
}
|
||||
_.each(fieldsets, function(fieldset) {
|
||||
fn(fieldset);
|
||||
_.each(fieldset.properties, function (property) {
|
||||
if (property != null && property.value != null && property.propertyEditorAlias === "Imulus.Archetype") {
|
||||
recurseFieldsets(fn, property.value.fieldsets);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Recursively processes each Archetype fieldset property.
|
||||
function recurseProperties(fn, fieldsets) {
|
||||
recurseFieldsets(function(fieldset) {
|
||||
_.each(fieldset.properties, function (property) {
|
||||
fn(property, fieldset);
|
||||
});
|
||||
}, fieldsets);
|
||||
}
|
||||
|
||||
// Indicates whether or not the fieldset can be moved between the source and target scope.
|
||||
// The source scope is the scope of the fieldset being dragged.
|
||||
// The target scope is the scope of the Archetype to drop into.
|
||||
function canMove(sourceScope, targetScope) {
|
||||
var targetFieldsetConfigs = targetScope.model.config.fieldsets;
|
||||
var targetFieldsets = targetScope.model.value.fieldsets;
|
||||
var sourceFieldset = sourceScope.fieldset;
|
||||
var sameArchetype = arrayContainsFieldset(sourceFieldset, targetFieldsets);
|
||||
var model = sourceScope.fieldsetConfigModel;
|
||||
var canRemove = sourceScope.canRemove();
|
||||
var canAdd = targetScope.canAdd();
|
||||
var valid = sameArchetype || (canRemove && canAdd);
|
||||
valid = valid && modelMatchesAnyFieldset(model, targetFieldsetConfigs);
|
||||
return valid;
|
||||
}
|
||||
|
||||
// This is an alternative to: element.sortable("instance")
|
||||
// Workaround for this issue: https://github.com/imulus/Archetype/pull/356#issuecomment-218527910
|
||||
// Snagged from this pull request: https://github.com/angular-ui/ui-sortable/pull/319
|
||||
// More technical details here: https://github.com/angular-ui/ui-sortable/issues/316
|
||||
function getSortableWidgetInstance(element) {
|
||||
// this is a fix to support jquery-ui prior to v1.11.x
|
||||
// otherwise we should be using `element.sortable('instance')`
|
||||
var data = element.data('ui-sortable');
|
||||
if (data && typeof data === 'object' && data.widgetFullName === 'ui-sortable') {
|
||||
return data;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -65,15 +65,22 @@ angular.module("umbraco.directives").directive('archetypeProperty', function ($c
|
||||
|
||||
if (!scope.renderModelPropertyIndex)
|
||||
{
|
||||
archetypeService.getFieldset(scope).properties.push(JSON.parse('{"alias": "' + alias + '", "value": "' + defaultValue + '"}'));
|
||||
var propertyValue = { alias: alias, value: defaultValue };
|
||||
archetypeService.getFieldset(scope).properties.push(propertyValue);
|
||||
scope.renderModelPropertyIndex = archetypeService.getPropertyIndexByAlias(archetypeService.getFieldset(scope).properties, alias);
|
||||
}
|
||||
|
||||
scope.renderModel = {};
|
||||
scope.model.value = archetypeService.getFieldsetProperty(scope).value;
|
||||
|
||||
//init the property editor state
|
||||
archetypeService.getFieldsetProperty(scope).editorState = {};
|
||||
// init the property editor state (while ensuring the temporary ID is retained
|
||||
// from any prior initializations).
|
||||
var fieldsetProperty = archetypeService.getFieldsetProperty(scope);
|
||||
var oldState = fieldsetProperty.editorState;
|
||||
archetypeService.ensureTemporaryId(fieldsetProperty);
|
||||
if (oldState) {
|
||||
fieldsetProperty.editorState.temporaryId = oldState.temporaryId;
|
||||
}
|
||||
|
||||
//set the config from the prevalues
|
||||
scope.model.config = config;
|
||||
@@ -117,16 +124,17 @@ angular.module("umbraco.directives").directive('archetypeProperty', function ($c
|
||||
});
|
||||
|
||||
scope.$on('archetypeFormSubmitting', function (ev, args) {
|
||||
if(args.action !== 'save') {
|
||||
// validate all fieldset properties
|
||||
_.each(scope.fieldset.properties, function (property) {
|
||||
archetypeService.validateProperty(scope.fieldset, property, configFieldsetModel);
|
||||
});
|
||||
// #385 - revert the changes made in #311 to avoid publishing invalid fieldsets (leaving the code from #311 here, in case we figure out how to re-introduce "save as draft")
|
||||
// if(args.action !== 'save') {
|
||||
// validate all fieldset properties
|
||||
_.each(scope.fieldset.properties, function (property) {
|
||||
archetypeService.validateProperty(scope.fieldset, property, configFieldsetModel);
|
||||
});
|
||||
|
||||
var validationKey = "validation-f" + scope.fieldsetIndex;
|
||||
var validationKey = "validation-f" + scope.fieldsetIndex;
|
||||
|
||||
ngModelCtrl.$setValidity(validationKey, scope.fieldset.isValid);
|
||||
}
|
||||
ngModelCtrl.$setValidity(validationKey, scope.fieldset.isValid);
|
||||
// }
|
||||
|
||||
// did the value change (if it did, it most likely did so during the "formSubmitting" event)
|
||||
var property = archetypeService.getFieldsetProperty(scope);
|
||||
|
||||
@@ -13,7 +13,7 @@ var ArchetypeSampleLabelTemplates = (function() {
|
||||
var id = value.split(",")[0];
|
||||
|
||||
if (id) {
|
||||
var entity = scope.services.archetypeLabelService.getEntityById(scope, id, args.entityType);
|
||||
var entity = scope.services.archetypeCacheService.getEntityById(scope, id, args.entityType);
|
||||
|
||||
if(entity) {
|
||||
return entity[args.propertyName];
|
||||
@@ -34,13 +34,13 @@ var ArchetypeSampleLabelTemplates = (function() {
|
||||
switch (value.type) {
|
||||
case "content":
|
||||
if(value.typeData.contentId) {
|
||||
entity = scope.services.archetypeLabelService.getEntityById(scope, value.typeData.contentId, "Document");
|
||||
entity = scope.services.archetypeCacheService.getEntityById(scope, value.typeData.contentId, "Document");
|
||||
}
|
||||
break;
|
||||
|
||||
case "media":
|
||||
if(value.typeData.mediaId) {
|
||||
entity = scope.services.archetypeLabelService.getEntityById(scope, value.typeData.mediaId, "Media");
|
||||
entity = scope.services.archetypeCacheService.getEntityById(scope, value.typeData.mediaId, "Media");
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
+8
-1
@@ -51,5 +51,12 @@
|
||||
"publishHelpText": "Konfigurér udgivelses- og udløbsdato for dette element",
|
||||
"publishReleaseDate": "Udgivelsesdato",
|
||||
"publishExpireDate": "Udløbsdato",
|
||||
"settings": "Indstillinger"
|
||||
"settings": "Indstillinger",
|
||||
"enableMemberGroups": "Aktivér medlems-grupper",
|
||||
"enableMemerGroupsDescription": "Tillad at fieldsets kun vises for specifikke medlems-grupper",
|
||||
"allowedMemberGroups": "Tilladte medlems-grupper",
|
||||
"allowedMemberGroupsHelpText": "Vælg de medlems-grupper, der skal kunne se dette element. Hvis der ikke er valgt nogen, kan alle se elementet.",
|
||||
"previewFieldsetOpen": "(se eksempel)",
|
||||
"previewFieldsetHeader": "Eksempel: ",
|
||||
"previewFieldsetClose": "(luk eksempel)"
|
||||
}
|
||||
|
||||
+8
-1
@@ -51,5 +51,12 @@
|
||||
"publishHelpText": "Konfigurér udgivelses- og udløbsdato for dette element",
|
||||
"publishReleaseDate": "Udgivelsesdato",
|
||||
"publishExpireDate": "Udløbsdato",
|
||||
"settings": "Indstillinger"
|
||||
"settings": "Indstillinger",
|
||||
"enableMemberGroups": "Aktivér medlems-grupper",
|
||||
"enableMemerGroupsDescription": "Tillad at fieldsets kun vises for specifikke medlems-grupper",
|
||||
"allowedMemberGroups": "Tilladte medlems-grupper",
|
||||
"allowedMemberGroupsHelpText": "Vælg de medlems-grupper, der skal kunne se dette element. Hvis der ikke er valgt nogen, kan alle se elementet.",
|
||||
"previewFieldsetOpen": "(se eksempel)",
|
||||
"previewFieldsetHeader": "Eksempel: ",
|
||||
"previewFieldsetClose": "(luk eksempel)"
|
||||
}
|
||||
|
||||
+4
-2
@@ -11,7 +11,7 @@
|
||||
"maxFieldsets": "Max Fieldsets",
|
||||
"maxFieldsetsDescription": "How many Fieldsets are allowed? Entering '1' will disable the controls. Default is unlimited.",
|
||||
"enableMultipleFieldsets": "Enable Multiple Fieldsets?",
|
||||
"enableMultipleFieldsetsDescription": "Allows multiple types of fieldsets within this archetype.",
|
||||
"enableMultipleFieldsetsDescription": "Allows multiple types of fieldsets within this Archetype.",
|
||||
"hideFieldsetToolbar": "Hide Fieldset Toolbar?",
|
||||
"hideFieldsetToolbarDescription": "Hides the fieldset toolbar that appears when more than one fieldset model appears.",
|
||||
"customWrapperClass": "Custom Wrapper Class",
|
||||
@@ -23,7 +23,7 @@
|
||||
"toggleDeveloperMode": "Toggle Developer Mode",
|
||||
"toggleDeveloperModeDescription": "Turn on for developer options.",
|
||||
"configModel": "Config Model",
|
||||
"configModelDescription": "Be careful editing the text below, it controls the schema for this archetype.",
|
||||
"configModelDescription": "Be careful editing the text below, it controls the schema for this Archetype.",
|
||||
"helpText": "Help Text",
|
||||
"defaultValue": "Default Value",
|
||||
"dataType": "DataType",
|
||||
@@ -41,6 +41,8 @@
|
||||
"overrideDefaultConverter":"Override Default Property Value Converter?",
|
||||
"enableCloning":"Enable Cloning?",
|
||||
"enableCloningDescription":"Enable Fieldset Cloning.",
|
||||
"enableCrossDragging":"Enable Cross-Archetype Dragging?",
|
||||
"enableCrossDraggingDescription":"Allows fieldsets to be dragged into other Archetypes.",
|
||||
"fieldsetGroups":"Fieldset groups",
|
||||
"fieldsetGroupsDescription":"If you have a lot of fieldsets to choose from, you may want to consider grouping them in the fieldset picker. Once you have created your groups here, a group picker will be displayed in the fieldset editor and you can assign your fieldsets to their respective groups.",
|
||||
"fieldsetGroupName":"Name",
|
||||
|
||||
+4
-2
@@ -11,7 +11,7 @@
|
||||
"maxFieldsets": "Max Fieldsets",
|
||||
"maxFieldsetsDescription": "How many Fieldsets are allowed? Entering '1' will disable the controls. Default is unlimited.",
|
||||
"enableMultipleFieldsets": "Enable Multiple Fieldsets?",
|
||||
"enableMultipleFieldsetsDescription": "Allows multiple types of fieldsets within this archetype.",
|
||||
"enableMultipleFieldsetsDescription": "Allows multiple types of fieldsets within this Archetype.",
|
||||
"hideFieldsetToolbar": "Hide Fieldset Toolbar?",
|
||||
"hideFieldsetToolbarDescription": "Hides the fieldset toolbar that appears when more than one fieldset model appears.",
|
||||
"customWrapperClass": "Custom Wrapper Class",
|
||||
@@ -23,7 +23,7 @@
|
||||
"toggleDeveloperMode": "Toggle Developer Mode",
|
||||
"toggleDeveloperModeDescription": "Turn on for developer options.",
|
||||
"configModel": "Config Model",
|
||||
"configModelDescription": "Be careful editing the text below, it controls the schema for this archetype.",
|
||||
"configModelDescription": "Be careful editing the text below, it controls the schema for this Archetype.",
|
||||
"helpText": "Help Text",
|
||||
"defaultValue": "Default Value",
|
||||
"dataType": "DataType",
|
||||
@@ -41,6 +41,8 @@
|
||||
"overrideDefaultConverter":"Override Default Property Value Converter?",
|
||||
"enableCloning":"Enable Cloning?",
|
||||
"enableCloningDescription":"Enable Fieldset Cloning.",
|
||||
"enableCrossDragging":"Enable Cross-Archetype Dragging?",
|
||||
"enableCrossDraggingDescription":"Allows fieldsets to be dragged into other Archetypes.",
|
||||
"fieldsetGroups":"Fieldset groups",
|
||||
"fieldsetGroupsDescription":"If you have a lot of fieldsets to choose from, you may want to consider grouping them in the fieldset picker. Once you have created your groups here, a group picker will be displayed in the fieldset editor and you can assign your fieldsets to their respective groups.",
|
||||
"fieldsetGroupName":"Name",
|
||||
|
||||
+4
-2
@@ -11,7 +11,7 @@
|
||||
"maxFieldsets": "Max Fieldsets",
|
||||
"maxFieldsetsDescription": "How many Fieldsets are allowed? Entering '1' will disable the controls. Default is unlimited.",
|
||||
"enableMultipleFieldsets": "Enable Multiple Fieldsets?",
|
||||
"enableMultipleFieldsetsDescription": "Allows multiple types of fieldsets within this archetype.",
|
||||
"enableMultipleFieldsetsDescription": "Allows multiple types of fieldsets within this Archetype.",
|
||||
"hideFieldsetToolbar": "Hide Fieldset Toolbar?",
|
||||
"hideFieldsetToolbarDescription": "Hides the fieldset toolbar that appears when more than one fieldset model appears.",
|
||||
"customWrapperClass": "Custom Wrapper Class",
|
||||
@@ -23,7 +23,7 @@
|
||||
"toggleDeveloperMode": "Toggle Developer Mode",
|
||||
"toggleDeveloperModeDescription": "Turn on for developer options.",
|
||||
"configModel": "Config Model",
|
||||
"configModelDescription": "Be careful editing the text below, it controls the schema for this archetype.",
|
||||
"configModelDescription": "Be careful editing the text below, it controls the schema for this Archetype.",
|
||||
"helpText": "Help Text",
|
||||
"defaultValue": "Default Value",
|
||||
"dataType": "DataType",
|
||||
@@ -41,6 +41,8 @@
|
||||
"overrideDefaultConverter":"Override Default Property Value Converter?",
|
||||
"enableCloning":"Enable Cloning?",
|
||||
"enableCloningDescription":"Enable Fieldset Cloning.",
|
||||
"enableCrossDragging":"Enable Cross-Archetype Dragging?",
|
||||
"enableCrossDraggingDescription":"Allows fieldsets to be dragged into other Archetypes.",
|
||||
"fieldsetGroups":"Fieldset groups",
|
||||
"fieldsetGroupsDescription":"If you have a lot of fieldsets to choose from, you may want to consider grouping them in the fieldset picker. Once you have created your groups here, a group picker will be displayed in the fieldset editor and you can assign your fieldsets to their respective groups.",
|
||||
"fieldsetGroupName":"Name",
|
||||
|
||||
+84
-9
@@ -249,7 +249,7 @@
|
||||
.archetypeAddButton {
|
||||
color: #ddd;
|
||||
.icon {
|
||||
vertical-align: text-top;
|
||||
vertical-align: middle;
|
||||
}
|
||||
&:hover {
|
||||
color: #333;
|
||||
@@ -290,6 +290,12 @@
|
||||
overflow: visible;
|
||||
vertical-align: top;
|
||||
height: 90px;
|
||||
.fieldsetPreviewOpen {
|
||||
font-style: italic;
|
||||
a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
ul.groups {
|
||||
display: block;
|
||||
@@ -310,6 +316,24 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.fieldsetPreview {
|
||||
.fieldsetPreviewClose {
|
||||
font-style: italic;
|
||||
font-size: 12px;
|
||||
text-align: center;
|
||||
}
|
||||
.fieldsetPreviewImage {
|
||||
padding: 6px 0px;
|
||||
img {
|
||||
height: auto;
|
||||
max-width: 100%;
|
||||
vertical-align: middle;
|
||||
border: 0;
|
||||
cursor: zoom-in;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.settingsWrapper {
|
||||
@@ -333,10 +357,33 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.settings {
|
||||
padding: 14px;
|
||||
background-color: #f8f8f8;
|
||||
overflow: hidden;
|
||||
|
||||
.allowedGroups {
|
||||
.umb-membergrouppicker a {
|
||||
i {
|
||||
padding-right: 0;
|
||||
font-size: inherit;
|
||||
}
|
||||
|
||||
&:hover i {
|
||||
color: #333;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Necessary to ensure empty lists can be dropped onto when sorting nested fieldsets.
|
||||
.archetypeSortable.archetypeEmpty {
|
||||
&.archetypeCrossDraggable {
|
||||
min-height: 42px;
|
||||
border: 1px dashed #dddddd;
|
||||
margin-top: 5px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -345,6 +392,7 @@
|
||||
.archetypeEditorControls {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.archetypeEditorControls, .archetypeFieldsetGroups {
|
||||
i {
|
||||
cursor: pointer;
|
||||
@@ -370,10 +418,10 @@
|
||||
small {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
|
||||
a {
|
||||
float: right;
|
||||
|
||||
|
||||
img {
|
||||
width: 35px;
|
||||
}
|
||||
@@ -383,6 +431,26 @@
|
||||
.manual-link {
|
||||
color: blue;
|
||||
}
|
||||
|
||||
.donate-link {
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.sponsors {
|
||||
padding-bottom: 10px;
|
||||
margin-bottom: 5px;
|
||||
margin-left: 5px;
|
||||
display: inline-table;
|
||||
float: right;
|
||||
|
||||
a {
|
||||
float: none;
|
||||
}
|
||||
|
||||
h4 {
|
||||
border-bottom: 1px solid #ccc;
|
||||
}
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
@@ -403,6 +471,8 @@
|
||||
|
||||
.archetypeFieldsets {
|
||||
margin-left: 0;
|
||||
border-top: 5px solid;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.archetypeFieldsetWrapper {
|
||||
@@ -419,7 +489,8 @@
|
||||
.archetypeFieldsetOption {
|
||||
margin-bottom: 15px;
|
||||
margin-right: 15px;
|
||||
input[type=text]{
|
||||
|
||||
input[type=text] {
|
||||
max-width: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
@@ -437,7 +508,7 @@
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
label{
|
||||
label {
|
||||
width: 400px;
|
||||
}
|
||||
}
|
||||
@@ -477,7 +548,7 @@
|
||||
label {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
input[type=text] {
|
||||
width: 100%;
|
||||
}
|
||||
@@ -512,10 +583,10 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.archetypeMaxFieldsets{
|
||||
.archetypeMaxFieldsets {
|
||||
border: 1px solid #ddd;
|
||||
width: 40px;
|
||||
text-align: right;
|
||||
@@ -528,7 +599,7 @@
|
||||
|
||||
.archetypePropertyCollapser {
|
||||
margin-top: 10px;
|
||||
|
||||
|
||||
div {
|
||||
margin-bottom: 10px;
|
||||
margin-right: 15px;
|
||||
@@ -542,6 +613,10 @@
|
||||
.fieldsetIcon {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
small {
|
||||
color: #817f85;
|
||||
}
|
||||
}
|
||||
|
||||
.ui-sortable-placeholder {
|
||||
|
||||
@@ -73,6 +73,34 @@ angular.module('umbraco.services').factory('archetypeCacheService', function (ar
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
},
|
||||
|
||||
getEntityByUmbracoId: function(scope, udi, type) {
|
||||
var cachedEntity = _.find(entityCache, function (e){
|
||||
return e.udi == udi;
|
||||
});
|
||||
|
||||
if(cachedEntity) {
|
||||
return cachedEntity;
|
||||
}
|
||||
|
||||
//go get it from server
|
||||
if (!isEntityLookupLoading) {
|
||||
isEntityLookupLoading = true;
|
||||
|
||||
scope.resources.entityResource.getByIds([udi], type).then(function (entities) {
|
||||
// prevent infinite lookups with a default entity
|
||||
var entity = entities.length > 0 ? entities[0] : { udi: udi, name: "" };
|
||||
|
||||
entityCache.push(entity);
|
||||
|
||||
isEntityLookupLoading = false;
|
||||
|
||||
return entity;
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,19 @@
|
||||
angular.module('umbraco.services').factory('archetypeGlobalConfigService', function ($q, $http, umbRequestHelper) {
|
||||
return {
|
||||
globalSettings: function () {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get("backoffice/ArchetypeApi/ArchetypeDataType/globalSettings"), 'Failed to get whether or not we are checking for updates!'
|
||||
);
|
||||
},
|
||||
setCheckForUpdates: function (isChecking) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post("backoffice/ArchetypeApi/ArchetypeDataType/SetCheckForUpdates", isChecking), 'Failed to update check status!'
|
||||
);
|
||||
},
|
||||
checkForUpdates: function () {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post("backoffice/ArchetypeApi/ArchetypeDataType/checkForUpdates", { }), 'Failed to check for updates!'
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -19,7 +19,6 @@ angular.module('umbraco.services').factory('archetypeLabelService', function (ar
|
||||
}
|
||||
|
||||
function getNativeLabel(datatype, value, scope) {
|
||||
|
||||
switch (datatype.selectedEditor) {
|
||||
case "Imulus.UrlPicker":
|
||||
return imulusUrlPicker(value, scope, {});
|
||||
@@ -27,13 +26,22 @@ angular.module('umbraco.services').factory('archetypeLabelService', function (ar
|
||||
return coreTinyMce(value, scope, {});
|
||||
case "Umbraco.MultiNodeTreePicker":
|
||||
return coreMntp(value, scope, datatype);
|
||||
case "Umbraco.MultiNodeTreePicker2":
|
||||
return coreMntpV2(value, scope, datatype);
|
||||
case "Umbraco.MultipleMediaPicker":
|
||||
case "Umbraco.MediaPicker":
|
||||
return coreMediaPicker(value, scope, datatype);
|
||||
case "Umbraco.MediaPicker2":
|
||||
return coreMediaPickerV2(value, scope, datatype);
|
||||
case "Umbraco.DropDown":
|
||||
return coreDropdown(value, scope, datatype);
|
||||
case "RJP.MultiUrlPicker":
|
||||
return rjpMultiUrlPicker(value, scope, {});
|
||||
default:
|
||||
case "Umbraco.ContentPickerAlias":
|
||||
return coreContentPicker(value, scope, datatype);
|
||||
case "Umbraco.ContentPicker2":
|
||||
return coreContentPickerV2(value, scope, datatype);
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
@@ -87,6 +95,39 @@ angular.module('umbraco.services').factory('archetypeLabelService', function (ar
|
||||
return entityArray.join(', ');
|
||||
}
|
||||
|
||||
function coreMntpV2(value, scope, args) {
|
||||
var ids = value.split(',');
|
||||
if (ids.length == 0) {
|
||||
return "";
|
||||
}
|
||||
var type = "document";
|
||||
|
||||
switch(args.preValues[0].value.type) {
|
||||
case 'content':
|
||||
type = 'document';
|
||||
break;
|
||||
case 'media':
|
||||
type = 'media';
|
||||
break;
|
||||
case 'member':
|
||||
type = 'member';
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
var entity;
|
||||
|
||||
_.each(ids, function (id) {
|
||||
if(id && !entity) {
|
||||
entity = archetypeCacheService.getEntityByUmbracoId(scope, id, type);
|
||||
}
|
||||
});
|
||||
|
||||
return (entity != null ? entity.name : "") + (ids.length > 1 ? ", ..." : "");
|
||||
}
|
||||
|
||||
function coreMediaPicker(value, scope, args) {
|
||||
if(value) {
|
||||
var entity = archetypeCacheService.getEntityById(scope, value, "media");
|
||||
@@ -99,6 +140,42 @@ angular.module('umbraco.services').factory('archetypeLabelService', function (ar
|
||||
return "";
|
||||
}
|
||||
|
||||
function coreMediaPickerV2(value, scope, args) {
|
||||
if(value) {
|
||||
var entity = archetypeCacheService.getEntityByUmbracoId(scope, value, "media");
|
||||
|
||||
if(entity) {
|
||||
return entity.name;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
function coreContentPicker(value, scope, args) {
|
||||
if (value) {
|
||||
var entity = archetypeCacheService.getEntityById(scope, value, "document");
|
||||
|
||||
if (entity) {
|
||||
return entity.name;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
function coreContentPickerV2(value, scope, args) {
|
||||
if (value) {
|
||||
var entity = archetypeCacheService.getEntityByUmbracoId(scope, value, "document");
|
||||
|
||||
if (entity) {
|
||||
return entity.name;
|
||||
}
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
function imulusUrlPicker(value, scope, args) {
|
||||
|
||||
if(!args.propertyName) {
|
||||
@@ -269,7 +346,10 @@ angular.module('umbraco.services').factory('archetypeLabelService', function (ar
|
||||
if(!templateLabelValue) {
|
||||
templateLabelValue = "";
|
||||
}
|
||||
|
||||
// handle collapsing dollar signs in labels (#387)
|
||||
if (templateLabelValue.indexOf("$$") >= 0) {
|
||||
templateLabelValue = templateLabelValue.replace(/\$\$/g, "$$$$$$$$");
|
||||
}
|
||||
parsedTemplate = parsedTemplate.replace(match, templateLabelValue);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,4 +1,11 @@
|
||||
angular.module('umbraco.services').factory('archetypeService', function () {
|
||||
|
||||
// Variables.
|
||||
var draggedRteArchetype;
|
||||
var rteClass = ".archetypeEditor .umb-rte textarea";
|
||||
var editorSettings = {};
|
||||
var disabledSortables = [];
|
||||
|
||||
//public
|
||||
return {
|
||||
//helper that returns a JS ojbect from 'value' string or the original string
|
||||
@@ -44,7 +51,7 @@ angular.module('umbraco.services').factory('archetypeService', function () {
|
||||
return property.alias == alias;
|
||||
});
|
||||
},
|
||||
getUniquePropertyAlias: function (currentScope, propertyAliasParts) {
|
||||
getUniquePropertyAlias: function (currentScope, propertyAliasParts, excludeUniqueId) {
|
||||
if (currentScope.hasOwnProperty('fieldsetIndex') && currentScope.hasOwnProperty('property') && currentScope.hasOwnProperty('propertyConfigIndex'))
|
||||
{
|
||||
var currentPropertyAlias = "f" + currentScope.fieldsetIndex + "-" + currentScope.property.alias + "-p" + currentScope.propertyConfigIndex;
|
||||
@@ -57,15 +64,23 @@ angular.module('umbraco.services').factory('archetypeService', function () {
|
||||
}
|
||||
|
||||
if (currentScope.$parent)
|
||||
this.getUniquePropertyAlias(currentScope.$parent, propertyAliasParts);
|
||||
this.getUniquePropertyAlias(currentScope.$parent, propertyAliasParts, true);
|
||||
|
||||
return _.unique(propertyAliasParts).reverse().join("-");
|
||||
var reversed = _.unique(propertyAliasParts).reverse();
|
||||
|
||||
if (!excludeUniqueId) {
|
||||
reversed.push(_.uniqueId("u-"));
|
||||
}
|
||||
|
||||
return reversed.join("-");
|
||||
},
|
||||
getFieldset: function(scope) {
|
||||
return scope.archetypeRenderModel.fieldsets[scope.fieldsetIndex];
|
||||
var renderModel = scope.archetypeRenderModel;
|
||||
return renderModel ? renderModel.fieldsets[scope.fieldsetIndex] : null;
|
||||
},
|
||||
getFieldsetProperty: function (scope) {
|
||||
return this.getFieldset(scope).properties[scope.renderModelPropertyIndex];
|
||||
var fieldset = this.getFieldset(scope);
|
||||
return fieldset ? fieldset.properties[scope.renderModelPropertyIndex] : null;
|
||||
},
|
||||
setFieldsetValidity: function (fieldset) {
|
||||
// mark the entire fieldset as invalid if there are any invalid properties in the fieldset, otherwise mark it as valid
|
||||
@@ -99,6 +114,107 @@ angular.module('umbraco.services').factory('archetypeService', function () {
|
||||
// it's the Umbraco way to hide the invalid state when altering an invalid property, even if the new value isn't valid either
|
||||
property.isValid = true;
|
||||
this.setFieldsetValidity(fieldset);
|
||||
},
|
||||
// This stores the rich text editors in all Archetypes (e.g., during a drag operation).
|
||||
// Typically, the editors will be restored after the drag completes.
|
||||
storeEditors: function (element) {
|
||||
|
||||
// If there are not tinyMCE editors, this may be undefined.
|
||||
if (typeof tinyMCE === "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Variables.
|
||||
var self = this;
|
||||
draggedRteArchetype = element;
|
||||
|
||||
// Empty the stored settings.
|
||||
editorSettings = {};
|
||||
|
||||
// For fast lookups, store each editor by the element ID.
|
||||
var editorsById = {};
|
||||
for (var i = 0; i < tinyMCE.editors.length; i++) {
|
||||
var tempEditor = tinyMCE.editors[i];
|
||||
editorsById[tempEditor.id] = tempEditor;
|
||||
}
|
||||
|
||||
// Process each rich text editor.
|
||||
$(rteClass).each(function() {
|
||||
|
||||
// Variables.
|
||||
var id = $(this).attr("id");
|
||||
var editor = editorsById[id];
|
||||
|
||||
// Get the property's temporary ID.
|
||||
var scope = angular.element(this).scope().$parent;
|
||||
var property = self.getFieldsetProperty(scope);
|
||||
var tempId = property ? property.editorState.temporaryId : null;
|
||||
|
||||
// Store the editor settings by the temporary ID?
|
||||
if (editor && editor.settings && tempId) {
|
||||
editorSettings[tempId] = editor.settings;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
},
|
||||
// This restores the rich text editors in the specified Archetype
|
||||
// (e.g., after a drop drop operation).
|
||||
restoreEditors: function(element) {
|
||||
|
||||
// If there are not tinyMCE editors, this may be undefined.
|
||||
if (typeof tinyMCE === "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
// Variables.
|
||||
var bothElements = element
|
||||
? element.add(draggedRteArchetype)
|
||||
: draggedRteArchetype;
|
||||
var self = this;
|
||||
|
||||
// Process each RTE in both Archetypes.
|
||||
$(rteClass, bothElements).each(function () {
|
||||
|
||||
// Variables.
|
||||
var id = $(this).attr("id");
|
||||
|
||||
// Get the stored editor settings.
|
||||
var scope = angular.element(this).scope().$parent;
|
||||
var property = self.getFieldsetProperty(scope);
|
||||
var tempId = property ? property.editorState.temporaryId : null;
|
||||
var settings = editorSettings[tempId];
|
||||
|
||||
// Remove and reinitialize the editor.
|
||||
if (settings) {
|
||||
tinyMCE.execCommand("mceRemoveEditor", false, id);
|
||||
tinyMCE.init(settings);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
},
|
||||
// Ensures the specified property has a temporary ID in its editor state,
|
||||
// optionally forcing one to be regenerated (if specified).
|
||||
ensureTemporaryId: function(property, regenerateId) {
|
||||
if (!property.editorState) {
|
||||
property.editorState = {};
|
||||
}
|
||||
var editorState = property.editorState;
|
||||
if (!editorState.temporaryId || regenerateId) {
|
||||
editorState.temporaryId = _.uniqueId("property-temp-id-");
|
||||
}
|
||||
},
|
||||
// Remembers a sortable that has been disabled (so it can be enabled later).
|
||||
rememberDisabledSortable: function(sortable) {
|
||||
disabledSortables.push(sortable);
|
||||
},
|
||||
// Enables all of the sortables that were disabled.
|
||||
enableSortables: function() {
|
||||
_.each(disabledSortables, function(sortable) {
|
||||
sortable.enable();
|
||||
});
|
||||
disabledSortables = [];
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -11,9 +11,11 @@
|
||||
<div>
|
||||
<label for="archetypeOverrideDefaultConverter"><input type="checkbox" id="archetypeOverrideDefaultConverter" ng-model="dialogData.model.overrideDefaultPropertyValueConverter" /><archetype-localize key="overrideDefaultConverter">Override Default Property Value Converter?</archetype-localize><small><archetype-localize key="overrideDefaultConverterDescription">Check this if you wish to use your own custom property value converter.</archetype-localize></small></label>
|
||||
</div>
|
||||
|
||||
<div ng-controller="ArchetypeConfigGlobalOptionsController">
|
||||
<label for="archetypeCheckForNewVersion"><input type="checkbox" id="archetypeCheckForNewVersion" ng-model="globalSettings.checkForNewVersion" ng-click="confirmCheckNewVersionChange();" /><archetype-localize key="checkForNewVersion">Automatically check for newer versions?</archetype-localize><small><archetype-localize key="checkForNewVersionDescription">Check this if you wish to be notified when a newer version of Archetype is available. This is a application level setting.</archetype-localize></small></label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="archetypeAdvancedOptionsConfigModel"><archetype-localize key="configModel">Config Model</archetype-localize><small><archetype-localize key="configModelDescription">Be careful editing the text below, it controls the schema for this archetype.</archetype-localize></small></label>
|
||||
<label for="archetypeAdvancedOptionsConfigModel"><archetype-localize key="configModel">Config Model</archetype-localize><small><archetype-localize key="configModelDescription">Be careful editing the text below, it controls the schema for this Archetype.</archetype-localize></small></label>
|
||||
<textarea class="archetypeDeveloperModel" id="archetypeAdvancedOptionsConfigModel" ng-model="dialogData.model" ng-change="dialogData.modelChanged = true"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -11,6 +11,13 @@
|
||||
<div>
|
||||
<label for="archetypeAdvancedOptionsCollapsing"><input type="checkbox" id="archetypeAdvancedOptionsCollapsing" ng-model="dialogData.model.enableCollapsing"/><archetype-localize key="enableCollapsing">Enable Collapsing?</archetype-localize><small><archetype-localize key="enableCollapsingDescription">Enable fieldset collapsing.</archetype-localize></small></label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="archetypeAdvancedOptionsMultipleOpen"><input type="checkbox" id="archetypeAdvancedOptionsMultipleOpen" ng-model="dialogData.model.enableMultipleOpen" /><archetype-localize key="enableMultipleOpen">Enable Multiple Open Fieldsets?</archetype-localize><small><archetype-localize key="enableMultipleOpenDescription">When fieldset collapsing is enabled, this allows multiple fieldsets to be open at the same time.</archetype-localize></small></label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="archetypeAdvancedOptionsMinFieldsets"><archetype-localize key="minFieldsets">Min Fieldsets</archetype-localize><small><archetype-localize key="minFieldsetsDescription">How many Fieldsets are required? Default is none.</archetype-localize></small></label>
|
||||
<input type="number" id="archetypeAdvancedOptionsMinFieldsets" class="archetypeMaxFieldsets" ng-model="dialogData.model.minFieldsets" />
|
||||
</div>
|
||||
<div>
|
||||
<label for="archetypeAdvancedOptionsMaxFieldsets"><archetype-localize key="maxFieldsets">Max Fieldsets</archetype-localize><small><archetype-localize key="maxFieldsetsDescription">How many Fieldsets are allowed? Entering '1' will disable the controls. Default is unlimited.</archetype-localize></small></label>
|
||||
<input type="number" id="archetypeAdvancedOptionsMaxFieldsets" class="archetypeMaxFieldsets" ng-model="dialogData.model.maxFieldsets"/>
|
||||
@@ -30,6 +37,12 @@
|
||||
<div>
|
||||
<label for="archetypeAdvancedOptionsPublishing"><input type="checkbox" id="archetypeAdvancedOptionsPublishing" ng-model="dialogData.model.enablePublishing" /><archetype-localize key="enablePublishing">Enable Fieldset Publishing?</archetype-localize><small><archetype-localize key="enablePublishingDescription">Allows fieldsets to be automatically published and/or unpublished.</archetype-localize></small></label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="archetypeAdvancedOptionsCrossDragging"><input type="checkbox" id="archetypeAdvancedOptionsCrossDragging" ng-model="dialogData.model.enableCrossDragging" /><archetype-localize key="enableCrossDragging">Enable Cross-Archetype Dragging?</archetype-localize><small><archetype-localize key="enableCrossDraggingDescription">Allows fieldsets to be dragged into other Archetypes.</archetype-localize></small></label>
|
||||
</div>
|
||||
<div>
|
||||
<label for="archetypeAdvancedOptionsMemberGroups"><input type="checkbox" id="archetypeAdvancedOptionsMemberGroups" ng-model="dialogData.model.enableMemberGroups" /><archetype-localize key="enableMemberGroups">Enable Member Group Access?</archetype-localize><small><archetype-localize key="enableMemerGroupsDescription">Allows fieldsets to be displayed for specified member groups only.</archetype-localize></small></label>
|
||||
</div>
|
||||
|
||||
<h4><archetype-localize key="multipleFieldsets">Multiple fieldsets</archetype-localize></h4>
|
||||
<div>
|
||||
|
||||
@@ -1,8 +1,17 @@
|
||||
{{VERSION_HTML}}
|
||||
<div class="archetypeConfig" ng-controller="Imulus.ArchetypeConfigController">
|
||||
<h2 class="archetype-headline"><img src="../App_Plugins/Archetype/assets/logo_50.png"/>Archetype<small>{{dllVersion}}</small><a href="https://twitter.com/archetypekit" target="_blank"><img src="../App_Plugins/Archetype/assets/twitter.png"/></a></h2>
|
||||
<p>At a minimum your Archetype needs at least one fieldset with at least one property. You can configure it to allow for multiple types of fieldsets within a single Archetype and you can even add another Archetype as a property. Please use the link below for the full manual:</p>
|
||||
<p><a class="manual-link" href="https://github.com/kgiszewski/ArchetypeManual" target="_blank">Archetype Manual</a></p>
|
||||
<h2 class="archetype-headline"><img src="../App_Plugins/Archetype/assets/logo_50.png"/>Archetype<small>{{dllVersion}}</small></h2>
|
||||
<p>At a minimum your Archetype needs at least one fieldset with at least one property. Please use the link below for the full manual. We would really love a donation if you find Archetype useful. Your company can also sponsor a sprint!</p>
|
||||
<p>
|
||||
<a class="manual-link" href="https://github.com/kgiszewski/ArchetypeManual" target="_blank">Archetype Manual</a> |
|
||||
<a class="manual-link" href="https://github.com/kgiszewski/Archetype/blob/master/Terms%20of%20Service.md" target="_blank">Terms of Service</a> |
|
||||
<a class="manual-link" href="https://www.youtube.com/watch?v=79LksNwGjLk" target="_blank">Quick Start Video</a> |
|
||||
<a class="manual-link" href="https://twitter.com/archetypekit" target="_blank">Twitter</a> |
|
||||
<a class="manual-link" href="https://github.com/kgiszewski/Archetype" target="_blank">GitHub</a> |
|
||||
<a class="manual-link" href="https://github.com/kgiszewski/Archetype/blob/master/Sponsors.md" target="_blank">Become a sponsor</a> |
|
||||
<a class="manual-link donate-link" href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=KBKWLURGLGU6L" target="_blank">Donate!</a>
|
||||
</p>
|
||||
|
||||
<ul class="archetypeFieldsets" ui-sortable="sortableOptions" ng-model="archetypeConfigRenderModel.fieldsets">
|
||||
<li ng-repeat="fieldset in archetypeConfigRenderModel.fieldsets" ng-hide="fieldset.remove">
|
||||
<div class="archetypeFieldsetWrapper" >
|
||||
@@ -12,14 +21,16 @@
|
||||
<i class="icon icon-navigation handle" ng-show="canSortFieldset()"></i>
|
||||
</div>
|
||||
<div class="archetypeFieldsetTitle" ng-click="focusFieldset(fieldset)">{{fieldset.label}}</div>
|
||||
<div class="archetypeFieldsetCollapser" ng-hide="fieldset.collapse && fieldset.label">
|
||||
<div class="archetypeFieldsetCollapser" ng-hide="fieldset.collapse && fieldset.label" ng-if="isLoaded(fieldset)">
|
||||
<div class="archetypeFieldsetOption">
|
||||
<label for="archetypeFieldLabel_{{$index}}"><archetype-localize key="label">Label</archetype-localize></label>
|
||||
<input type="text" id="archetypeFieldLabel_{{$index}}" ng-model="fieldset.label" on-keyup="autoPopulateAlias(this)" />
|
||||
<input type="text" id="archetypeFieldLabel_{{$index}}" ng-model="fieldset.label" on-keyup="autoPopulateAlias(fieldset)" />
|
||||
<small>The label shown to the editors when adding a new fieldset.</small>
|
||||
</div>
|
||||
<div class="archetypeFieldsetOption">
|
||||
<label for="archetypeFieldAlias_{{$index}}"><archetype-localize key="alias">Alias</archetype-localize></label>
|
||||
<input type="text" id="archetypeFieldAlias_{{$index}}" ng-model="fieldset.alias" on-keyup="markAliasDirty(this)" required/>
|
||||
<input type="text" id="archetypeFieldAlias_{{$index}}" ng-model="fieldset.alias" on-keyup="markAliasDirty(fieldset)" required/>
|
||||
<small>The alias used to identify the fieldset when rendering.</small>
|
||||
</div>
|
||||
<div class="archetypeFieldsetOption" ng-show="archetypeConfigRenderModel.fieldsetGroups.length">
|
||||
<label for="archetypeFieldsetGroup_{{$index}}"><archetype-localize key="fieldsetGroup">Group</archetype-localize></label>
|
||||
@@ -28,6 +39,12 @@
|
||||
<div class="archetypeFieldsetOption">
|
||||
<label for="archetypeFieldLabelTemplate_{{$index}}"><archetype-localize key="labelTemplate">Label Template</archetype-localize></label>
|
||||
<input type="text" id="archetypeFieldLabelTemplate_{{$index}}" ng-model="fieldset.labelTemplate" />
|
||||
<small>Generates labels per fieldset. Can contain property aliases, e.g. "Article: {{title}}".</small>
|
||||
</div>
|
||||
<div class="archetypeFieldsetOption">
|
||||
<label for="archetypeFieldPreview_{{$index}}">Preview image</label>
|
||||
<input type="text" id="archetypeFieldPreview_{{$index}}" ng-model="fieldset.previewImage" on-keyup="markAliasDirty(fieldset)" />
|
||||
<small>A relative path to a preview image, e.g. "/assets/fieldset.png".</small>
|
||||
</div>
|
||||
<div class="archetypeFieldsetOption" ng-show="archetypeConfigRenderModel.enableMultipleFieldsets">
|
||||
<label for="archetypeFieldIcon_{{$index}}"><archetype-localize key="icon">Icon</archetype-localize></label>
|
||||
@@ -50,11 +67,11 @@
|
||||
<div class="archetypePropertyCollapser" ng-hide="property.collapse && property.label">
|
||||
<div>
|
||||
<label for="archetypePropertyLabel_{{$parent.$index}}_{{$index}}"><archetype-localize key="label">Label</archetype-localize></label>
|
||||
<input type="text" id="archetypePropertyLabel_{{$parent.$index}}_{{$index}}" ng-model="property.label" on-keyup="autoPopulateAlias(this)"/>
|
||||
<input type="text" id="archetypePropertyLabel_{{$parent.$index}}_{{$index}}" ng-model="property.label" on-keyup="autoPopulateAlias(property)"/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="archetypePropertyAlias_{{$parent.$index}}_{{$index}}"><archetype-localize key="alias">Alias</archetype-localize></label>
|
||||
<input type="text" id="archetypePropertyAlias_{{$parent.$index}}_{{$index}}" ng-model="property.alias" on-keyup="markAliasDirty(this)" required/>
|
||||
<input type="text" id="archetypePropertyAlias_{{$parent.$index}}_{{$index}}" ng-model="property.alias" on-keyup="markAliasDirty(property)" required/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="archetypePropertyHelpText_{{$parent.$index}}_{{$index}}"><archetype-localize key="helpText">Help Text</archetype-localize></label>
|
||||
|
||||
@@ -1,7 +1,25 @@
|
||||
{{VERSION_HTML}}
|
||||
<div class="archetypeEditor ng-class:model.config.customCssClass">
|
||||
<textarea class="archetypeDeveloperModel" ng-show="model.config.developerMode" ng-model="model.value"></textarea>
|
||||
<ul ui-sortable="sortableOptions" ng-model="model.value.fieldsets" ng-show="!showAddButton()">
|
||||
|
||||
<!-- "Add" button. -->
|
||||
<div ng-show="showAddButton()">
|
||||
<a class="archetypeAddButton" ng-click="openFieldsetPicker(0, $event)" prevent-default>
|
||||
<i class="icon icon-add"></i>
|
||||
<archetype-localize key="addFieldset">Add an item</archetype-localize>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Mandatory validation. -->
|
||||
<input type="hidden" name="archetypeMandatory" ng-model="model.mandatoryValidation" ng-required="model.validation.mandatory" />
|
||||
<div><span class="help-inline" val-msg-for="archetypeMandatory" val-toggle-msg="required"><archetype-localize key="required">Required</archetype-localize></span></div>
|
||||
|
||||
<!-- Min fieldsets validation. -->
|
||||
<input type="hidden" name="archetypeMinFieldsets" ng-model="model.mandatoryMinFieldsets" ng-required="!minFieldsetsFulfilled()" />
|
||||
<div><span class="help-inline" val-msg-for="archetypeMinFieldsets" val-toggle-msg="required">{{minFieldsetsMessage}}</span></div>
|
||||
|
||||
<!-- Fieldsets. -->
|
||||
<ul ui-sortable="sortableOptions" class="archetypeSortable" ng-class="{archetypeEmpty: model.value.fieldsets.length === 0 || sortingLastItem(), archetypeCrossDraggable: model.config.enableCrossDragging}" ng-model="model.value.fieldsets">
|
||||
<li ng-repeat="fieldset in model.value.fieldsets">
|
||||
<fieldset ng-class="['archetype-fieldset-' + fieldset.alias, (getFieldsetValidity(fieldset) == false ? 'archetypeFieldsetError' : '')]" ng-init="fieldsetConfigModel = getConfigFieldsetByAlias(fieldset.alias)">
|
||||
<div class="archetypeFieldsetLabel" ng-class="{enableCollapsing: model.config.enableCollapsing}">
|
||||
@@ -46,7 +64,7 @@
|
||||
</div>
|
||||
<div class="settings" ng-show="showSettings">
|
||||
<!-- misc fieldset settings go here -->
|
||||
<div ng-if="fieldset.releaseDateModel" ng-show="canPublish()">
|
||||
<div ng-if="fieldset.releaseDateModel" ng-show="canPublish()" class="control-group">
|
||||
<label ng-hide="model.config.hidePropertyLabels == '1'" class="control-label">
|
||||
<span><archetype-localize key="publish">Publishing</archetype-localize></span>
|
||||
<div class="archetypeFieldsetHelpText">
|
||||
@@ -70,6 +88,19 @@
|
||||
<archetype-submit-watcher active-submit-watcher="activeSubmitWatcher" load-callback="submitWatcherOnLoad" submit-callback="submitWatcherOnSubmit"></archetype-submit-watcher>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="fieldset.allowedMemberGroupsModel" ng-show="canUseMemberGroups()" class="control-group allowedGroups">
|
||||
<label ng-hide="model.config.hidePropertyLabels == '1'" class="control-label">
|
||||
<span><archetype-localize key="allowedMemberGroups">Allowed member groups</archetype-localize></span>
|
||||
<div class="archetypeFieldsetHelpText">
|
||||
<small><archetype-localize key="allowedMemberGroupsHelpText">Choose the member groups that should be allowed to see this item. Leave empty to allow all member groups.</archetype-localize></small>
|
||||
</div>
|
||||
</label>
|
||||
<div ng-class="[(model.config.hidePropertyLabels == '1' ? 'controls-no-label' : 'controls')]">
|
||||
<umb-editor model="fieldset.allowedMemberGroupsModel"></umb-editor>
|
||||
</div>
|
||||
<!-- we need a submit watcher here to make sure the allowed member groups are saved back to the model -->
|
||||
<archetype-submit-watcher active-submit-watcher="activeSubmitWatcher" load-callback="submitWatcherOnLoad" submit-callback="submitWatcherOnSubmit"></archetype-submit-watcher>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -77,32 +108,49 @@
|
||||
</fieldset>
|
||||
</li>
|
||||
</ul>
|
||||
<div ng-show="showAddButton()">
|
||||
<a class="archetypeAddButton" ng-click="openFieldsetPicker(0, $event)" prevent-default>
|
||||
<i class="icon icon-add"></i>
|
||||
<archetype-localize key="addFieldset">Add an item</archetype-localize>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Fieldset picker. -->
|
||||
<div class="usky-grid fieldsetPicker" ng-class="{withGroups: overlayMenu.fieldsetGroups.length > 1}" ng-if="overlayMenu.show">
|
||||
<div class="cell-tools-menu" ng-style="overlayMenu.style" delayed-mouseleave="closeFieldsetPicker()" archetype-click-outside="closeFieldsetPicker()">
|
||||
<h5>
|
||||
<archetype-localize key="addFieldset">Add an item</archetype-localize>
|
||||
</h5>
|
||||
<ul class="groups" ng-show="overlayMenu.fieldsetGroups.length > 1">
|
||||
<li ng-repeat="fieldsetGroup in overlayMenu.fieldsetGroups" ng-class="{active: fieldsetGroup == overlayMenu.activeFieldsetGroup}">
|
||||
<a ng-click="overlayMenu.activeFieldsetGroup = fieldsetGroup">
|
||||
{{fieldsetGroup.name}}
|
||||
<div ng-show="!overlayMenu.fieldsetPreview">
|
||||
<h5>
|
||||
<archetype-localize key="addFieldset">Add an item</archetype-localize>
|
||||
</h5>
|
||||
<ul class="groups" ng-show="overlayMenu.fieldsetGroups.length > 1">
|
||||
<li ng-repeat="fieldsetGroup in overlayMenu.fieldsetGroups" ng-class="{active: fieldsetGroup == overlayMenu.activeFieldsetGroup}">
|
||||
<a ng-click="overlayMenu.activeFieldsetGroup = fieldsetGroup">
|
||||
{{fieldsetGroup.name}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="elements">
|
||||
<li ng-repeat="fieldset in overlayMenu.activeFieldsetGroup.fieldsets">
|
||||
<a ng-click="pickFieldset(fieldset.alias, overlayMenu.index)" href>
|
||||
<i class="icon {{fieldset.icon}}"></i>
|
||||
{{fieldset.label}}
|
||||
</a>
|
||||
<div class="fieldsetPreviewOpen" ng-if="fieldset.previewImage">
|
||||
<a href ng-click="openFieldsetPreview(fieldset)"><archetype-localize key="previewFieldsetOpen">(see preview)</archetype-localize></a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div ng-show="overlayMenu.fieldsetPreview" class="fieldsetPreview">
|
||||
<h5>
|
||||
<archetype-localize key="previewFieldsetHeader">Preview: </archetype-localize>{{overlayMenu.fieldsetPreview.label}}
|
||||
</h5>
|
||||
<div class="fieldsetPreviewClose">
|
||||
<a href ng-click="closeFieldsetPreview()"><archetype-localize key="previewFieldsetClose">(close preview)</archetype-localize></a>
|
||||
</div>
|
||||
<div class="fieldsetPreviewImage">
|
||||
<a href="{{overlayMenu.fieldsetPreview.previewImage}}" target="_blank">
|
||||
<img ng-src="{{overlayMenu.fieldsetPreview.previewImage}}" />
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="elements">
|
||||
<li ng-repeat="fieldset in overlayMenu.activeFieldsetGroup.fieldsets">
|
||||
<a ng-click="pickFieldset(fieldset.alias, overlayMenu.index)" href>
|
||||
<i class="icon {{fieldset.icon}}"></i>
|
||||
{{fieldset.label}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="fieldsetPreviewClose">
|
||||
<a href ng-click="closeFieldsetPreview()"><archetype-localize key="previewFieldsetClose">(close preview)</archetype-localize></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 4.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 4.7 KiB |
+4
-4
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"name": "Archetype",
|
||||
"version": "1.13.0",
|
||||
"url": "http://github.com/imulus/archetype/",
|
||||
"author": "Imulus - Kevin Giszewski - Tom Fulton - Lee Kelleher - Matt Brailsford - Kenn Jacobsen - Et. Al.",
|
||||
"authorUrl": "http://imulus.com/",
|
||||
"version": "1.16.0",
|
||||
"url": "http://github.com/kgiszewski/archetype/",
|
||||
"author": "Kevin Giszewski - Tom Fulton - Lee Kelleher - Matt Brailsford - Kenn Jacobsen - Nicholas Westby - Et. Al.",
|
||||
"authorUrl": "http://github.com/kgiszewski/archetype/",
|
||||
"license": "MIT",
|
||||
"licenseUrl": "http://opensource.org/licenses/MIT"
|
||||
}
|
||||
@@ -4,12 +4,12 @@
|
||||
<id>Archetype</id>
|
||||
<version><%= version %></version>
|
||||
<title><%= name %></title>
|
||||
<authors>imulus, kgiszewski, tomfulton</authors>
|
||||
<owners>imulus, kgiszewski, tomfulton</owners>
|
||||
<projectUrl>http://github.com/imulus/archetype</projectUrl>
|
||||
<authors>kgiszewski, tomfulton</authors>
|
||||
<owners>kgiszewski, tomfulton</owners>
|
||||
<projectUrl>http://github.com/kgiszewski/archetype</projectUrl>
|
||||
<description><![CDATA[Archetype for Umbraco]]></description>
|
||||
<tags>umbraco</tags>
|
||||
<iconUrl>http://github.com/imulus/archetype/raw/master/assets/logo.png</iconUrl>
|
||||
<iconUrl>http://imulus.github.io/Archetype/images/logo.png</iconUrl>
|
||||
<licenseUrl><%= licenseUrl %></licenseUrl>
|
||||
<dependencies>
|
||||
<dependency id="Archetype.Binaries" version="<%= version %>" />
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
<id>Archetype.Binaries</id>
|
||||
<version><%= version %></version>
|
||||
<title><%= name %></title>
|
||||
<authors>imulus, kgiszewski, tomfulton</authors>
|
||||
<owners>imulus, kgiszewski, tomfulton</owners>
|
||||
<projectUrl>http://github.com/imulus/archetype</projectUrl>
|
||||
<authors>kgiszewski, tomfulton</authors>
|
||||
<owners>kgiszewski, tomfulton</owners>
|
||||
<projectUrl>http://github.com/kgiszewski/archetype</projectUrl>
|
||||
<description><![CDATA[Archetype binaries for Umbraco]]></description>
|
||||
<tags>umbraco</tags>
|
||||
<iconUrl>http://github.com/imulus/archetype/raw/master/assets/logo.png</iconUrl>
|
||||
<iconUrl>http://imulus.github.io/Archetype/images/logo.png</iconUrl>
|
||||
<licenseUrl><%= licenseUrl %></licenseUrl>
|
||||
<dependencies>
|
||||
<dependency id="UmbracoCms.Core" version="7.2.2" />
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
<title><%= name %></title>
|
||||
<authors>leekelleher</authors>
|
||||
<owners>kgiszewski, leekelleher</owners>
|
||||
<projectUrl>http://github.com/imulus/archetype</projectUrl>
|
||||
<projectUrl>http://github.com/kgiszewski/archetype</projectUrl>
|
||||
<description><![CDATA[Archetype Courier extension for Umbraco]]></description>
|
||||
<tags>umbraco</tags>
|
||||
<iconUrl>http://github.com/imulus/archetype/raw/master/assets/logo.png</iconUrl>
|
||||
<iconUrl>http://imulus.github.io/Archetype/images/logo.png</iconUrl>
|
||||
<licenseUrl><%= licenseUrl %></licenseUrl>
|
||||
<dependencies>
|
||||
<dependency id="Archetype.Binaries" version="<%= version %>" />
|
||||
|
||||
Reference in New Issue
Block a user