diff --git a/src/Umbraco.Web.UI/umbraco/Views/content/edit.html b/src/Umbraco.Web.UI/umbraco/Views/content/edit.html new file mode 100644 index 0000000000..a6899fa675 --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/Views/content/edit.html @@ -0,0 +1,36 @@ + + +
+ +
+ +
+
+ + +
+ Publish + + + + + + +
+
+
+
+ + + + + + +
diff --git a/src/Umbraco.Web.UI/umbraco/Views/directives/umb-header.html b/src/Umbraco.Web.UI/umbraco/Views/directives/umb-header.html new file mode 100644 index 0000000000..799cf2312b --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/Views/directives/umb-header.html @@ -0,0 +1,13 @@ +
+
+ +
+ + +
+
\ No newline at end of file diff --git a/src/Umbraco.Web.UI/umbraco/js/umbraco.controllers.js b/src/Umbraco.Web.UI/umbraco/js/umbraco.controllers.js index 3b3bc93521..fbee16c84f 100644 --- a/src/Umbraco.Web.UI/umbraco/js/umbraco.controllers.js +++ b/src/Umbraco.Web.UI/umbraco/js/umbraco.controllers.js @@ -165,13 +165,16 @@ angular.module('umbraco').controller("Umbraco.Editors.ContentCreateController", return; }); }); -angular.module("umbraco").controller("Umbraco.Editors.ContentEditController", function ($scope, $routeParams, contentResource, notifications) { +angular.module("umbraco").controller("Umbraco.Editors.ContentEditController", function ($scope, $routeParams, contentResource, notifications, $q) { if($routeParams.create) - $scope.content = contentResource.getContentScaffold($routeParams.parentId, $routeParams.doctype); - else - $scope.content = contentResource.getContent($routeParams.id); - + $scope.content = contentResource.getContentScaffold($routeParams.parentId, $routeParams.doctype); + else { + $q.when(contentResource.getContent($routeParams.id)) + .then(function (data) { + $scope.content = data; + }); + } $scope.saveAndPublish = function (cnt) { cnt.publishDate = new Date(); diff --git a/src/Umbraco.Web.UI/umbraco/js/umbraco.directives.js b/src/Umbraco.Web.UI/umbraco/js/umbraco.directives.js index cda7d4e49c..1a14405226 100644 --- a/src/Umbraco.Web.UI/umbraco/js/umbraco.directives.js +++ b/src/Umbraco.Web.UI/umbraco/js/umbraco.directives.js @@ -4,7 +4,7 @@ * Licensed MIT */ 'use strict'; -define(['app', 'angular'], function (app, angular) { +define(['app', 'angular', 'underscore'], function (app, angular, _) { /** * @ngdoc directive @@ -231,41 +231,52 @@ angular.module('umbraco.directives', []) replace: true, transclude: 'true', templateUrl: 'views/directives/umb-header.html', + //create a new isolated scope assigning a tabs property from the attribute 'tabs' + //which is bound to the parent scope property passed in + scope: { + tabs: "=" + }, + link: function (scope, iElement, iAttrs) { - compile: function compile(tElement, tAttrs, transclude) { - return function postLink(scope, iElement, iAttrs, controller) { + if (!iAttrs.tabs) + throw "a 'tabs' attribute must be set for umbHeader which represents the collection of tabs"; - scope.panes = []; - var $panes = $('div.tab-content'); + var hasProcessed = false; - var activeTab = 0, _id, _title, _active; - $timeout(function() { + //when the tabs change, we need to hack the planet a bit and force the first tab content to be active, + //unfortunately twitter bootstrap tabs is not playing perfectly with angular. + scope.$watch("tabs", function (newValue, oldValue) { - $panes.find('.tab-pane').each(function(index) { - var $this = angular.element(this); - var _scope = $this.scope(); + //don't process if we cannot or have already done so + if (!newValue) return; + if (hasProcessed || !newValue.length || newValue.length == 0) return; + + //set the flag + hasProcessed = true; - _id = $this.attr("id"); - _title = $this.attr('title'); - _active = !_active && $this.hasClass('active'); + var $panes = $('div.tab-content'); + var activeTab = _.find(newValue, function (item) { + return item.active; + }); + //we need to do a timeout here so that the current sync operation can complete + // and update the UI, then this will fire and the UI elements will be available. + $timeout(function () { + $panes.find('.tab-pane').each(function (index) { + var $this = angular.element(this); + var _scope = $this.scope(); + if (_scope.id == activeTab.id) { + $this.addClass('active' + (iAttrs.fade ? ' in' : '')); + } + else { + $this.removeClass('active'); + } - if(iAttrs.fade){$this.addClass('fade');} - - scope.panes.push({ - id: _id, - title: _title, - active: _active - }); + if (iAttrs.fade) { $this.addClass('fade'); } }); - - if(scope.panes.length && !_active) { - $panes.find('.tab-pane:first-child').addClass('active' + (iAttrs.fade ? ' in' : '')); - scope.panes[0].active = true; - } - - }); //end timeout - }; //end postlink + }); + + }); } }; }) @@ -284,13 +295,18 @@ angular.module('umbraco.directives', []) restrict: 'E', replace: true, transclude: 'true', - + //assign isolated scope from the attributes + //NOTE: we use @rel because angular has a bug where + // it cannot assign based on hyphenated attributes like + // data-tab-id (which should be dataTabId but it doesn't work) scope: { - title: '@', - id: '@' + label: '@title', + id: '@rel' }, - - templateUrl: 'views/directives/umb-tab.html' + templateUrl: 'views/directives/umb-tab.html', + link: function (scope, element, attrs) { + scope.elementId = "tab" + scope.id; + } }; }) @@ -298,9 +314,9 @@ angular.module('umbraco.directives', []) .directive('umbProperty', function(){ return { + scope: true, restrict: 'E', - replace: true, - transclude: 'true', + replace: true, templateUrl: 'views/directives/umb-property.html', link: function (scope, element, attrs) { //let's make a requireJs call to try and retrieve the associated js diff --git a/src/Umbraco.Web.UI/umbraco/js/umbraco.filters.js b/src/Umbraco.Web.UI/umbraco/js/umbraco.filters.js index 75bcd48c9c..1fc18f3740 100644 --- a/src/Umbraco.Web.UI/umbraco/js/umbraco.filters.js +++ b/src/Umbraco.Web.UI/umbraco/js/umbraco.filters.js @@ -53,7 +53,7 @@ define(['app', 'angular'], function (app, angular) { //if its not defined then return undefined if (!input) return input; - $log.info("Filtering property editor view: " + input); + //$log.info("Filtering property editor view: " + input); var path = String(input); if (path.startsWith('/')) { diff --git a/src/Umbraco.Web.UI/umbraco/js/umbraco.resources.js b/src/Umbraco.Web.UI/umbraco/js/umbraco.resources.js index 57b41e7f2a..a9afa5dd81 100644 --- a/src/Umbraco.Web.UI/umbraco/js/umbraco.resources.js +++ b/src/Umbraco.Web.UI/umbraco/js/umbraco.resources.js @@ -131,7 +131,7 @@ define(['app', 'angular'], function (app, angular) { * @name umbraco.resources.contentResource * @description Loads in data for content **/ - function contentTypeResource($q, $http) { + function contentResource($q, $http) { /** internal method to get the api url */ function getContentUrl(contentId) { @@ -143,9 +143,16 @@ define(['app', 'angular'], function (app, angular) { var deferred = $q.defer(); - //go and get the tree data + //go and get the data $http.get(getContentUrl(id)). success(function (data, status, headers, config) { + //set the first tab to active + _.each(data.tabs, function (item) { + item.active = false; + }); + if (data.tabs.length > 0) + data.tabs[0].active = true; + deferred.resolve(data); }). error(function (data, status, headers, config) { @@ -275,7 +282,7 @@ define(['app', 'angular'], function (app, angular) { }; } - angular.module('umbraco.resources.content', []).factory('contentResource', contentTypeResource); + angular.module('umbraco.resources.content', []).factory('contentResource', contentResource); // angular.module('umbraco.resources.content', []) //.factory('contentFactory', function () { diff --git a/src/Umbraco.Web/Models/ContentEditing/Tab.cs b/src/Umbraco.Web/Models/ContentEditing/Tab.cs index 5f3d7bb6f2..899f81230a 100644 --- a/src/Umbraco.Web/Models/ContentEditing/Tab.cs +++ b/src/Umbraco.Web/Models/ContentEditing/Tab.cs @@ -9,6 +9,9 @@ namespace Umbraco.Web.Models.ContentEditing [DataContract(Name = "tab", Namespace = "")] public class Tab { + [DataMember(Name = "id")] + public int Id { get; set; } + [DataMember(Name = "label")] public string Label { get; set; } diff --git a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs index 42e39cf375..8ee9512d63 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs @@ -49,6 +49,7 @@ namespace Umbraco.Web.Models.Mapping //return the tab with the tab properties return new Tab { + Id = propertyGroup.Id, Alias = propertyGroup.Name, Label = propertyGroup.Name, Properties = displayProperties @@ -61,6 +62,7 @@ namespace Umbraco.Web.Models.Mapping //now add the generic properties tab tabs.Add(new Tab { + Id = 0, Label = "Generic properties", Alias = "Generic properties", Properties = orphanProperties.Select(ToContentPropertyDisplay)