diff --git a/src/Umbraco.Core/Services/FileService.cs b/src/Umbraco.Core/Services/FileService.cs index 6360ad8988..2105f7af2c 100644 --- a/src/Umbraco.Core/Services/FileService.cs +++ b/src/Umbraco.Core/Services/FileService.cs @@ -744,40 +744,9 @@ namespace Umbraco.Core.Services if (CreatingPartialView.IsRaisedEventCancelled(new NewEventArgs(partialView, true, partialView.Alias, -1), this)) return Attempt.Fail(); - string partialViewHeader; - switch (partialViewType) - { - case PartialViewType.PartialView: - partialViewHeader = PartialViewHeader; - break; - case PartialViewType.PartialViewMacro: - partialViewHeader = PartialViewMacroHeader; - break; - default: - throw new ArgumentOutOfRangeException("partialViewType"); - } - if (snippetName.IsNullOrWhiteSpace() == false) { - //create the file - var snippetPathAttempt = TryGetSnippetPath(snippetName); - if (snippetPathAttempt.Success == false) - { - throw new InvalidOperationException("Could not load snippet with name " + snippetName); - } - - using (var snippetFile = new StreamReader(System.IO.File.OpenRead(snippetPathAttempt.Result))) - { - var snippetContent = snippetFile.ReadToEnd().Trim(); - - //strip the @inherits if it's there - snippetContent = StripPartialViewHeader(snippetContent); - - var content = string.Format("{0}{1}{2}", - partialViewHeader, - Environment.NewLine, snippetContent); - partialView.Content = content; - } + partialView.Content = GetPartialViewMacroSnippetContent(snippetName, partialViewType); } var uow = _fileUowProvider.GetUnitOfWork(); @@ -914,6 +883,55 @@ namespace Umbraco.Core.Services } } + public string GetPartialViewSnippetContent(string snippetName) + { + return GetPartialViewMacroSnippetContent(snippetName, PartialViewType.PartialView); + } + + public string GetPartialViewMacroSnippetContent(string snippetName) + { + return GetPartialViewMacroSnippetContent(snippetName, PartialViewType.PartialViewMacro); + } + + private string GetPartialViewMacroSnippetContent(string snippetName, PartialViewType partialViewType) + { + if (snippetName.IsNullOrWhiteSpace()) + throw new ArgumentNullException("snippetName"); + + string partialViewHeader; + switch (partialViewType) + { + case PartialViewType.PartialView: + partialViewHeader = PartialViewHeader; + break; + case PartialViewType.PartialViewMacro: + partialViewHeader = PartialViewMacroHeader; + break; + default: + throw new ArgumentOutOfRangeException("partialViewType"); + } + + // Try and get the snippet path + var snippetPathAttempt = TryGetSnippetPath(snippetName); + if (snippetPathAttempt.Success == false) + { + throw new InvalidOperationException("Could not load snippet with name " + snippetName); + } + + using (var snippetFile = new StreamReader(System.IO.File.OpenRead(snippetPathAttempt.Result))) + { + var snippetContent = snippetFile.ReadToEnd().Trim(); + + //strip the @inherits if it's there + snippetContent = StripPartialViewHeader(snippetContent); + + var content = string.Format("{0}{1}{2}", + partialViewHeader, + Environment.NewLine, snippetContent); + return content; + } + } + public void SetPartialViewMacroFileContent(string filepath, Stream content) { using (var repository = GetPartialViewRepository(PartialViewType.PartialViewMacro, UowProvider.GetUnitOfWork())) diff --git a/src/Umbraco.Core/Services/IFileService.cs b/src/Umbraco.Core/Services/IFileService.cs index 5115a25087..453d199bfe 100644 --- a/src/Umbraco.Core/Services/IFileService.cs +++ b/src/Umbraco.Core/Services/IFileService.cs @@ -331,6 +331,13 @@ namespace Umbraco.Core.Services /// The content of the macro partial view. Stream GetPartialViewMacroFileContentStream(string filepath); + /// + /// Gets the content of a macro partial view snippet as a string + /// + /// The name of the snippet + /// + string GetPartialViewMacroSnippetContent(string snippetName); + /// /// Sets the content of a macro partial view. /// @@ -352,6 +359,13 @@ namespace Umbraco.Core.Services /// The content of the partial view. Stream GetPartialViewFileContentStream(string filepath); + /// + /// Gets the content of a partial view snippet as a string. + /// + /// The name of the snippet + /// The content of the partial view. + string GetPartialViewSnippetContent(string snippetName); + /// /// Sets the content of a partial view. /// diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/codefile.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/codefile.resource.js index b6e35d9d7b..e83bb4f14e 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/codefile.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/codefile.resource.js @@ -77,39 +77,6 @@ function codefileResource($q, $http, umbDataFormatter, umbRequestHelper) { "Failed to retrieve data for template with alias: " + alias); }, - - /** - * @ngdoc method - * @name umbraco.resources.codefileResource#getScaffold - * @methodOf umbraco.resources.codefileResource - * - * @description - * Returns a scaffold of an empty codefile item - * - * The scaffold is used to build editors for code file editors that has not yet been populated with data. - * - * ##usage - *
-         * codefileResource.getScaffold()
-         *    .then(function(template) {
-         *        alert('its here!');
-         *    });
-         * 
- * - * @returns {Promise} resourcePromise object containing the codefile scaffold. - * - */ - getScaffold: function (id) { - - return umbRequestHelper.resourcePromise( - $http.get( - umbRequestHelper.getApiUrl( - "templateApiBaseUrl", - "GetScaffold", - [{ id: id }])), - "Failed to retrieve data for empty template"); - }, - /** * @ngdoc method * @name umbraco.resources.codefileResource#deleteByPath @@ -176,7 +143,70 @@ function codefileResource($q, $http, umbDataFormatter, umbRequestHelper) { "PostSave"), codeFile), "Failed to save data for code file " + codeFile.virtualPath); + }, + + /** + * @ngdoc method + * @name umbraco.resources.codefileResource#getSnippets + * @methodOf umbraco.resources.codefileResource + * + * @description + * Gets code snippets for a given file type + * + * ##usage + *
+         * codefileResource.getSnippets("partialViews")
+         *    .then(function(snippets) {
+         *        alert('its here!');
+         *    });
+         * 
+ * + * @param {string} file type: (partialViews, partialViewMacros) + * @returns {Promise} resourcePromise object. + * + */ + getSnippets: function (fileType) { + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "codeFileApiBaseUrl", + "GetSnippets?type=" + fileType )), + "Failed to get snippet for" + fileType); + }, + + /** + * @ngdoc method + * @name umbraco.resources.codefileResource#getScaffold + * @methodOf umbraco.resources.codefileResource + * + * @description + * Returns a scaffold of an empty codefile item. + * + * The scaffold is used to build editors for code file editors that has not yet been populated with data. + * + * ##usage + *
+         * codefileResource.getScaffold("partialViews", "Breadcrumb")
+         *    .then(function(data) {
+         *        alert('its here!');
+         *    });
+         * 
+ * + * @param {string} File type: (scripts, partialViews, partialViewMacros). + * @param {string} Snippet name (Ex. Breadcrumb). + * @returns {Promise} resourcePromise object. + * + */ + + getScaffold: function (type, id, snippetName) { + return umbRequestHelper.resourcePromise( + $http.get( + umbRequestHelper.getApiUrl( + "codeFileApiBaseUrl", + "GetScaffold?type=" + type + "&id=" + id + "&snippetName=" + snippetName)), + "Failed to get scaffold for" + type); } + }; } diff --git a/src/Umbraco.Web.UI.Client/src/views/partialviewmacros/create.controller.js b/src/Umbraco.Web.UI.Client/src/views/partialviewmacros/create.controller.js new file mode 100644 index 0000000000..3b3fb0f9f5 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/partialviewmacros/create.controller.js @@ -0,0 +1,55 @@ +(function () { + "use strict"; + + function PartialViewMacrosCreateController($scope, codefileResource, $location, navigationService) { + + var vm = this; + var node = $scope.dialogOptions.currentNode; + + vm.snippets = []; + vm.showSnippets = false; + vm.creatingFolder = false; + + vm.createPartialViewMacro = createPartialViewMacro; + vm.showCreateFolder = showCreateFolder; + vm.createFolder = createFolder; + vm.showCreateFromSnippet = showCreateFromSnippet; + + function onInit() { + codefileResource.getSnippets('partialViewMacros') + .then(function(snippets) { + vm.snippets = snippets; + }); + } + + function createPartialViewMacro(selectedSnippet) { + + var snippet = null; + + if(selectedSnippet && selectedSnippet.fileName) { + snippet = selectedSnippet.fileName; + } + + $location.path("/developer/partialviewmacros/edit/" + node.id).search("create", "true").search("snippet", snippet); + navigationService.hideMenu(); + + } + + function showCreateFolder() { + vm.creatingFolder = true; + } + + function createFolder() { + + } + + function showCreateFromSnippet() { + vm.showSnippets = true; + } + + onInit(); + + } + + angular.module("umbraco").controller("Umbraco.Editors.PartialViewMacros.CreateController", PartialViewMacrosCreateController); +})(); diff --git a/src/Umbraco.Web.UI.Client/src/views/partialviewmacros/create.html b/src/Umbraco.Web.UI.Client/src/views/partialviewmacros/create.html new file mode 100644 index 0000000000..aa8796ae7a --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/partialviewmacros/create.html @@ -0,0 +1,75 @@ +
+ + + + + + +
diff --git a/src/Umbraco.Web.UI.Client/src/views/partialviewmacros/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/partialviewmacros/edit.controller.js index c402f42ee7..4860773b02 100644 --- a/src/Umbraco.Web.UI.Client/src/views/partialviewmacros/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/partialviewmacros/edit.controller.js @@ -227,10 +227,19 @@ function init() { //we need to load this somewhere, for now its here. assetsService.loadCss("lib/ace-razor-mode/theme/razor_chrome.css"); + if ($routeParams.create) { - codefileResource.getScaffold().then(function (partialViewMacro) { + + var snippet = "Empty"; + + if($routeParams.snippet) { + snippet = $routeParams.snippet; + } + + codefileResource.getScaffold("partialViewMacros", $routeParams.id, snippet).then(function (partialViewMacro) { ready(partialViewMacro); }); + } else { codefileResource.getByPath('partialViewMacros', $routeParams.id).then(function (partialViewMacro) { ready(partialViewMacro); diff --git a/src/Umbraco.Web.UI.Client/src/views/partialviews/create.controller.js b/src/Umbraco.Web.UI.Client/src/views/partialviews/create.controller.js new file mode 100644 index 0000000000..5aeaa28935 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/partialviews/create.controller.js @@ -0,0 +1,55 @@ +(function () { + "use strict"; + + function PartialViewsCreateController($scope, codefileResource, $location, navigationService) { + + var vm = this; + var node = $scope.dialogOptions.currentNode; + + vm.snippets = []; + vm.showSnippets = false; + vm.creatingFolder = false; + + vm.createPartialView = createPartialView; + vm.showCreateFolder = showCreateFolder; + vm.createFolder = createFolder; + vm.showCreateFromSnippet = showCreateFromSnippet; + + function onInit() { + codefileResource.getSnippets('partialViews') + .then(function(snippets) { + vm.snippets = snippets; + }); + } + + function createPartialView(selectedSnippet) { + + var snippet = null; + + if(selectedSnippet && selectedSnippet.fileName) { + snippet = selectedSnippet.fileName; + } + + $location.path("/settings/partialviews/edit/" + node.id).search("create", "true").search("snippet", snippet); + navigationService.hideMenu(); + + } + + function showCreateFolder() { + vm.creatingFolder = true; + } + + function createFolder() { + + } + + function showCreateFromSnippet() { + vm.showSnippets = true; + } + + onInit(); + + } + + angular.module("umbraco").controller("Umbraco.Editors.PartialViews.CreateController", PartialViewsCreateController); +})(); diff --git a/src/Umbraco.Web.UI.Client/src/views/partialviews/create.html b/src/Umbraco.Web.UI.Client/src/views/partialviews/create.html new file mode 100644 index 0000000000..fc9bf98c4f --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/partialviews/create.html @@ -0,0 +1,75 @@ +
+ + + + + + +
diff --git a/src/Umbraco.Web.UI.Client/src/views/partialviews/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/partialviews/edit.controller.js index dc388a906b..a493ed30c1 100644 --- a/src/Umbraco.Web.UI.Client/src/views/partialviews/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/partialviews/edit.controller.js @@ -227,15 +227,25 @@ function init() { //we need to load this somewhere, for now its here. assetsService.loadCss("lib/ace-razor-mode/theme/razor_chrome.css"); + if ($routeParams.create) { - codefileResource.getScaffold().then(function (partialView) { + + var snippet = "Empty"; + + if($routeParams.snippet) { + snippet = $routeParams.snippet; + } + + codefileResource.getScaffold("partialViews", $routeParams.id, snippet).then(function (partialView) { ready(partialView); }); + } else { codefileResource.getByPath('partialViews', $routeParams.id).then(function (partialView) { ready(partialView); }); } + } function ready(partialView) { diff --git a/src/Umbraco.Web.UI.Client/src/views/scripts/create.controller.js b/src/Umbraco.Web.UI.Client/src/views/scripts/create.controller.js new file mode 100644 index 0000000000..1729693d83 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/scripts/create.controller.js @@ -0,0 +1,33 @@ +(function () { + "use strict"; + + function ScriptsCreateController($scope, $location, navigationService) { + + var vm = this; + var node = $scope.dialogOptions.currentNode; + + vm.creatingFolder = false; + vm.folderName = ""; + vm.fileExtension = ""; + + vm.createFile = createFile; + vm.showCreateFolder = showCreateFolder; + vm.createFolder = createFolder; + + function createFile() { + $location.path("/settings/scripts/edit/" + node.id).search("create", "true"); + navigationService.hideMenu(); + } + + function showCreateFolder() { + vm.creatingFolder = true; + } + + function createFolder() { + + } + + } + + angular.module("umbraco").controller("Umbraco.Editors.Scripts.CreateController", ScriptsCreateController); +})(); diff --git a/src/Umbraco.Web.UI.Client/src/views/scripts/create.html b/src/Umbraco.Web.UI.Client/src/views/scripts/create.html new file mode 100644 index 0000000000..d57ead3b15 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/scripts/create.html @@ -0,0 +1,47 @@ + + + diff --git a/src/Umbraco.Web.UI.Client/src/views/scripts/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/scripts/edit.controller.js index cd10ae75d5..d2a5fcbc0e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/scripts/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/scripts/edit.controller.js @@ -79,7 +79,7 @@ assetsService.loadCss("lib/ace-razor-mode/theme/razor_chrome.css"); if ($routeParams.create) { - codefileResource.getScaffold().then(function (script) { + codefileResource.getScaffold("scripts", $routeParams.id).then(function (script) { ready(script); }); } else { diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index 444ecc2e3d..f6823e766f 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -197,6 +197,11 @@ Document Type without a template New folder New data type + New javascript file + New empty partial view + New partial view from snippet + New empty partial view macro + New partial view macro from snippet Browse your website diff --git a/src/Umbraco.Web/Editors/CodeFileController.cs b/src/Umbraco.Web/Editors/CodeFileController.cs index 58dd28a15e..bcb6630c0a 100644 --- a/src/Umbraco.Web/Editors/CodeFileController.cs +++ b/src/Umbraco.Web/Editors/CodeFileController.cs @@ -1,7 +1,12 @@ using AutoMapper; +using System.Collections.Generic; +using System.Linq; using System.Net; using System.Net.Http; using System.Web.Http; +using ClientDependency.Core; +using Umbraco.Core; +using Umbraco.Core.IO; using Umbraco.Core.Models; using Umbraco.Core.Services; using Umbraco.Web.Models.ContentEditing; @@ -9,7 +14,6 @@ using Umbraco.Web.Mvc; using Umbraco.Web.WebApi; using Umbraco.Web.WebApi.Filters; using Umbraco.Web.Trees; -using Umbraco.Core.IO; namespace Umbraco.Web.Editors { @@ -32,11 +36,13 @@ namespace Umbraco.Web.Editors { case Core.Constants.Trees.PartialViews: var view = new PartialView(display.VirtualPath); + view.Content = display.Content; var result = Services.FileService.CreatePartialView(view, display.Snippet, Security.CurrentUser.Id); return result.Success == true ? Request.CreateResponse(HttpStatusCode.OK) : Request.CreateNotificationValidationErrorResponse(result.Exception.Message); case Core.Constants.Trees.PartialViewMacros: var viewMacro = new PartialView(display.VirtualPath); + viewMacro.Content = display.Content; var resultMacro = Services.FileService.CreatePartialViewMacro(viewMacro, display.Snippet, Security.CurrentUser.Id); return resultMacro.Success == true ? Request.CreateResponse(HttpStatusCode.OK) : Request.CreateNotificationValidationErrorResponse(resultMacro.Exception.Message); @@ -105,6 +111,95 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(HttpStatusCode.NotFound); } + /// + /// Used to get a list of available templates/snippets to base a new Partial View og Partial View Macro from + /// + /// This is a string but will be 'partialViews', 'partialViewMacros' + /// Returns a list of if a correct type is sent + public IEnumerable GetSnippets(string type) + { + if (string.IsNullOrWhiteSpace(type)) + { + throw new HttpResponseException(HttpStatusCode.BadRequest); + } + + IEnumerable snippets; + switch (type) + { + case Core.Constants.Trees.PartialViews: + snippets = Services.FileService.GetPartialViewSnippetNames( + //ignore these - (this is taken from the logic in "PartialView.ascx.cs") + "Gallery", + "ListChildPagesFromChangeableSource", + "ListChildPagesOrderedByProperty", + "ListImagesFromMediaFolder"); + break; + case Core.Constants.Trees.PartialViewMacros: + snippets = Services.FileService.GetPartialViewSnippetNames(); + break; + default: + throw new HttpResponseException(HttpStatusCode.NotFound); + } + + return snippets.Select(snippet => new SnippetDisplay() {Name = snippet.SplitPascalCasing().ToFirstUpperInvariant(), FileName = snippet}); + } + + /// + /// Used to scaffold the json object for the editors for 'scripts', 'partialViews', 'partialViewMacros' + /// + /// This is a string but will be 'scripts' 'partialViews', 'partialViewMacros' + /// + /// + /// + public CodeFileDisplay GetScaffold(string type, string id = null, string snippetName = null) + { + if (string.IsNullOrWhiteSpace(type)) + { + throw new HttpResponseException(HttpStatusCode.BadRequest); + } + + if (id.IsNullOrWhiteSpace()) + id = string.Empty; + + CodeFileDisplay codeFileDisplay; + + switch (type) + { + case Core.Constants.Trees.PartialViews: + codeFileDisplay = Mapper.Map(new PartialView(string.Empty)); + codeFileDisplay.VirtualPath = SystemDirectories.PartialViews; + if (snippetName.IsNullOrWhiteSpace() == false) + codeFileDisplay.Content = Services.FileService.GetPartialViewSnippetContent(snippetName); + break; + case Core.Constants.Trees.PartialViewMacros: + codeFileDisplay = Mapper.Map(new PartialView(string.Empty)); + codeFileDisplay.VirtualPath = SystemDirectories.MacroPartials; + if (snippetName.IsNullOrWhiteSpace() == false) + codeFileDisplay.Content = Services.FileService.GetPartialViewMacroSnippetContent(snippetName); + break; + case Core.Constants.Trees.Scripts: + codeFileDisplay = Mapper.Map(new Script(string.Empty)); + codeFileDisplay.VirtualPath = SystemDirectories.Scripts; + break; + default: + throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, "Unsupported editortype")); + } + + // Make sure that the root virtual path ends with '/' + codeFileDisplay.VirtualPath = codeFileDisplay.VirtualPath.EnsureEndsWith("/"); + + if (id.IsNullOrWhiteSpace() == false && id != Core.Constants.System.Root.ToInvariantString()) + { + codeFileDisplay.VirtualPath += id.TrimStart("/").EnsureEndsWith("/"); + } + + codeFileDisplay.VirtualPath = codeFileDisplay.VirtualPath.TrimStart("~"); + codeFileDisplay.Path = Url.GetTreePathFromFilePath(id); + codeFileDisplay.FileType = type; + + return codeFileDisplay; + } + /// /// Used to delete a specific file from disk via the FileService /// @@ -150,7 +245,7 @@ namespace Umbraco.Web.Editors } /// - /// Used to save/update an existing file after its initial creation + /// Used to create or update a 'partialview', 'partialviewmacro' or 'script' file /// /// /// The updated CodeFileDisplay model @@ -166,81 +261,56 @@ namespace Umbraco.Web.Editors throw new HttpResponseException(HttpStatusCode.NotFound); } - switch (display.FileType) { case Core.Constants.Trees.PartialViews: - var view = Services.FileService.GetPartialView(display.VirtualPath); - if (view != null) + var partialViewResult = CreateOrUpdatePartialView(display); + if (partialViewResult.Success) { - // might need to find the path - var orgPath = view.OriginalPath.Substring(0, view.OriginalPath.IndexOf(view.Name)); - view.Path = orgPath + display.Name; - view.Content = display.Content; - - //Save the file and update the response to reflect any name and path changes - var result = Services.FileService.SavePartialView(view, Security.CurrentUser.Id); - if (result.Success == true) - { - display = Mapper.Map(result.Result, display); - display.Path = Url.GetTreePathFromFilePath(view.Path); - return display; - } - - display.AddErrorNotification( - Services.TextService.Localize("speechBubbles/partialViewErrorHeader"), - Services.TextService.Localize("speechBubbles/partialViewErrorText")); - } - else - { - throw new HttpResponseException(HttpStatusCode.NotFound); + display = Mapper.Map(partialViewResult.Result, display); + display.Path = Url.GetTreePathFromFilePath(partialViewResult.Result.Path); + return display; } + + display.AddErrorNotification( + Services.TextService.Localize("speechBubbles/partialViewErrorHeader"), + Services.TextService.Localize("speechBubbles/partialViewErrorText")); break; case Core.Constants.Trees.PartialViewMacros: - var viewMacro = Services.FileService.GetPartialViewMacro(display.VirtualPath); - if (viewMacro != null) + var partialViewMacroResult = CreateOrUpdatePartialViewMacro(display); + if (partialViewMacroResult.Success) { - viewMacro.Content = display.Content; - viewMacro.Path = display.Name; - - //save the file and update the display to reflect any path and name changes - var result = Services.FileService.SavePartialViewMacro(viewMacro, Security.CurrentUser.Id); - if (result.Success == true) - { - display = Mapper.Map(result.Result, display); - display.Path = Url.GetTreePathFromFilePath(result.Result.Path); - return display; - } - - display.AddErrorNotification( - Services.TextService.Localize("speechBubbles/partialViewErrorHeader"), - Services.TextService.Localize("speechBubbles/partialViewErrorText")); - } - else - { - throw new HttpResponseException(HttpStatusCode.NotFound); + display = Mapper.Map(partialViewMacroResult.Result, display); + display.Path = Url.GetTreePathFromFilePath(partialViewMacroResult.Result.Path); + return display; } + + display.AddErrorNotification( + Services.TextService.Localize("speechBubbles/partialViewErrorHeader"), + Services.TextService.Localize("speechBubbles/partialViewErrorText")); break; case Core.Constants.Trees.Scripts: + var virtualPath = display.VirtualPath; var script = Services.FileService.GetScriptByName(display.VirtualPath); if (script != null) { - script.Content = display.Content; script.Path = display.Name; - - Services.FileService.SaveScript(script, Security.CurrentUser.Id); display = Mapper.Map(script, display); display.Path = Url.GetTreePathFromFilePath(script.Path); return display; - } else { - throw new HttpResponseException(HttpStatusCode.NotFound); + var fileName = EnsurePartialViewExtension(display.Name, ".js"); + script = new Script(virtualPath + fileName); } + + script.Content = display.Content; + + Services.FileService.SaveScript(script, Security.CurrentUser.Id); break; default: @@ -249,5 +319,74 @@ namespace Umbraco.Web.Editors return display; } + + private Attempt CreateOrUpdatePartialView(CodeFileDisplay display) + { + Attempt partialViewResult; + string virtualPath = NormalizeVirtualPath(display.VirtualPath, SystemDirectories.PartialViews); + var view = Services.FileService.GetPartialView(virtualPath); + if (view != null) + { + // might need to find the path + var orgPath = view.OriginalPath.Substring(0, view.OriginalPath.IndexOf(view.Name)); + view.Path = orgPath + display.Name; + + view.Content = display.Content; + partialViewResult = Services.FileService.SavePartialView(view, Security.CurrentUser.Id); + } + else + { + var fileName = EnsurePartialViewExtension(display.Name, ".cshtml"); + view = new PartialView(virtualPath + fileName); + view.Content = display.Content; + partialViewResult = Services.FileService.CreatePartialView(view, display.Snippet, Security.CurrentUser.Id); + } + + return partialViewResult; + } + + private string NormalizeVirtualPath(string virtualPath, string systemDirectory) + { + if (virtualPath.IsNullOrWhiteSpace()) + return string.Empty; + + systemDirectory = systemDirectory.TrimStart("~"); + systemDirectory = systemDirectory.Replace('\\', '/'); + virtualPath = virtualPath.TrimStart("~"); + virtualPath = virtualPath.Replace('\\', '/'); + virtualPath = virtualPath.ReplaceFirst(systemDirectory, string.Empty); + + return virtualPath; + } + + private Attempt CreateOrUpdatePartialViewMacro(CodeFileDisplay display) + { + Attempt partialViewMacroResult; + var virtualPath = display.VirtualPath ?? string.Empty; + var viewMacro = Services.FileService.GetPartialViewMacro(virtualPath); + if (viewMacro != null) + { + viewMacro.Content = display.Content; + viewMacro.Path = display.Name; + partialViewMacroResult = Services.FileService.SavePartialViewMacro(viewMacro, Security.CurrentUser.Id); + } + else + { + var fileName = EnsurePartialViewExtension(display.Name, ".cshtml"); + viewMacro = new PartialView(virtualPath + fileName); + viewMacro.Content = display.Content; + partialViewMacroResult = Services.FileService.CreatePartialViewMacro(viewMacro, display.Snippet, Security.CurrentUser.Id); + } + + return partialViewMacroResult; + } + + private string EnsurePartialViewExtension(string value, string extension) + { + if (value.EndsWith(extension) == false) + value += extension; + + return value; + } } } diff --git a/src/Umbraco.Web/Models/ContentEditing/SnippetDisplay.cs b/src/Umbraco.Web/Models/ContentEditing/SnippetDisplay.cs new file mode 100644 index 0000000000..e05f8c5c89 --- /dev/null +++ b/src/Umbraco.Web/Models/ContentEditing/SnippetDisplay.cs @@ -0,0 +1,14 @@ +using System.Runtime.Serialization; + +namespace Umbraco.Web.Models.ContentEditing +{ + [DataContract(Name = "scriptFile", Namespace = "")] + public class SnippetDisplay + { + [DataMember(Name = "name", IsRequired = true)] + public string Name { get; set; } + + [DataMember(Name = "fileName", IsRequired = true)] + public string FileName { get; set; } + } +} diff --git a/src/Umbraco.Web/Trees/PartialViewMacrosTreeController.cs b/src/Umbraco.Web/Trees/PartialViewMacrosTreeController.cs index 10daa56dbe..61d9c17cef 100644 --- a/src/Umbraco.Web/Trees/PartialViewMacrosTreeController.cs +++ b/src/Umbraco.Web/Trees/PartialViewMacrosTreeController.cs @@ -34,13 +34,26 @@ namespace Umbraco.Web.Trees if (id == Constants.System.Root.ToInvariantString()) { - + //set the default to create + menu.DefaultMenuAlias = ActionNew.Instance.Alias; + //create action + menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias))); //refresh action menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true); return menu; } + if (id.EndsWith(FileSearchPattern.TrimStart("*")) == false) + { + //set the default to create + menu.DefaultMenuAlias = ActionNew.Instance.Alias; + //create action + menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias))); + //refresh action + menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true); + } + // TODO: Wire up new delete dialog menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias))); return menu; diff --git a/src/Umbraco.Web/Trees/PartialViewsTreeController.cs b/src/Umbraco.Web/Trees/PartialViewsTreeController.cs index 7a88def826..96da9a2e33 100644 --- a/src/Umbraco.Web/Trees/PartialViewsTreeController.cs +++ b/src/Umbraco.Web/Trees/PartialViewsTreeController.cs @@ -33,13 +33,26 @@ namespace Umbraco.Web.Trees if (id == Constants.System.Root.ToInvariantString()) { - + //set the default to create + menu.DefaultMenuAlias = ActionNew.Instance.Alias; + //create action + menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias))); //refresh action menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true); return menu; } + if (id.EndsWith(FileSearchPattern.TrimStart("*")) == false) + { + //set the default to create + menu.DefaultMenuAlias = ActionNew.Instance.Alias; + //create action + menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias))); + //refresh action + menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true); + } + // TODO: Wire up new delete dialog menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias))); return menu; diff --git a/src/Umbraco.Web/Trees/ScriptTreeController.cs b/src/Umbraco.Web/Trees/ScriptTreeController.cs index ae19dbcf48..c7d4e728aa 100644 --- a/src/Umbraco.Web/Trees/ScriptTreeController.cs +++ b/src/Umbraco.Web/Trees/ScriptTreeController.cs @@ -1,4 +1,5 @@ -using Umbraco.Core; +using System.Linq; +using Umbraco.Core; using Umbraco.Core.IO; using umbraco.BusinessLogic.Actions; using Umbraco.Web.Models.Trees; @@ -30,13 +31,26 @@ namespace Umbraco.Web.Trees if (id == Constants.System.Root.ToInvariantString()) { - + //set the default to create + menu.DefaultMenuAlias = ActionNew.Instance.Alias; + //create action + menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias))); //refresh action menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true); return menu; } + if (id.EndsWith(FileSearchPattern.TrimStart("*")) == false) + { + //set the default to create + menu.DefaultMenuAlias = ActionNew.Instance.Alias; + //create action + menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias))); + //refresh action + menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true); + } + // TODO: Wire up new delete dialog menu.Items.Add(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias))); return menu; diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 3e5172b774..3171821c7e 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -338,6 +338,7 @@ +