Merge pull request #2 from imulus/feature/dev-tasks

Grunt Tasks for Development
This commit is contained in:
Kevin Giszewski
2014-01-12 11:43:59 -08:00
9 changed files with 290 additions and 94 deletions
+27 -6
View File
@@ -18,7 +18,13 @@ module.exports = function(grunt) {
options: {
spawn: false,
}
},
dev: {
files: ['app/**'],
tasks: ['deploy']
}
},
jshint: {
@@ -34,9 +40,22 @@ module.exports = function(grunt) {
copy: {
main: {
files: [
{expand: true, src: ['app/package.manifest'], dest: '<%= dest %>', flatten: true},
{expand: true, src: ['app/views/archetype.html'], dest: '<%= dest %>/views', flatten: true}
{expand: true, cwd: 'app/', src: ['package.manifest'], dest: '<%= dest %>', flatten: true},
{expand: true, cwd: 'app/views/', src: ['archetype.html'], dest: '<%= dest %>/views', flatten: true}
]
},
deploy: {
files: [
{expand: true, cwd: '<%= dest %>/', src: ['**'], dest: '<%= grunt.option("target") %>\\App_Plugins\\Imulus.Archetype', flatten: false},
]
}
},
touch: {
options: {},
webconfig: {
src: ['D:\\dev\\projects\\imulus-neue\\src\\imulus.umbraco\\web.config']
}
},
@@ -57,8 +76,8 @@ module.exports = function(grunt) {
},
application: {
src: [
'app/controllers/archetype_controller.js',
'app/directives/content_item.js'
'app/controllers/controller.js',
'app/directives/archetypeproperty.js'
],
dest: '<%= dest %>/js/archetype.js'
}
@@ -75,10 +94,12 @@ module.exports = function(grunt) {
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-touch');
grunt.registerTask('touchwebconfigifenabled', function() { if (grunt.option("touch")) grunt.task.run("touch:webconfig") });
grunt.registerTask('deploy', ['default', 'copy:deploy', 'touchwebconfigifenabled']);
grunt.registerTask('css:build', ['less']);
grunt.registerTask('js:build', ['concat']);
grunt.registerTask('default', ['clean', 'css:build', 'js:build', 'copy']);
grunt.registerTask('default', ['clean', 'css:build', 'js:build', 'copy:main']);
};
+4 -1
View File
@@ -12,4 +12,7 @@ Archetype
## Deploy ##
Copy the files in `/dist/` to your Umbraco site, at `/App_Plugins/Archetype/`
grunt deploy --target=C:\\path\\to\\umbraco\\site
grunt watch:dev --target=C:\\path\to\\umbraco\\site
* Add `--touch` to either command to automatically touch the web.config on a deploy
@@ -2,15 +2,14 @@
//$scope.model.value = "";
//test config/model
//$scope.model.config.emptyFieldSetModel = '{ remove: false, properties:[{ type: "textbox", options: { label: "Name" }, data: "" }, { type: "contentPicker", options: { label: "Pick some content" }, data: "" }]}';
//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
var validDefaultModel = getValidJson("$scope.model.config.defaultModel", $scope.model.config.defaultModel);
var validEmptyFieldsetModel = getValidJson("$scope.model.config.emptyFieldsetModel", $scope.model.config.emptyFieldsetModel);
$scope.model.value = $scope.model.value || (validDefaultModel || { fieldsets: [validEmptyFieldsetModel] });
//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);
$scope.model.value = $scope.model.value || ($scope.model.config.defaultModel || { fieldsets: [getEmptyRenderItem($scope.model.config.fieldsetModels[0])] });
//ini
$scope.archetypeRenderModel = {};
@@ -20,7 +19,10 @@
//defines the options for the jquery sortable
//i used an ng-model="archetypeRenderModel" so the sort updates the right model
$scope.sortableOptions = {
//configuration overrides the default
var configSortableOptions = getValidJson("$scope.model.config.sortableOptions", $scope.model.config.sortableOptions);
$scope.sortableOptions = configSortableOptions || {
axis: 'y',
cursor: "move",
handle: ".handle",
@@ -28,18 +30,26 @@
},
stop: function (ev, ui) {
console.log($scope.archetypeRenderModel);
}
};
$scope.addRow = function ($index) {
if (true)
//handles a fieldset add
$scope.addRow = function (fieldsetAlias, $index) {
if ($scope.canAdd())
{
var validJson = getValidJson("$scope.model.config.emptyFieldsetModel", $scope.model.config.emptyFieldsetModel);
if (validJson)
if ($scope.model.config.fieldsetModels)
{
$scope.archetypeRenderModel.fieldsets.splice($index + 1, 0, validJson);
var newRenderItem = getEmptyRenderItem($scope.getConfigFieldsetByAlias(fieldsetAlias));
if (typeof $index != 'undefined')
{
$scope.archetypeRenderModel.fieldsets.splice($index + 1, 0, newRenderItem);
}
else
{
$scope.archetypeRenderModel.fieldsets.push(newRenderItem);
}
}
}
}
@@ -64,11 +74,13 @@
return true;
}
//helper that returns if an item can be removed
$scope.canRemove = function ()
{
return countVisible() > 1;
}
//helper that returns if an item can be sorted
$scope.canSort = function ()
{
return countVisible() > 1;
@@ -79,6 +91,15 @@
$scope.archetypeRenderModel = $scope.model.value;
}
//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];
}
}
}
//helper returns valid JS or null
function getValidJson(variable, json)
{
@@ -97,6 +118,7 @@
//developerMode helpers
$scope.archetypeRenderModel.toString = stringify;
//encapsulate stringify (should be built into browsers, not sure of IE support)
function stringify() {
return JSON.stringify(this);
}
@@ -104,7 +126,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;
@@ -138,6 +160,12 @@
}
}
//helper to add an empty fieldset
function getEmptyRenderItem (fieldsetModel)
{
return eval("({ alias: '" + fieldsetModel.alias + "', remove: false, properties: []})");
}
//sync things up on save
$scope.$on("formSubmitting", function (ev, args) {
syncModelToRenderModel();
@@ -146,10 +174,10 @@
//custom js
if ($scope.model.config.customJsPath) {
assetsService.loadJs($scope.model.config.customJsPath);
}
}
//archetype css
assetsService.loadCss("/App_Plugins/Archetype/css/archetype.css");
assetsService.loadCss("/App_Plugins/Imulus.Archetype/css/archetype.css");
//custom css
if($scope.model.config.customCssPath)
+89
View File
@@ -0,0 +1,89 @@
angular.module("umbraco").directive('archetypeProperty', function ($compile, $http) {
function getFieldsetByAlias(fieldsetModels, alias)
{
for (var i in fieldsetModels)
{
if (fieldsetModels[i].alias == alias)
{
return fieldsetModels[i];
}
}
}
function getPropertyIdByAlias(properties, alias)
{
for (var i in properties)
{
if (properties[i].alias == alias) {
return i;
}
}
}
var linker = function (scope, element, attrs) {
var configFieldsetModel = getFieldsetByAlias(scope.archetypeConfig.fieldsetModels, 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;
if (view)
{
$http.get(view).success(function (data) {
if (data) {
if (scope.archetypeConfig.developerMode == '1')
{
console.log(scope);
}
var rawTemplate = data;
//define the initial model and config
scope.model = {};
scope.model.config = {};
//ini the property value after test to make sure a prop exists in the renderModel
var renderModelPropertyIndex = getPropertyIdByAlias(scope.archetypeRenderModel.fieldsets[scope.fieldsetIndex].properties, alias);
if (!renderModelPropertyIndex)
{
scope.archetypeRenderModel.fieldsets[scope.fieldsetIndex].properties.push(eval("({alias: '" + alias + "', value:''})"));
renderModelPropertyIndex = getPropertyIdByAlias(scope.archetypeRenderModel.fieldsets[scope.fieldsetIndex].properties, alias);
}
scope.model.value = scope.archetypeRenderModel.fieldsets[scope.fieldsetIndex].properties[renderModelPropertyIndex].value;
//set the config from the prevalues
scope.model.config = config;
//some items need an alias
scope.model.alias = "scope-" + scope.$id;
//watch for changes since there is no two-way binding with the local model.value
scope.$watch('model.value', function (newValue, oldValue) {
scope.archetypeRenderModel.fieldsets[scope.fieldsetIndex].properties[renderModelPropertyIndex].value = newValue;
});
element.html(rawTemplate).show();
$compile(element.contents())(scope);
}
});
}
}
return {
restrict: "E",
rep1ace: true,
link: linker,
scope: {
property: '=',
propertyConfigIndex: '=',
archetypeConfig: '=',
fieldset: '=',
fieldsetIndex: '=',
archetypeRenderModel: '='
}
}
});
-47
View File
@@ -1,47 +0,0 @@
angular.module("umbraco").directive('contentItem', function ($compile, $http) {
var linker = function (scope, element, attrs) {
if (scope.content.view)
{
$http.get(scope.content.view).success(function (data) {
if (data) {
var rawTemplate = data;
//define the initial model and config
scope.model = {};
scope.model.config = {};
//pull these from the content
scope.model.value = scope.content.value;
scope.model.config = scope.content.config;
//some items need an alias
scope.model.alias = "scope-" + scope.$id;
//watch for changes since there is no two-way binding with the child values
scope.$watch('model.value', function (newValue, oldValue) {
scope.content.value = newValue;
});
//add label
if (true) {
rawTemplate = '<label>{{content.options.label}}</label>' + rawTemplate;
}
element.html(rawTemplate).show();
$compile(element.contents())(scope);
}
});
}
}
return {
restrict: "E",
rep1ace: true,
link: linker,
scope: {
content: '='
}
}
});
+39
View File
@@ -3,6 +3,7 @@
padding: 5px;
margin-bottom: 5px;
background-color: #fff;
clear: both;
}
.archetypeEditor label{
@@ -10,6 +11,12 @@
float: left;
}
.archetypeEditor fieldset>label{
float: left;
width: 200px;
padding-left: 0;
}
.archetypeEditor .multiPropertyTextbox{
margin-bottom: 3px;
}
@@ -24,6 +31,7 @@
.archetypeEditor .archetypeProperty{
clear: both;
overflow: hidden;
}
.archetypeEditor .umb-contentpicker{
@@ -37,4 +45,35 @@
min-height: 100px;
margin-bottom: 10px;
border: 1px solid red;
}
.archetypeEditor .archetypeFieldsetToolbar {
margin-bottom: 10px;
overflow: hidden;
}
.archetypeEditor .archetypeFieldsetToolbar li {
float: left;
padding: 2px 4px;
margin-right: 10px;
border: 1px solid #ddd;
cursor: pointer;
}
.archetypeEditor .archetypeFieldsetHeaderText{
clear:both;
margin-bottom: 3px;
font-size: 12px;
}
.archetypeEditor .archetypeFieldsetFooterText{
clear:both;
margin-bottom: 3px;
font-size: 12px;
}
.archetypeEditor .archetypeFieldsetHelpText{
clear:both;
margin-bottom: 3px;
font-size: 12px;
}
+53 -16
View File
@@ -1,27 +1,56 @@
{
propertyEditors: [
{
alias: "Archetype",
name: "Archetype",
alias: "Imulus.Archetype",
name: "Imulus Archetype",
editor: {
view: "~/App_Plugins/Archetype/views/archetype.html",
view: "~/App_Plugins/Imulus.Archetype/views/archetype.html",
valueType: "JSON"
},
prevalues: {
fields: [
{
label: "Empty Fieldset Model",
description: "(Required) What would you like a new fieldset model to be?",
key: "emptyFieldsetModel",
label: "Empty Fieldset Models",
description: "(Required) Define your fieldset models?",
key: "fieldsetModels",
view: "textarea",
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 editor controls?",
description: "Hide the add/remove/sort controls",
key: "hideControls",
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: [
@@ -46,8 +75,8 @@
]
},
{
label: "Custom Class",
description: "(Optional) Enter a custom CSS class.",
label: "Custom Wrapper Class",
description: "(Optional) Enter a custom CSS class that will be applied to the wrapper div.",
key: "customCssClass",
view: "textstring",
validation: [
@@ -69,24 +98,32 @@
key: "customJsPath",
view: "textstring",
validation: [
]
},
{
label: "Developer Mode",
description: "Turn on for developer options.",
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/Archetype/js/archetype.js'
'~/App_Plugins/Imulus.Archetype/js/archetype.js'
]
}
+31 -6
View File
@@ -1,16 +1,41 @@
<div class="archetypeEditor ng-class:model.config.customCssClass" ng-controller="Imulus.ArchetypeController">
<textarea class="archetypeDeveloperModel" ng-show="model.config.developerMode" ng-model="archetypeRenderModel"></textarea>
<div class="archetypeFieldsetToolbar" ng-show="model.config.fieldsetModels.length > 1 && model.config.hideFieldsetToolbar != '1'">
<ul>
<li ng-repeat="fieldsetModel in model.config.fieldsetModels" ng-click="addRow(fieldsetModel.alias)">
<img ng-src='{{fieldsetModel.icon}}' title="{{fieldsetModel.tooltip}}" />
<span>{{fieldsetModel.label}}</span>
</li>
</ul>
</div>
<ul ui-sortable="sortableOptions" ng-model="archetypeRenderModel.fieldsets">
<li ng-repeat="fieldset in archetypeRenderModel.fieldsets" ng-hide="fieldset.remove">
<fieldset>
<div class="archetypeEditorControls" ng-hide="model.config.hideControls || model.config.maxProperties == '1'">
<i class="icon icon-add" ng-click="addRow($index)" ng-show="canAdd()"></i>
<fieldset ng-class="fieldset.alias" ng-init="fieldsetConfigModel=getConfigFieldsetByAlias(fieldset.alias)">
<label ng-hide="model.config.hideFieldsetLabels == '1'">
<img ng-src='{{fieldsetConfigModel.icon}}' title="{{fieldsetConfigModel.tooltip}}"/>
<span>{{fieldsetConfigModel.label}}</span>
</label>
<div class="archetypeEditorControls" ng-hide="model.config.hideFieldsetControls || model.config.maxProperties == '1'">
<i class="icon icon-add" ng-click="addRow(fieldset.alias, $index)" ng-show="canAdd()"></i>
<i class="icon icon-delete" ng-click="removeRow($index)" ng-show="canRemove()"></i>
<i class="icon icon-navigation handle" ng-show="canSort()"></i>
</div>
<div class="archetypeProperty" ng-repeat="property in fieldset.properties">
<content-item content="property"></content-item>
</div>
<div class="archetypeFieldsetHeaderText" ng-show="fieldsetConfigModel.headerText">
<em>{{fieldsetConfigModel.headerText}}</em>
</div>
<div class="archetypeProperty" ng-repeat="property in fieldsetConfigModel.properties">
<label ng-hide="archetypeConfig.hidePropertyLabels == '1'">
<span>{{property.label}}</span>
<div class="archetypeFieldsetHelpText" ng-show="property.helpText">
<em>{{property.helpText}}</em>
</div>
</label>
<archetype-property class="archetypeEditor ng-class:property.alias" property="property" fieldset-index="$parent.$index" fieldset="fieldset" archetype-config="model.config" property-config-index="$index" archetype-render-model="archetypeRenderModel"></archetype-property>
</div>
<div class="archetypeFieldsetFooterText" ng-show="fieldsetConfigModel.footerText">
<em>{{fieldsetConfigModel.footerText}}</em>
</div>
</fieldset>
</li>
</ul>
+2 -1
View File
@@ -11,6 +11,7 @@
"grunt-contrib-watch": "~0.5.3",
"grunt-contrib-jshint": "~0.7.2",
"grunt-cli": "~0.1.11",
"grunt-contrib-clean": "~0.5.0"
"grunt-contrib-clean": "~0.5.0",
"grunt-touch": "~0.1.0"
}
}