diff --git a/src/Umbraco.Core/Constants-Applications.cs b/src/Umbraco.Core/Constants-Applications.cs
index 2d4042fad0..b53a2b8eaf 100644
--- a/src/Umbraco.Core/Constants-Applications.cs
+++ b/src/Umbraco.Core/Constants-Applications.cs
@@ -77,7 +77,7 @@
/// alias for the macro tree.
///
public const string Macros = "macros";
-
+
///
/// alias for the datatype tree.
///
@@ -92,7 +92,7 @@
/// alias for the dictionary tree.
///
public const string Dictionary = "dictionary";
-
+
public const string Stylesheets = "stylesheets";
///
@@ -121,7 +121,7 @@
public const string Templates = "templates";
public const string RelationTypes = "relationTypes";
-
+
public const string Languages = "languages";
///
diff --git a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs
index c404e0404d..a868245940 100644
--- a/src/Umbraco.Tests/Testing/UmbracoTestBase.cs
+++ b/src/Umbraco.Tests/Testing/UmbracoTestBase.cs
@@ -228,6 +228,7 @@ namespace Umbraco.Tests.Testing
.Append()
.Append()
.Append()
+ .Append()
.Append();
Composition.RegisterUnique();
diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js
index edf54ca034..40def728ed 100644
--- a/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js
+++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/tags/umbtagseditor.directive.js
@@ -29,6 +29,8 @@
let typeahead;
let tagsHound;
+ let initLoad = true;
+
vm.$onInit = onInit;
vm.$onChanges = onChanges;
vm.$onDestroy = onDestroy;
@@ -53,7 +55,7 @@
vm.isLoading = false;
//ensure that the models are formatted correctly
- configureViewModel();
+ configureViewModel(true);
// Set the visible prompt to -1 to ensure it will not be visible
vm.promptIsVisible = "-1";
@@ -139,8 +141,7 @@
if (!changes.value.isFirstChange() && changes.value.currentValue !== changes.value.previousValue) {
configureViewModel();
- reValidate()
-
+ reValidate();
}
}
}
@@ -154,13 +155,19 @@
$element.find('.tags-' + vm.htmlId).typeahead('destroy');
}
- function configureViewModel() {
+ function configureViewModel(isInitLoad) {
if (vm.value) {
if (angular.isString(vm.value) && vm.value.length > 0) {
if (vm.config.storageType === "Json") {
//json storage
vm.viewModel = JSON.parse(vm.value);
- updateModelValue(vm.viewModel);
+
+ //if this is the first load, we are just re-formatting the underlying model to be consistent
+ //we don't want to notify the component parent of any changes, that will occur if the user actually
+ //changes a value. If we notify at this point it will signal a form dirty change which we don't want.
+ if (!isInitLoad) {
+ updateModelValue(vm.viewModel);
+ }
}
else {
//csv storage
@@ -174,8 +181,12 @@
return self.indexOf(v) === i;
});
- updateModelValue(vm.viewModel);
-
+ //if this is the first load, we are just re-formatting the underlying model to be consistent
+ //we don't want to notify the component parent of any changes, that will occur if the user actually
+ //changes a value. If we notify at this point it will signal a form dirty change which we don't want.
+ if (!isInitLoad) {
+ updateModelValue(vm.viewModel);
+ }
}
}
else if (angular.isArray(vm.value)) {
diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js b/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js
index ed3d6ded33..e801e2cc58 100644
--- a/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js
+++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/dashboard.tabs.controller.js
@@ -192,7 +192,6 @@ function FormsController($scope, $route, $cookies, packageResource, localization
function Video_player (videoId) {
// Get dom elements
this.container = document.getElementById(videoId);
- this.video = this.container.getElementsByTagName('video')[0];
//Create controls
this.controls = document.createElement('div');
@@ -215,104 +214,6 @@ function FormsController($scope, $route, $cookies, packageResource, localization
this.controls.appendChild(this.loader);
this.loader.appendChild(this.progress_bar);
}
-
-
- Video_player.prototype
- .seeking = function() {
- // get the value of the seekbar (hidden input[type="range"])
- var time = this.video.duration * (this.seek_bar.value / 100);
-
- // Update video to seekbar value
- this.video.currentTime = time;
- };
-
- // Stop video when user initiates seeking
- Video_player.prototype
- .start_seek = function() {
- this.video.pause();
- };
-
- // Start video when user stops seeking
- Video_player.prototype
- .stop_seek = function() {
- this.video.play();
- };
-
- // Update the progressbar (span.loader) according to video.currentTime
- Video_player.prototype
- .update_progress_bar = function() {
- // Get video progress in %
- var value = (100 / this.video.duration) * this.video.currentTime;
-
- // Update progressbar
- this.progress_bar.style.width = value + '%';
- };
-
- // Bind progressbar to mouse when seeking
- Video_player.prototype
- .handle_mouse_move = function(event) {
- // Get position of progressbar relative to browser window
- var pos = this.progress_bar.getBoundingClientRect().left;
-
- // Make sure event is reckonized cross-browser
- event = event || window.event;
-
- // Update progressbar
- this.progress_bar.style.width = (event.clientX - pos) + "px";
- };
-
- // Eventlisteners for seeking
- Video_player.prototype
- .video_event_handler = function(videoPlayer, interval) {
- // Update the progress bar
- var animate_progress_bar = setInterval(function () {
- videoPlayer.update_progress_bar();
- }, interval);
-
- // Fire when input value changes (user seeking)
- videoPlayer.seek_bar
- .addEventListener("change", function() {
- videoPlayer.seeking();
- });
-
- // Fire when user clicks on seekbar
- videoPlayer.seek_bar
- .addEventListener("mousedown", function (clickEvent) {
- // Pause video playback
- videoPlayer.start_seek();
-
- // Stop updating progressbar according to video progress
- clearInterval(animate_progress_bar);
-
- // Update progressbar to where user clicks
- videoPlayer.handle_mouse_move(clickEvent);
-
- // Bind progressbar to cursor
- window.onmousemove = function(moveEvent){
- videoPlayer.handle_mouse_move(moveEvent);
- };
- });
-
- // Fire when user releases seekbar
- videoPlayer.seek_bar
- .addEventListener("mouseup", function () {
-
- // Unbind progressbar from cursor
- window.onmousemove = null;
-
- // Start video playback
- videoPlayer.stop_seek();
-
- // Animate the progressbar
- animate_progress_bar = setInterval(function () {
- videoPlayer.update_progress_bar();
- }, interval);
- });
- };
-
-
- var videoPlayer = new Video_player('video_1');
- videoPlayer.video_event_handler(videoPlayer, 17);
}
angular.module("umbraco").controller("Umbraco.Dashboard.FormsDashboardController", FormsController);
diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/forms/formsdashboardintro.html b/src/Umbraco.Web.UI.Client/src/views/dashboard/forms/formsdashboardintro.html
index 3b382367c4..c18e7f4ccf 100644
--- a/src/Umbraco.Web.UI.Client/src/views/dashboard/forms/formsdashboardintro.html
+++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/forms/formsdashboardintro.html
@@ -8,14 +8,6 @@
-
-
-
-
Create forms using an intuitive drag and drop interface. From simple contact forms that sends e-mails to advanced questionaires that integrate with CRM systems. Your clients will love it!
Styles
The CSS that should be applied in the rich text editor, e.g. "color:red;"Code
- Rich Text Editor
+ Rich Text EditorFailed to delete template with ID %0%
diff --git a/src/Umbraco.Web/Dashboards/FormsDashboard.cs b/src/Umbraco.Web/Dashboards/FormsDashboard.cs
index a3e1123369..867e8af3aa 100644
--- a/src/Umbraco.Web/Dashboards/FormsDashboard.cs
+++ b/src/Umbraco.Web/Dashboards/FormsDashboard.cs
@@ -1,4 +1,5 @@
using System;
+using Umbraco.Core;
using Umbraco.Core.Composing;
using Umbraco.Core.Dashboards;
@@ -9,7 +10,7 @@ namespace Umbraco.Web.Dashboards
{
public string Alias => "formsInstall";
- public string[] Sections => new [] { "forms" };
+ public string[] Sections => new [] { Constants.Applications.Forms };
public string View => "views/dashboard/forms/formsdashboardintro.html";
diff --git a/src/Umbraco.Web/Editors/SectionController.cs b/src/Umbraco.Web/Editors/SectionController.cs
index 0a2f17cd15..52034b9c95 100644
--- a/src/Umbraco.Web/Editors/SectionController.cs
+++ b/src/Umbraco.Web/Editors/SectionController.cs
@@ -43,7 +43,7 @@ namespace Umbraco.Web.Editors
// this is a bit nasty since we'll be proxying via the app tree controller but we sort of have to do that
// since tree's by nature are controllers and require request contextual data
- var appTreeController = new ApplicationTreeController(GlobalSettings, UmbracoContext, SqlContext, Services, AppCaches, Logger, RuntimeState, _treeService, Umbraco)
+ var appTreeController = new ApplicationTreeController(GlobalSettings, UmbracoContext, SqlContext, Services, AppCaches, Logger, RuntimeState, _treeService, _sectionService, Umbraco)
{
ControllerContext = ControllerContext
};
diff --git a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs
index 3afe6aa397..52373184b4 100644
--- a/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs
+++ b/src/Umbraco.Web/Runtime/WebRuntimeComposer.cs
@@ -220,6 +220,7 @@ namespace Umbraco.Web.Runtime
.Append()
.Append()
.Append()
+ .Append()
.Append();
// register core CMS dashboards and 3rd party types - will be ordered by weight attribute & merged with package.manifest dashboards
diff --git a/src/Umbraco.Web/Trees/ApplicationTreeController.cs b/src/Umbraco.Web/Trees/ApplicationTreeController.cs
index 162d001e96..b8fe709738 100644
--- a/src/Umbraco.Web/Trees/ApplicationTreeController.cs
+++ b/src/Umbraco.Web/Trees/ApplicationTreeController.cs
@@ -32,13 +32,15 @@ namespace Umbraco.Web.Trees
public class ApplicationTreeController : UmbracoAuthorizedApiController
{
private readonly ITreeService _treeService;
+ private readonly ISectionService _sectionService;
public ApplicationTreeController(IGlobalSettings globalSettings, UmbracoContext umbracoContext,
ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger,
- IRuntimeState runtimeState, ITreeService treeService, UmbracoHelper umbracoHelper)
+ IRuntimeState runtimeState, ITreeService treeService, ISectionService sectionService, UmbracoHelper umbracoHelper)
: base(globalSettings, umbracoContext, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper)
{
_treeService = treeService;
+ _sectionService = sectionService;
}
///
@@ -56,12 +58,21 @@ namespace Umbraco.Web.Trees
if (string.IsNullOrEmpty(application))
throw new HttpResponseException(HttpStatusCode.NotFound);
+ var section = _sectionService.GetByAlias(application);
+ if (section == null)
+ throw new HttpResponseException(HttpStatusCode.NotFound);
+
//find all tree definitions that have the current application alias
var groupedTrees = _treeService.GetBySectionGrouped(application, use);
var allTrees = groupedTrees.Values.SelectMany(x => x).ToList();
if (allTrees.Count == 0)
- throw new HttpResponseException(HttpStatusCode.NotFound);
+ {
+ //if there are no trees defined for this section but the section is defined then we can have a simple
+ //full screen section without trees
+ var name = Services.TextService.Localize("sections/" + application);
+ return TreeRootNode.CreateSingleTreeRoot(Constants.System.Root.ToInvariantString(), null, null, name, TreeNodeCollection.Empty, true);
+ }
// handle request for a specific tree / or when there is only one tree
if (!tree.IsNullOrWhiteSpace() || allTrees.Count == 1)
@@ -101,8 +112,8 @@ namespace Umbraco.Web.Trees
return treeRootNode;
}
- // otherwise it's a section with no tree, aka a fullscreen section
- // todo is this true? what if we just failed to TryGetRootNode on all of them?
+ // otherwise it's a section with all empty trees, aka a fullscreen section
+ // todo is this true? what if we just failed to TryGetRootNode on all of them? SD: Yes it's true but we should check the result of TryGetRootNode and throw?
return TreeRootNode.CreateSingleTreeRoot(Constants.System.Root.ToInvariantString(), null, null, name, TreeNodeCollection.Empty, true);
}
diff --git a/src/Umbraco.Web/Trees/FormsBackOfficeSection.cs b/src/Umbraco.Web/Trees/FormsBackOfficeSection.cs
new file mode 100644
index 0000000000..048ed47f11
--- /dev/null
+++ b/src/Umbraco.Web/Trees/FormsBackOfficeSection.cs
@@ -0,0 +1,14 @@
+using Umbraco.Core;
+using Umbraco.Core.Models.Trees;
+
+namespace Umbraco.Web.Trees
+{
+ ///
+ /// Defines the back office media section
+ ///
+ public class FormsBackOfficeSection : IBackOfficeSection
+ {
+ public string Alias => Constants.Applications.Forms;
+ public string Name => "Forms";
+ }
+}
diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj
index 11d2be5b70..fa2ac81761 100755
--- a/src/Umbraco.Web/Umbraco.Web.csproj
+++ b/src/Umbraco.Web/Umbraco.Web.csproj
@@ -214,6 +214,7 @@
+