diff --git a/.gitignore b/.gitignore index 5e0d59a..89a7373 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,48 @@ $RECYCLE.BIN/ dist/ node_modules/ -pkg/ \ No newline at end of file +pkg/tmp/ +pkg/*.nupkg + +[Dd]ebug/ +[Bb]uild/ +[Rr]elease/ +[Bb]in/ +[Oo]bj/ +[Pp]ackages/ + +*.aps +*.bak +*.backup +*.build.csdef +*.cache +*.ilk +*.lib +*.log +*.meta +*.ncb +*.obj +*.orig +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.scc +*.sdf +*.sln.docstates +*.suo +*.tlb +*.tlh +*.tli +*.tmp +*.user +*.vspscc +*.[Pp]ublish.xml +*_i.c +*_p.c +.builds +.svn +.hg +.hgignore \ No newline at end of file diff --git a/Gruntfile.js b/Gruntfile.js index 0ea5251..febcf19 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -2,6 +2,9 @@ module.exports = function(grunt) { grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), dest: 'dist', + version: '0.0.0', + package_dir: 'pkg', + package_temp_dir: '<%= package_dir %>/tmp/', watch: { less: { @@ -56,22 +59,56 @@ module.exports = function(grunt) { application: { src: [ 'app/controllers/controller.js', - 'app/directives/archetypeproperty.js' + 'app/controllers/config.controller.js', + 'app/directives/archetypeproperty.js', + 'app/services/propertyeditor.js' ], dest: '<%= dest %>/js/archetype.js' } }, + nugetpack: { + dist: { + src: '<%= package_temp_dir %>/nuget/package.nuspec', + dest: '<%= package_dir %>' + } + }, + + template: { + 'nuget_manifest': { + 'options': { + 'data': { + version: '<%= version %>', + files: [{ path: '..\\..\\..\\<%= dest %>\\**', target: 'content\\App_Plugins\\Archetype'}] + } + }, + 'files': { + '<%= package_temp_dir %>/nuget/package.nuspec': ['<%= package_dir %>/nuget/package.nuspec'] + } + } + }, + + clean: { + build: ['<%= dest %>'], + package_temp: ['<%= package_temp_dir %>'] + }, + copy: { build: { files: [ {expand: true, cwd: 'app/', src: ['package.manifest'], dest: '<%= dest %>', flatten: true}, - {expand: true, cwd: 'app/views/', src: ['archetype.html'], dest: '<%= dest %>/views', flatten: true} + {expand: true, cwd: 'app/config/', src: ['config.views.js'], dest: '<%= dest %>/js', flatten: true}, + {expand: true, cwd: 'app/views/', src: ['archetype.html', 'archetype.config.html'], dest: '<%= dest %>/views', flatten: true} ] }, deploy: { files: [ - {expand: true, cwd: '<%= dest %>/', src: ['**'], dest: '<%= grunt.option("target") %>\\App_Plugins\\Imulus.Archetype', flatten: false}, + {expand: true, cwd: '<%= dest %>/', src: ['**'], dest: '<%= grunt.option("target") %>\\App_Plugins\\Archetype', flatten: false}, + ] + }, + nuget_prepare: { + files: [ + {expand: true, cwd: '<%= dest %>/', src: ['**'], dest: '<%= package_temp_dir %>/nuget/content/', flatten: false}, ] }, umbracopackage: { @@ -105,6 +142,7 @@ module.exports = function(grunt) { }, clean: ['<%= dest %>'] + } }); @@ -115,10 +153,13 @@ module.exports = function(grunt) { grunt.loadNpmTasks('grunt-contrib-copy'); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-jshint'); + grunt.loadNpmTasks('grunt-nuget'); + grunt.loadNpmTasks('grunt-template'); grunt.loadNpmTasks('grunt-touch'); grunt.loadTasks('tasks'); + grunt.registerTask('package:nuget', ['default', 'clean:package_temp', 'copy:nuget_prepare', 'template:nuget_manifest', 'nugetpack', 'clean:package_temp']); grunt.registerTask('touchwebconfigifenabled', function() { if (grunt.option("touch")) grunt.task.run("touch:webconfig") }); grunt.registerTask('deploy', ['default', 'copy:deploy', 'touchwebconfigifenabled']); grunt.registerTask('package:umbraco', ['copy:umbracopackage', 'umbracoPackage']); diff --git a/README.md b/README.md index 91f68fb..a6e5a9e 100644 --- a/README.md +++ b/README.md @@ -41,164 +41,11 @@ Your /App_Plugins should contain this structure: ## Prevalue Configs ## Most of the fields are self evident, the following fields will be discussed further: - -###Empty Fieldset Models### -This option is required and defines the fieldsets and their properties. - -If you get a YSOD regarding truncating of data, it's b/c Umbraco has a arbitrarily low limit on the number of characters (2500) allowed as prevalues in the DB. -See: http://issues.umbraco.org/issue/U4-2120 - -An example follows below: - - ( //note that this needs to start with an open parentheses and notice the closing one at the end of this. This avoids issues with only seeing [object]. - [ //this array holds the array of fieldset objects - { //fieldset object - alias: "FS1", //fieldset alias (unique) - tooltip: "This is for fieldset 1", //used as a helper text - icon: "/umbraco/Images/aboutNew.png", //a custom icon - label: "Fieldset 1", //the fieldset label - headerText: "Please fill out the boxes.", // text to be prepended to the fieldset properties? - footerText: "Thanks!", //text to be appended to the fieldset properties? - properties:[ //an array of property objects - { - alias: "firstName", //uniquely name the property (unique to the fieldset) - label: "First Name", //a label to use - helpText: "(Required)", //a note that will appear under the label - view: "/umbraco/views/propertyeditors/textbox/textbox.html", //a path to a view - value: "", //set to none or set to a default; can be json (if the view understands it) - config: { //pass configs to the view; configs are based on the view used - - } - }, - { //another property - alias: "lastName", - label: "Last Name", - helpText: "(Required)", - view: "/umbraco/views/propertyeditors/textbox/textbox.html", - value: "", - config: { - - } - }, - { - alias: "age", - label: "Age", - helpText: "(Optional)", - view: "/umbraco/views/propertyeditors/textbox/textbox.html", - value: "", - config: { - - } - }, - { - alias: "blah", - label: "Blah", - helpText: "", - view: "/umbraco/views/propertyeditors/contentpicker/contentpicker.html", - value: "", - config: { - - } - } - ] - }, - { //another fieldset - alias: "FS2", - tooltip: "This is for fieldset 2", - icon: "/umbraco/Images/about.png", - label: "Fieldset 2", - headerText: "Please fill out the boxes.", - footerText: "Thanks!", - properties:[ - { - alias: "foo", - label: "Foo", - helpText: "(Required)", - view: "/umbraco/views/propertyeditors/textbox/textbox.html", - value: "", - config: { - - } - }, - { - alias: "bar", - label: "Bar", - helpText: "", - view: "/umbraco/views/propertyeditors/textbox/textbox.html", - value: "", - config: { - - } - } - ] - } - ] - )//close it - -###Default Model### -Here is the spot to define a starting value. This model uses only the essential data that must be saved. This example shows multiple fieldsets with multiple properties: - - ( //again use a parenthesis to avoid [object] - { - "fieldsets": [ - { - "alias": "FS2", - "properties": [ - { - "alias": "bar", - "value": "Field" - }, - { - "alias": "foo", - "value": "Another" - } - ] - }, - { - "alias": "FS2", - "properties": [ - { - "alias": "foo", - "value": "The Foo Field" - }, - { - "alias": "bar", - "value": "The Bar Field" - } - ] - }, - { - "alias": "FS1", - "properties": [ - { - "alias": "age", - "value": "Old" - }, - { - "alias": "lastName", - "value": "Giszewski" - }, - { - "alias": "firstName", - "value": "Kevin" - }, - { - "alias": "blah", - "value": "" - } - ] - } - ] - } - ) ###Developer Mode### By turning this on, you will get a textarea visible with the data model (not prevalue model). You can change the contents of the textarea for real-time editing. Additionally when in developer mode, the console will reflect the scope object of each property. -###Sortable Options### -Just in case you need to pass something into the jQueryUI sort options, you can override the default behavior by passing in a new JS snippet here. - ##View Compatibility## The basis of compatibility is based on the following: diff --git a/app/Umbraco/.nuget/NuGet.Config b/app/Umbraco/.nuget/NuGet.Config new file mode 100644 index 0000000..67f8ea0 --- /dev/null +++ b/app/Umbraco/.nuget/NuGet.Config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/Umbraco/.nuget/NuGet.exe b/app/Umbraco/.nuget/NuGet.exe new file mode 100644 index 0000000..8f61340 Binary files /dev/null and b/app/Umbraco/.nuget/NuGet.exe differ diff --git a/app/Umbraco/.nuget/NuGet.targets b/app/Umbraco/.nuget/NuGet.targets new file mode 100644 index 0000000..0f124b1 --- /dev/null +++ b/app/Umbraco/.nuget/NuGet.targets @@ -0,0 +1,136 @@ + + + + $(MSBuildProjectDirectory)\..\ + + + true + + + false + + + false + + + false + + + + + + + + + + + $([System.IO.Path]::Combine($(SolutionDir), ".nuget")) + $([System.IO.Path]::Combine($(ProjectDir), "packages.config")) + + + + + $(SolutionDir).nuget + packages.config + + + + + $(NuGetToolsPath)\NuGet.exe + @(PackageSource) + + "$(NuGetExePath)" + mono --runtime=v4.0.30319 $(NuGetExePath) + + $(TargetDir.Trim('\\')) + + -RequireConsent + -NonInteractive + + "$(SolutionDir) " + "$(SolutionDir)" + + + $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir) + $(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols + + + + RestorePackages; + $(BuildDependsOn); + + + + + $(BuildDependsOn); + BuildPackage; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/Umbraco/Umbraco.Archetype.sln b/app/Umbraco/Umbraco.Archetype.sln new file mode 100644 index 0000000..70ff40d --- /dev/null +++ b/app/Umbraco/Umbraco.Archetype.sln @@ -0,0 +1,27 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Archetype.Umbraco", "Umbraco.Archetype\Archetype.Umbraco.csproj", "{7D185D41-4228-4978-ACB8-83F9A48AD94F}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{D84AA4ED-85A6-484F-9E72-BE7AC9835821}" + ProjectSection(SolutionItems) = preProject + .nuget\NuGet.Config = .nuget\NuGet.Config + .nuget\NuGet.exe = .nuget\NuGet.exe + .nuget\NuGet.targets = .nuget\NuGet.targets + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7D185D41-4228-4978-ACB8-83F9A48AD94F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7D185D41-4228-4978-ACB8-83F9A48AD94F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7D185D41-4228-4978-ACB8-83F9A48AD94F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7D185D41-4228-4978-ACB8-83F9A48AD94F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/app/Umbraco/Umbraco.Archetype/Archetype.Umbraco.csproj b/app/Umbraco/Umbraco.Archetype/Archetype.Umbraco.csproj new file mode 100644 index 0000000..053a0bd --- /dev/null +++ b/app/Umbraco/Umbraco.Archetype/Archetype.Umbraco.csproj @@ -0,0 +1,207 @@ + + + + + Debug + AnyCPU + {7D185D41-4228-4978-ACB8-83F9A48AD94F} + Library + Properties + Archetype.Umbraco + Archetype + v4.5 + 512 + ..\ + true + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.dll + + + ..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.Net4.dll + + + ..\packages\UmbracoCms.Core.7.0.1\lib\businesslogic.dll + + + ..\packages\ClientDependency.1.7.0.4\lib\ClientDependency.Core.dll + + + ..\packages\ClientDependency-Mvc.1.7.0.4\lib\ClientDependency.Core.Mvc.dll + + + ..\packages\UmbracoCms.Core.7.0.1\lib\cms.dll + + + ..\packages\UmbracoCms.Core.7.0.1\lib\controls.dll + + + ..\packages\xmlrpcnet.2.5.0\lib\net20\CookComputing.XmlRpcV2.dll + + + ..\packages\UmbracoCms.Core.7.0.1\lib\Examine.dll + + + ..\packages\HtmlAgilityPack.1.4.6\lib\Net45\HtmlAgilityPack.dll + + + ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll + + + ..\packages\UmbracoCms.Core.7.0.1\lib\interfaces.dll + + + ..\packages\UmbracoCms.Core.7.0.1\lib\log4net.dll + + + ..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll + + + ..\packages\UmbracoCms.Core.7.0.1\lib\Microsoft.ApplicationBlocks.Data.dll + + + ..\packages\UmbracoCms.Core.7.0.1\lib\Microsoft.Web.Helpers.dll + + + True + ..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + + + ..\packages\Microsoft.AspNet.Mvc.FixedDisplayModes.1.0.1\lib\net40\Microsoft.Web.Mvc.FixedDisplayModes.dll + + + ..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll + + + ..\packages\MySql.Data.6.6.5\lib\net40\MySql.Data.dll + + + ..\packages\Newtonsoft.Json.4.5.11\lib\net40\Newtonsoft.Json.dll + + + ..\packages\UmbracoCms.Core.7.0.1\lib\SQLCE4Umbraco.dll + + + + + True + ..\packages\UmbracoCms.Core.7.0.1\lib\System.Data.SqlServerCe.dll + + + True + ..\packages\UmbracoCms.Core.7.0.1\lib\System.Data.SqlServerCe.Entity.dll + + + + ..\packages\Microsoft.AspNet.WebApi.Client.4.0.30506.0\lib\net40\System.Net.Http.Formatting.dll + + + + True + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.Helpers.dll + + + ..\packages\Microsoft.AspNet.WebApi.Core.4.0.30506.0\lib\net40\System.Web.Http.dll + + + ..\packages\Microsoft.AspNet.WebApi.WebHost.4.0.30506.0\lib\net40\System.Web.Http.WebHost.dll + + + True + ..\packages\Microsoft.AspNet.Mvc.4.0.30506.0\lib\net40\System.Web.Mvc.dll + + + True + ..\packages\Microsoft.AspNet.Razor.2.0.30506.0\lib\net40\System.Web.Razor.dll + + + True + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.dll + + + True + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Deployment.dll + + + True + ..\packages\Microsoft.AspNet.WebPages.2.0.30506.0\lib\net40\System.Web.WebPages.Razor.dll + + + + + + + + ..\packages\UmbracoCms.Core.7.0.1\lib\TidyNet.dll + + + ..\packages\UmbracoCms.Core.7.0.1\lib\umbraco.dll + + + ..\packages\UmbracoCms.Core.7.0.1\lib\Umbraco.Core.dll + + + ..\packages\UmbracoCms.Core.7.0.1\lib\umbraco.DataLayer.dll + + + ..\packages\UmbracoCms.Core.7.0.1\lib\umbraco.editorControls.dll + + + ..\packages\UmbracoCms.Core.7.0.1\lib\umbraco.MacroEngines.dll + + + ..\packages\UmbracoCms.Core.7.0.1\lib\umbraco.providers.dll + + + ..\packages\UmbracoCms.Core.7.0.1\lib\Umbraco.Web.UI.dll + + + ..\packages\UmbracoCms.Core.7.0.1\lib\umbraco.XmlSerializers.dll + + + ..\packages\UmbracoCms.Core.7.0.1\lib\UmbracoExamine.dll + + + ..\packages\UmbracoCms.Core.7.0.1\lib\UrlRewritingNet.UrlRewriter.dll + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/Umbraco/Umbraco.Archetype/Extensions/Extensions.cs b/app/Umbraco/Umbraco.Archetype/Extensions/Extensions.cs new file mode 100644 index 0000000..b875475 --- /dev/null +++ b/app/Umbraco/Umbraco.Archetype/Extensions/Extensions.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Archetype.Umbraco.Extensions +{ + public static class Extensions + { + //lifted from the core as it is marked 'internal' + public static bool DetectIsJson(this string input) + { + input = input.Trim(); + return input.StartsWith("{") && input.EndsWith("}") + || input.StartsWith("[") && input.EndsWith("]"); + } + } +} diff --git a/app/Umbraco/Umbraco.Archetype/Models/Archetype.cs b/app/Umbraco/Umbraco.Archetype/Models/Archetype.cs new file mode 100644 index 0000000..380e41b --- /dev/null +++ b/app/Umbraco/Umbraco.Archetype/Models/Archetype.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Archetype.Umbraco.Models +{ + public class Archetype + { + public IEnumerable
Fieldsets { get; set; } + + public Archetype() + { + Fieldsets = new List
(); + } + } +} diff --git a/app/Umbraco/Umbraco.Archetype/Models/Fieldset.cs b/app/Umbraco/Umbraco.Archetype/Models/Fieldset.cs new file mode 100644 index 0000000..e2aeaee --- /dev/null +++ b/app/Umbraco/Umbraco.Archetype/Models/Fieldset.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Umbraco.Core; + +namespace Archetype.Umbraco.Models +{ + public class Fieldset + { + public string Alias { get; set; } + public IEnumerable Properties; + + public Fieldset() + { + Properties = new List(); + } + + public string GetValue(string propertyAlias) + { + return GetValue(propertyAlias); + } + + public T GetValue(string propertyAlias) + { + var property = GetProperty(propertyAlias); + + if (property == null || string.IsNullOrEmpty(property.Value)) + return default(T); + + var convertAttempt = property.Value.TryConvertTo(); + + if (convertAttempt.Success) + return convertAttempt.Result; + + return default(T); + } + + private Property GetProperty(string propertyAlias) + { + return Properties.FirstOrDefault(p => p.Alias.InvariantEquals(propertyAlias)); + } + + } +} diff --git a/app/Umbraco/Umbraco.Archetype/Models/Property.cs b/app/Umbraco/Umbraco.Archetype/Models/Property.cs new file mode 100644 index 0000000..f8dc12f --- /dev/null +++ b/app/Umbraco/Umbraco.Archetype/Models/Property.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Archetype.Umbraco.Models +{ + public class Property + { + public string Alias { get; set; } + public string Value { get; set; } + } +} diff --git a/app/Umbraco/Umbraco.Archetype/Properties/AssemblyInfo.cs b/app/Umbraco/Umbraco.Archetype/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..20fd3a3 --- /dev/null +++ b/app/Umbraco/Umbraco.Archetype/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Archetype")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Archetype")] +[assembly: AssemblyCopyright("Copyright © 2014")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("e37e94f9-c7ba-4b54-b7e1-64419b3dba0b")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/app/Umbraco/Umbraco.Archetype/PropertyConverters/ArchetypeValueConverter.cs b/app/Umbraco/Umbraco.Archetype/PropertyConverters/ArchetypeValueConverter.cs new file mode 100644 index 0000000..a087e13 --- /dev/null +++ b/app/Umbraco/Umbraco.Archetype/PropertyConverters/ArchetypeValueConverter.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Newtonsoft.Json; +using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Models.PublishedContent; +using Archetype.Umbraco.Models; +using Archetype.Umbraco.Extensions; + +namespace Archetype.Umbraco.PropertyConverters +{ + /* based on the Tim Geyssens sample at: https://github.com/TimGeyssens/MatrixPropEditor/blob/master/SamplePropertyValueConverter/SamplePropertyValueConverter/MatrixValueConverter.cs */ + [PropertyValueType(typeof(Archetype.Umbraco.Models.Archetype))] + [PropertyValueCache(PropertyCacheValue.All, PropertyCacheLevel.Content)] + public class ArchetypeValueConverter : PropertyValueConverterBase + { + public override bool IsConverter(PublishedPropertyType propertyType) + { + return propertyType.PropertyEditorAlias.Equals("Imulus.Archetype"); + } + + public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview) + { + if (source == null) return null; + + var sourceString = source.ToString(); + + if (sourceString.DetectIsJson()) + { + try + { + var archetype = JsonConvert.DeserializeObject (sourceString); + return archetype; + } + catch (Exception ex) + { + return null; + } + } + + return sourceString; + } + } +} diff --git a/app/Umbraco/Umbraco.Archetype/packages.config b/app/Umbraco/Umbraco.Archetype/packages.config new file mode 100644 index 0000000..7918cdf --- /dev/null +++ b/app/Umbraco/Umbraco.Archetype/packages.config @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/config/config.views.js b/app/config/config.views.js new file mode 100644 index 0000000..bdc81fc --- /dev/null +++ b/app/config/config.views.js @@ -0,0 +1,22 @@ +[ + { + "name": "Textstring", + "path": "/umbraco/views/propertyeditors/textbox/textbox.html" + }, + { + "name": "Content Picker", + "path": "/umbraco/views/propertyeditors/contentpicker/contentpicker.html" + }, + { + "name": "Boolean", + "path": "/umbraco/views/propertyeditors/boolean/boolean.html" + }, + { + "name": "Checkbox List", + "path": "/umbraco/views/propertyeditors/checkboxlist/checkboxlist.html" + }, + { + "name": "Radio Buttons", + "path": "/umbraco/views/propertyeditors/radiobuttons/radiobuttons.html" + } +] \ No newline at end of file diff --git a/app/controllers/config.controller.js b/app/controllers/config.controller.js new file mode 100644 index 0000000..8a6734f --- /dev/null +++ b/app/controllers/config.controller.js @@ -0,0 +1,239 @@ +angular.module("umbraco").controller("Imulus.ArchetypeConfigController", function ($scope, $http, assetsService, propertyEditorService) { + + //$scope.model.value = ""; + //console.log($scope.model.value); + + var newPropertyModel = '{alias: "", remove: false, collapse: false, label: "", helpText: "", view: "", value: "", config: ""}'; + var newFieldsetModel = '{alias: "", remove: false, collapse: false, labelTemplate: "", tooltip: "", icon: "", label: "", headerText: "", footerText: "", properties:[' + newPropertyModel + ']}'; + var defaultFieldsetConfigModel = eval("({showAdvancedOptions: false, hideFieldsetToolbar: false, enableMultipleFieldsets: false, hideFieldsetControls: false, hideFieldsetLabels: false, hidePropertyLabel: false, maxFieldsets: null, fieldsets: [" + newFieldsetModel + "]})"); + + $scope.model.value = $scope.model.value || defaultFieldsetConfigModel; + + initConfigRenderModel(); + + //get the available views + propertyEditorService.getViews().then(function(data){ + $scope.availableViews = data; + }); + + $scope.sortableOptions = { + axis: 'y', + cursor: "move", + handle: ".handle", + update: function (ev, ui) { + + }, + stop: function (ev, ui) { + + } + }; + + $scope.focusFieldset = function(fieldset){ + var iniState; + + if(fieldset) + { + iniState = fieldset.collapse; + } + + _.each($scope.archetypeConfigRenderModel.fieldsets, function(fieldset){ + if($scope.archetypeConfigRenderModel.fieldsets.length == 1 && fieldset.remove == false) + { + fieldset.collapse = false; + return; + } + + if(fieldset.label) + { + fieldset.collapse = true; + } + else + { + fieldset.collapse = false; + } + }); + + if(iniState) + { + fieldset.collapse = !iniState; + } + } + //ini + $scope.focusFieldset(); + + $scope.focusProperty = function(properties, property){ + var iniState; + + if(property) + { + iniState = property.collapse; + } + + _.each(properties, function(property){ + if(property.label) + { + property.collapse = true; + } + else + { + property.collapse = false; + } + }); + + if(iniState) + { + property.collapse = !iniState; + } + } + + //setup JSON.stringify helpers + $scope.archetypeConfigRenderModel.toString = stringify; + + //encapsulate stringify (should be built into browsers, not sure of IE support) + function stringify() { + return JSON.stringify(this); + } + + //watch for changes + $scope.$watch('archetypeConfigRenderModel', function (v) { + //console.log(v); + if (typeof v === 'string') { + $scope.archetypeConfigRenderModel = JSON.parse(v); + $scope.archetypeConfigRenderModel.toString = stringify; + } + }, true); + + //helper that returns if an item can be removed + $scope.canRemoveFieldset = function () + { + return countVisibleFieldset() > 1; + } + + //helper that returns if an item can be sorted + $scope.canSortFieldset = function () + { + return countVisibleFieldset() > 1; + } + + //helper that returns if an item can be removed + $scope.canRemoveProperty = function (fieldset) + { + return countVisibleProperty(fieldset) > 1; + } + + //helper that returns if an item can be sorted + $scope.canSortProperty = function (fieldset) + { + return countVisibleProperty(fieldset) > 1; + } + + //helper to count what is visible + function countVisibleFieldset() + { + var count = 0; + + _.each($scope.archetypeConfigRenderModel.fieldsets, function(fieldset){ + if (fieldset.remove == false) { + count++; + } + }); + + return count; + } + + function countVisibleProperty(fieldset) + { + var count = 0; + + for (var i in fieldset.properties) { + if (fieldset.properties[i].remove == false) { + count++; + } + } + + return count; + } + + //handles a fieldset add + $scope.addFieldsetRow = function ($index, $event) { + $scope.archetypeConfigRenderModel.fieldsets.splice($index + 1, 0, eval("(" + newFieldsetModel + ")")); + $scope.focusFieldset(); + } + + //rather than splice the archetypeConfigRenderModel, we're hiding this and cleaning onFormSubmitting + $scope.removeFieldsetRow = function ($index) { + if ($scope.canRemoveFieldset()) { + if (confirm('Are you sure you want to remove this?')) { + $scope.archetypeConfigRenderModel.fieldsets[$index].remove = true; + } + } + } + + //handles a property add + $scope.addPropertyRow = function (fieldset, $index) { + fieldset.properties.splice($index + 1, 0, eval("(" + newPropertyModel + ")")); + } + + //rather than splice the archetypeConfigRenderModel, we're hiding this and cleaning onFormSubmitting + $scope.removePropertyRow = function (fieldset, $index) { + if ($scope.canRemoveProperty(fieldset)) { + if (confirm('Are you sure you want to remove this?')) { + fieldset.properties[$index].remove = true; + } + } + } + + //helper to ini the render model + function initConfigRenderModel() + { + $scope.archetypeConfigRenderModel = $scope.model.value; + + _.each($scope.archetypeConfigRenderModel.fieldsets, function(fieldset){ + + fieldset.remove = false; + + if(fieldset.label) + { + fieldset.collapse = true; + } + + _.each(fieldset.properties, function(fieldset){ + fieldset.remove = false; + }); + }); + } + + //sync things up on save + $scope.$on("formSubmitting", function (ev, args) { + syncModelToRenderModel(); + }); + + //helper to sync the model to the renderModel + function syncModelToRenderModel() + { + $scope.model.value = $scope.archetypeConfigRenderModel; + var fieldsets = []; + + _.each($scope.archetypeConfigRenderModel.fieldsets, function(fieldset){ + //check fieldsets + if (!fieldset.remove) { + fieldsets.push(fieldset); + + var properties = []; + + _.each(fieldset.properties, function(property){ + if (!property.remove) { + properties.push(property); + } + }); + + fieldset.properties = properties; + } + }); + + $scope.model.value.fieldsets = fieldsets; + } + + //archetype css + assetsService.loadCss("/App_Plugins/Archetype/css/archetype.css"); +}); diff --git a/app/controllers/controller.js b/app/controllers/controller.js index d475c57..39beb32 100644 --- a/app/controllers/controller.js +++ b/app/controllers/controller.js @@ -1,28 +1,41 @@ -angular.module("umbraco").controller("Imulus.ArchetypeController", function ($scope, $http, assetsService) { +angular.module("umbraco").controller("Imulus.ArchetypeController", function ($scope, $http, $interpolate, assetsService, angularHelper, notificationsService) { //$scope.model.value = ""; - //set default value of the model //this works by checking to see if there is a model; then cascades to the default model then to an empty fieldset - //validate the user configs - $scope.model.config.defaultModel = getValidJson("$scope.model.config.defaultModel", $scope.model.config.defaultModel); - $scope.model.config.fieldsetModels = getValidJson("$scope.model.config.fieldsetModels", $scope.model.config.fieldsetModels); + var form = angularHelper.getCurrentForm($scope); - $scope.model.value = $scope.model.value || ($scope.model.config.defaultModel || { fieldsets: [getEmptyRenderItem($scope.model.config.fieldsetModels[0])] }); + $scope.model.config = $scope.model.config.archetypeConfig; + + $scope.model.value = $scope.model.value || { fieldsets: [getEmptyRenderFieldset($scope.model.config.fieldsets[0])] }; //ini $scope.archetypeRenderModel = {}; initArchetypeRenderModel(); + + //helper to get $eval the labelTemplate + $scope.getFieldsetTitle = function(fieldsetConfigModel, fieldsetIndex) { + var fieldset = $scope.archetypeRenderModel.fieldsets[fieldsetIndex]; + var template = fieldsetConfigModel.labelTemplate; + var rgx = /{{(.*?)}}*/g; + var results; + var parsedTemplate = template; + + while ((results = rgx.exec(template)) !== null) { + var propertyAlias = results[1]; + var propertyValue = $scope.getPropertyValueByAlias(fieldset, propertyAlias); + parsedTemplate = parsedTemplate.replace(results[0], propertyValue); + } + + return parsedTemplate; + }; /* add/remove/sort */ //defines the options for the jquery sortable //i used an ng-model="archetypeRenderModel" so the sort updates the right model - //configuration overrides the default - var configSortableOptions = getValidJson("$scope.model.config.sortableOptions", $scope.model.config.sortableOptions); - - $scope.sortableOptions = configSortableOptions || { + $scope.sortableOptions = { axis: 'y', cursor: "move", handle: ".handle", @@ -38,19 +51,21 @@ $scope.addRow = function (fieldsetAlias, $index) { if ($scope.canAdd()) { - if ($scope.model.config.fieldsetModels) + if ($scope.model.config.fieldsets) { - var newRenderItem = getEmptyRenderItem($scope.getConfigFieldsetByAlias(fieldsetAlias)); + var newFieldset = getEmptyRenderFieldset($scope.getConfigFieldsetByAlias(fieldsetAlias)); if (typeof $index != 'undefined') { - $scope.archetypeRenderModel.fieldsets.splice($index + 1, 0, newRenderItem); + $scope.archetypeRenderModel.fieldsets.splice($index + 1, 0, newFieldset); } else { - $scope.archetypeRenderModel.fieldsets.push(newRenderItem); + $scope.archetypeRenderModel.fieldsets.push(newFieldset); } } + newFieldset.collapse = true; + $scope.focusFieldset(newFieldset); } } @@ -66,9 +81,9 @@ //helpers for determining if a user can do something $scope.canAdd = function () { - if ($scope.model.config.maxProperties) + if ($scope.model.config.maxFieldsets) { - return countVisible() < $scope.model.config.maxProperties; + return countVisible() < $scope.model.config.maxFieldsets; } return true; @@ -89,16 +104,58 @@ //helper, ini the render model from the server (model.value) function initArchetypeRenderModel() { $scope.archetypeRenderModel = $scope.model.value; + + _.each($scope.archetypeRenderModel.fieldsets, function (fieldset) + { + fieldset.remove = false; + fieldset.collapse = false; + fieldset.isValid = true; + }); } //helper to get the correct fieldset from config $scope.getConfigFieldsetByAlias = function(alias) { - for (var i in $scope.model.config.fieldsetModels) { - if ($scope.model.config.fieldsetModels[i].alias == alias) { - return $scope.model.config.fieldsetModels[i]; + return _.find($scope.model.config.fieldsets, function(fieldset){ + return fieldset.alias == alias; + }); + } + + //helper to get a property by alias from a fieldset + $scope.getPropertyValueByAlias = function(fieldset, propertyAlias) { + var property = _.find(fieldset.properties, function(p) { + return p.alias == propertyAlias; + }); + return (typeof property !== 'undefined') ? property.value : ''; + }; + + //helper for collapsing + $scope.focusFieldset = function(fieldset){ + + var iniState; + + if(fieldset) + { + iniState = fieldset.collapse; + } + + _.each($scope.archetypeRenderModel.fieldsets, function(fieldset){ + if($scope.archetypeRenderModel.fieldsets.length == 1 && fieldset.remove == false) + { + fieldset.collapse = false; + return; } + + fieldset.collapse = true; + }); + + if(iniState) + { + fieldset.collapse = !iniState; } } + + //ini + $scope.focusFieldset(); //helper returns valid JS or null function getValidJson(variable, json) @@ -126,7 +183,7 @@ //watch for changes $scope.$watch('archetypeRenderModel', function (v) { if ($scope.model.config.developerMode) { - //console.log(v); + console.log(v); if (typeof v === 'string') { $scope.archetypeRenderModel = JSON.parse(v); $scope.archetypeRenderModel.toString = stringify; @@ -139,11 +196,11 @@ { var count = 0; - for (var i in $scope.archetypeRenderModel.fieldsets) { - if ($scope.archetypeRenderModel.fieldsets[i].remove == false) { + _.each($scope.archetypeRenderModel.fieldsets, function(fieldset){ + if (fieldset.remove == false) { count++; } - } + }); return count; } @@ -153,24 +210,111 @@ { $scope.model.value = { fieldsets: [] }; - for (var i in $scope.archetypeRenderModel.fieldsets) { - if (!$scope.archetypeRenderModel.fieldsets[i].remove) { - //remove the 'remove' property as this is only for sorting/internal use - delete $scope.archetypeRenderModel.fieldsets[i].remove; - $scope.model.value.fieldsets.push($scope.archetypeRenderModel.fieldsets[i]); + _.each($scope.archetypeRenderModel.fieldsets, function(fieldset){ + if (typeof fieldset != 'function' && !fieldset.remove){ + + //clone and clean + var tempFieldset = JSON.parse(JSON.stringify(fieldset)); + delete tempFieldset.remove; + delete tempFieldset.isValid; + delete tempFieldset.collapse; + + _.each(tempFieldset.properties, function(property){ + delete property.isValid; + }); + + $scope.model.value.fieldsets.push(tempFieldset); } - } + }); } //helper to add an empty fieldset - function getEmptyRenderItem (fieldsetModel) + function getEmptyRenderFieldset (fieldsetModel) { return eval("({ alias: '" + fieldsetModel.alias + "', remove: false, properties: []})"); } + //helper for validation + function getValidation() + { + var validation = {} + validation.isValid = true; + validation.requiredAliases = []; + validation.invalidProperties = []; + + //determine which fields are required + _.each($scope.model.config.fieldsets, function(fieldset){ + _.each(fieldset.properties, function(property){ + if(property.required) + { + validation.requiredAliases.push(property.alias); + } + }); + }); + + //if nothing required; let's go + if(validation.requiredAliases.length == 0) + { + return validation; + } + + //otherwise we need to check the required aliases + _.each($scope.archetypeRenderModel.fieldsets, function(fieldset){ + fieldset.isValid = true; + + _.each(fieldset.properties, function(property){ + property.isValid = true; + + //if a required field + if(_.find(validation.requiredAliases, function(alias){ return alias == property.alias })) + { + //TODO: do a better validation test + if(property.value == ""){ + fieldset.isValid = false; + property.isValid = false; + validation.isValid = false; + + validation.invalidProperties.push(property); + } + } + }); + }); + + if($scope.model.config.developerMode == '1') + { + console.log(validation); + } + + return validation; + } + + $scope.getPropertyValidity = function(fieldsetIndex, alias) + { + if($scope.archetypeRenderModel.fieldsets[fieldsetIndex]) + { + var property = _.find($scope.archetypeRenderModel.fieldsets[fieldsetIndex].properties, function(property){ + return property.alias == alias; + }); + } + + return (typeof property == 'undefined') ? true : property.isValid; + } + //sync things up on save $scope.$on("formSubmitting", function (ev, args) { - syncModelToRenderModel(); + + var validation = getValidation(); + + if(!validation.isValid) + { + notificationsService.warning("Cannot Save Document", "The document could not be saved because of missing required fields.") + form.$setValidity("archetypeError", false); + } + else + { + syncModelToRenderModel(); + form.$setValidity("archetypeError", true); + } }); //custom js @@ -179,7 +323,7 @@ } //archetype css - assetsService.loadCss("/App_Plugins/Imulus.Archetype/css/archetype.css"); + assetsService.loadCss("/App_Plugins/Archetype/css/archetype.css"); //custom css if($scope.model.config.customCssPath) diff --git a/app/directives/archetypeproperty.js b/app/directives/archetypeproperty.js index 632a675..06dc6da 100644 --- a/app/directives/archetypeproperty.js +++ b/app/directives/archetypeproperty.js @@ -1,12 +1,12 @@ angular.module("umbraco").directive('archetypeProperty', function ($compile, $http) { - function getFieldsetByAlias(fieldsetModels, alias) + function getFieldsetByAlias(fieldsets, alias) { - for (var i in fieldsetModels) + for (var i in fieldsets) { - if (fieldsetModels[i].alias == alias) + if (fieldsets[i].alias == alias) { - return fieldsetModels[i]; + return fieldsets[i]; } } } @@ -23,13 +23,54 @@ var linker = function (scope, element, attrs) { - var configFieldsetModel = getFieldsetByAlias(scope.archetypeConfig.fieldsetModels, scope.fieldset.alias); + var configFieldsetModel = getFieldsetByAlias(scope.archetypeConfig.fieldsets, scope.fieldset.alias); var view = configFieldsetModel.properties[scope.propertyConfigIndex].view; var label = configFieldsetModel.properties[scope.propertyConfigIndex].label; var config = configFieldsetModel.properties[scope.propertyConfigIndex].config; var alias = configFieldsetModel.properties[scope.propertyConfigIndex].alias; + var defaultValue = configFieldsetModel.properties[scope.propertyConfigIndex].value; + //try to convert the config to a JS object + if(config && typeof config == 'string'){ + try{ + if(scope.archetypeConfig.developerMode == '1'){ + console.log("Trying to eval config: " + config); + } + config = eval("(" + config + ")"); + } + catch(exception) + { + if(scope.archetypeConfig.developerMode == '1'){ + console.log("Failed to eval config."); + } + } + } + + if(config && scope.archetypeConfig.developerMode == '1'){ + console.log("Config post-eval: " + config); + } + + //try to convert the defaultValue to a JS object + if(defaultValue && typeof defaultValue == 'string'){ + try{ + if(scope.archetypeConfig.developerMode == '1'){ + console.log("Trying to eval default value: " + defaultValue); + } + defaultValue = eval("(" + defaultValue + ")"); + } + catch(exception) + { + if(scope.archetypeConfig.developerMode == '1'){ + console.log("Failed to eval defaultValue."); + } + } + } + + if(defaultValue && scope.archetypeConfig.developerMode == '1'){ + console.log("Default value post-eval: " + defaultValue); + } + if (view) { $http.get(view).success(function (data) { @@ -50,7 +91,7 @@ if (!renderModelPropertyIndex) { - scope.archetypeRenderModel.fieldsets[scope.fieldsetIndex].properties.push(eval("({alias: '" + alias + "', value:''})")); + scope.archetypeRenderModel.fieldsets[scope.fieldsetIndex].properties.push(eval("({alias: '" + alias + "', value:'" + defaultValue + "'})")); renderModelPropertyIndex = getPropertyIdByAlias(scope.archetypeRenderModel.fieldsets[scope.fieldsetIndex].properties, alias); } scope.model.value = scope.archetypeRenderModel.fieldsets[scope.fieldsetIndex].properties[renderModelPropertyIndex].value; diff --git a/app/less/archetype.less b/app/less/archetype.less index 7329433..9595008 100644 --- a/app/less/archetype.less +++ b/app/less/archetype.less @@ -32,6 +32,7 @@ .archetypeEditor .archetypeProperty{ clear: both; overflow: hidden; + margin-top: 3px; } .archetypeEditor .umb-contentpicker{ @@ -76,4 +77,114 @@ clear:both; margin-bottom: 3px; font-size: 12px; +} + +.archetypeConfig { + margin-bottom: 20px; +} + +.archetypeConfig ul{ + list-style: none; +} + +.archetypeConfig .archetypeEditorControls{ + float: right; +} + +.archetypeConfig li{ + background-color: #fff; +} + +.archetypeConfig label{ + width: 120px; +} + +.archetypeConfig .archetypeFieldsetWrapper{ + border: 1px solid #ccc; + padding: 10px 5px; + margin-bottom: 10px; +} + +.archetypeConfig .archetypeFieldsetOption input[type=text]{ + width: 600px; +} + +.archetypeConfig .archetypeDeveloperModel { + width: 88%; + margin-left: 30px; + height: 100px; +} + +.archetypeConfig .archetypePropertiesWrapper{ + border: 1px solid #ddd; + padding: 10px; + margin: 10px; + margin-left: 50px; + width: 665px; +} + +.archetypeConfig .archetypePropertiesWrapper ul{ + padding: 0; + margin: 0; +} + +.archetypeConfig .archetypePropertiesWrapper li{ + padding: 10px; + margin-bottom: 10px; + background-color: #eee; +} + +.archetypeConfig .archetypePropertiesWrapper li:last-child{ + margin-bottom: 0; +} + +.archetypeConfig .archetypeFieldsets { + margin-left: 0; +} + +.archetypeConfig .archetypeFieldsetTitle { + overflow: hidden; +} + +.archetypeConfig .archetypeFieldsetCollapser{ + margin-top: 10px; +} + +.archetypeConfig .archetypeOptions label{ + width: 200px; +} + +.archetypeConfig .archetypeAdvancedOptions label{ + width: 400px; +} + +.archetypeConfig .archetypeDeveloperModel { + margin-bottom: 10px; +} + +.archetypeConfig .archetypeMaxFieldsets{ + border: 1px solid #ddd; + width: 25px; + text-align: right; +} + +.archetypeConfig .archetypePropertyTitle{ + overflow: hidden; +} + +.archetypeConfig .archetypePropertyCollapser{ + margin-top: 10px; +} + +.archetypeEditor .archetypeFieldsetError{ + border: 1px solid red; +} + +.archetypeEditor .archetypePropertyError{ + border: 1px solid red; + background-color: #8b0000; + color: #fff; + margin-bottom: 5px; + padding-top: 3px; + padding-bottom: 3px; } \ No newline at end of file diff --git a/app/package.manifest b/app/package.manifest index 2a6744d..edf1d6d 100644 --- a/app/package.manifest +++ b/app/package.manifest @@ -1,129 +1,30 @@ { - propertyEditors: [ + propertyEditors: [ { alias: "Imulus.Archetype", - name: "Imulus Archetype", + name: "Archetype", editor: { - view: "~/App_Plugins/Imulus.Archetype/views/archetype.html", + view: "~/App_Plugins/Archetype/views/archetype.html", valueType: "JSON" - }, + }, prevalues: { - fields: [ - { - label: "Empty Fieldset Models", - description: "(Required) Define your fieldset models?", - key: "fieldsetModels", - view: "textarea", + fields: [ + { + label: "Config", + description: "(Required) Describe your Archetype.", + key: "archetypeConfig", + view: "/App_Plugins/Archetype/views/archetype.config.html", validation: [ { type: "Required" } ] - }, - { - label: "Hide fieldset toolbar?", - description: "Hides the fieldset toolbar that appears when more than one fieldset model appears.", - key: "hideFieldsetToolbar", - view: "boolean", - validation: [ - - ] - }, - { - label: "Hide fieldset editor controls?", - description: "Hides the fieldset add/remove/sort controls.", - key: "hideFieldsetControls", - view: "boolean", - validation: [ - - ] - }, - { - label: "Hide fieldset labels?", - description: "Hides the fieldset labels.", - key: "hideFieldsetLabels", - view: "boolean", - validation: [ - - ] - }, - { - label: "Hide property labels?", - description: "Hides the property labels.", - key: "hidePropertyLabels", - view: "boolean", - validation: [ - - ] - }, - { - label: "Default Model", - description: "(Optional) What would you the default model to be? Otherwise the model will defer to the Empty Fieldset Model for new items.", - key: "defaultModel", - view: "textarea", - validation: [ - - ] - }, - { - label: "Max Fieldsets", - description: "(Optional) How many Fieldsets are allowed? Entering '1' will disable the controls. Default is unlimited.", - key: "maxProperties", - view: "number", - validation: [ - - ] - }, - { - label: "Custom Wrapper Class", - description: "(Optional) Enter a custom CSS class that will be applied to the wrapper div.", - key: "customCssClass", - view: "textstring", - validation: [ - - ] - }, - { - label: "CSS File", - description: "(Optional) Enter a path for a custom CSS file to be included on the page.", - key: "customCssPath", - view: "textstring", - validation: [ - - ] - }, - { - label: "JS File", - description: "(Optional) Enter a path for a custom JS file to be included on the page.", - key: "customJsPath", - view: "textstring", - validation: [ - - ] - }, - { - label: "Developer Mode", - description: "(Advanced) Turn on for developer options.", - key: "developerMode", - view: "boolean", - validation: [ - - ] - }, - { - label: "Sortable Options", - description: "(Advanced) Override the default sortable controls with a JSON object.", - key: "sortableOptions", - view: "textarea", - validation: [ - - ] } ] } } ], javascript: [ - '~/App_Plugins/Imulus.Archetype/js/archetype.js' + '~/App_Plugins/Archetype/js/archetype.js' ] } \ No newline at end of file diff --git a/app/services/propertyeditor.js b/app/services/propertyeditor.js new file mode 100644 index 0000000..57bf02b --- /dev/null +++ b/app/services/propertyeditor.js @@ -0,0 +1,9 @@ +angular.module('umbraco').factory('propertyEditorService', function($q, $http, umbRequestHelper){ + return { + getViews: function() { + return umbRequestHelper.resourcePromise( + $http.get("/App_Plugins/Archetype/js/config.views.js"), 'Failed to retreive config for views.' + ); + } + }; +}); \ No newline at end of file diff --git a/app/views/archetype.config.html b/app/views/archetype.config.html new file mode 100644 index 0000000..c8695f8 --- /dev/null +++ b/app/views/archetype.config.html @@ -0,0 +1,119 @@ +
+
    +
  • +
    +
    + + + +
    +
    {{fieldset.label}}
    +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    +
      +
    • +
      + + + +
      +
      {{property.label}}
      +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      + +
      +
      +
    • +
    +
    +
    +
    +
  • +
+ +
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
+
+ + +
+
+
diff --git a/app/views/archetype.html b/app/views/archetype.html index 84c7bb6..c48ff8d 100644 --- a/app/views/archetype.html +++ b/app/views/archetype.html @@ -1,8 +1,8 @@ 
-
+
    -
  • +
  • {{fieldsetModel.label}}
  • @@ -10,32 +10,34 @@
  • -
    -
diff --git a/package.json b/package.json index 776d9fc..3b23fd6 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,9 @@ "grunt-touch": "~0.1.0", "guid": "0.0.12", "adm-zip": "~0.4.3", - "rimraf": "~2.2.5" + "rimraf": "~2.2.5", + "grunt-nuget": "~0.1.1", + "grunt-template": "~0.2.2", + "grunt-touch": "~0.1.0" } } diff --git a/pkg/nuget/package.nuspec b/pkg/nuget/package.nuspec new file mode 100644 index 0000000..e5143cc --- /dev/null +++ b/pkg/nuget/package.nuspec @@ -0,0 +1,20 @@ + + + + Archetype + <%= version %> + Archetype + imulus, tomfulton + imulus, tomfulton + http://github.com/imulus/archetype + + umbraco + http://github.com/imulus/archetype/raw/master/assets/logo.png + http://www.opensource.org/licenses/mit-license.php + + + <% for (var file in files) { %> + + <% } %> + + \ No newline at end of file