Merge pull request #1736 from umbraco/temp-U4-9429

U4-9429 Make new create dialogs for code files (or rethink snippets)
This commit is contained in:
Warren Buckley
2017-02-07 21:28:43 +00:00
committed by GitHub
19 changed files with 744 additions and 124 deletions

View File

@@ -744,40 +744,9 @@ namespace Umbraco.Core.Services
if (CreatingPartialView.IsRaisedEventCancelled(new NewEventArgs<IPartialView>(partialView, true, partialView.Alias, -1), this))
return Attempt<IPartialView>.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()))

View File

@@ -331,6 +331,13 @@ namespace Umbraco.Core.Services
/// <returns>The content of the macro partial view.</returns>
Stream GetPartialViewMacroFileContentStream(string filepath);
/// <summary>
/// Gets the content of a macro partial view snippet as a string
/// </summary>
/// <param name="snippetName">The name of the snippet</param>
/// <returns></returns>
string GetPartialViewMacroSnippetContent(string snippetName);
/// <summary>
/// Sets the content of a macro partial view.
/// </summary>
@@ -352,6 +359,13 @@ namespace Umbraco.Core.Services
/// <returns>The content of the partial view.</returns>
Stream GetPartialViewFileContentStream(string filepath);
/// <summary>
/// Gets the content of a partial view snippet as a string.
/// </summary>
/// <param name="snippetName">The name of the snippet</param>
/// <returns>The content of the partial view.</returns>
string GetPartialViewSnippetContent(string snippetName);
/// <summary>
/// Sets the content of a partial view.
/// </summary>

View File

@@ -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
* <pre>
* codefileResource.getScaffold()
* .then(function(template) {
* alert('its here!');
* });
* </pre>
*
* @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
* <pre>
* codefileResource.getSnippets("partialViews")
* .then(function(snippets) {
* alert('its here!');
* });
* </pre>
*
* @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
* <pre>
* codefileResource.getScaffold("partialViews", "Breadcrumb")
* .then(function(data) {
* alert('its here!');
* });
* </pre>
*
* @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);
}
};
}

View File

@@ -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);
})();

View File

@@ -0,0 +1,75 @@
<div ng-controller="Umbraco.Editors.PartialViewMacros.CreateController as vm" ng-cloak>
<div class="umbracoDialog umb-dialog-body with-footer">
<div class="umb-pane" ng-if="!vm.creatingFolder">
<h5><localize key="create_createUnder">Create an item under</localize> {{currentNode.name}}</h5>
<!-- Main options -->
<div ng-if="!vm.showSnippets">
<ul class="umb-actions umb-actions-child">
<li>
<a href="" ng-click="vm.createPartialViewMacro()" umb-auto-focus>
<i class="large icon-article"></i>
<span class="menu-label"><localize key="create_newEmptyPartialViewMacro">New empty partial view macro</localize></span>
</a>
</li>
<li>
<a href="" ng-click="vm.showCreateFromSnippet()">
<i class="large icon-article"></i>
<span class="menu-label"><localize key="create_newPartialViewMacroFromSnippet">New partial view macro from snippet</localize></span>
</a>
</li>
<li>
<a href="" ng-click="vm.showCreateFolder()">
<i class="large icon-folder"></i>
<span class="menu-label"><localize key="general_folder"></localize></span>
</a>
</li>
</ul>
</div>
<!-- Snippets list -->
<div ng-if="vm.showSnippets">
<ul class="umb-actions umb-actions-child">
<li ng-repeat="snippet in vm.snippets">
<a href="" ng-click="vm.createPartialViewMacro(snippet)" style="padding-top: 6px; padding-bottom: 6px;">
<i class="icon-article" style="font-size: 20px;"></i>
<span class="menu-label" style="margin-left: 0; padding-left: 5px;">{{ snippet.name }}</span>
</a>
</li>
</ul>
</div>
</div>
<!-- Create folder -->
<div class="umb-pane" ng-if="vm.creatingFolder">
<form novalidate name="createFolderForm"
ng-submit="vm.createFolder()"
val-form-manager>
<div ng-show="error">
<h5 class="text-error">{{error.errorMsg}}</h5>
<p class="text-error">{{error.data.message}}</p>
</div>
<umb-control-group label="Enter a folder name" hide-label="false">
<input type="text" name="folderName" ng-model="vm.folderName" class="umb-textstring textstring input-block-level" umb-auto-focus required />
</umb-control-group>
<button type="submit" class="btn btn-primary"><localize key="general_create">Create</localize></button>
</form>
</div>
</div>
<!-- Dialog footer -->
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar">
<button class="btn" ng-click="nav.hideDialog(true)">
<localize key="buttons_somethingElse">Do something else</localize>
</button>
</div>
</div>

View File

@@ -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);

View File

@@ -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);
})();

View File

@@ -0,0 +1,75 @@
<div ng-controller="Umbraco.Editors.PartialViews.CreateController as vm" ng-cloak>
<div class="umbracoDialog umb-dialog-body with-footer">
<div class="umb-pane" ng-if="!vm.creatingFolder">
<h5><localize key="create_createUnder">Create an item under</localize> {{currentNode.name}}</h5>
<!-- Main options -->
<div ng-if="!vm.showSnippets">
<ul class="umb-actions umb-actions-child">
<li>
<a href="" ng-click="vm.createPartialView()" umb-auto-focus>
<i class="large icon-article"></i>
<span class="menu-label"><localize key="create_newEmptyPartialView">New empty partial view</localize></span>
</a>
</li>
<li>
<a href="" ng-click="vm.showCreateFromSnippet()">
<i class="large icon-article"></i>
<span class="menu-label"><localize key="create_newPartialViewFromSnippet">New partial view from snippet</localize></span>
</a>
</li>
<li>
<a href="" ng-click="vm.showCreateFolder()">
<i class="large icon-folder"></i>
<span class="menu-label"><localize key="general_folder"></localize></span>
</a>
</li>
</ul>
</div>
<!-- Snippets list -->
<div ng-if="vm.showSnippets">
<ul class="umb-actions umb-actions-child">
<li ng-repeat="snippet in vm.snippets">
<a href="" ng-click="vm.createPartialView(snippet)" style="padding-top: 6px; padding-bottom: 6px;">
<i class="icon-article" style="font-size: 20px;"></i>
<span class="menu-label" style="margin-left: 0; padding-left: 5px;">{{ snippet.name }}</span>
</a>
</li>
</ul>
</div>
</div>
<!-- Create folder -->
<div class="umb-pane" ng-if="vm.creatingFolder">
<form novalidate name="createFolderForm"
ng-submit="vm.createFolder()"
val-form-manager>
<div ng-show="error">
<h5 class="text-error">{{error.errorMsg}}</h5>
<p class="text-error">{{error.data.message}}</p>
</div>
<umb-control-group label="Enter a folder name" hide-label="false">
<input type="text" name="folderName" ng-model="vm.folderName" class="umb-textstring textstring input-block-level" umb-auto-focus required />
</umb-control-group>
<button type="submit" class="btn btn-primary"><localize key="general_create">Create</localize></button>
</form>
</div>
</div>
<!-- Dialog footer -->
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar">
<button class="btn" ng-click="nav.hideDialog(true)">
<localize key="buttons_somethingElse">Do something else</localize>
</button>
</div>
</div>

View File

@@ -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) {

View File

@@ -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);
})();

View File

@@ -0,0 +1,47 @@
<div class="umbracoDialog umb-dialog-body with-footer" ng-controller="Umbraco.Editors.Scripts.CreateController as vm" ng-cloak>
<div class="umb-pane" ng-if="!vm.creatingFolder">
<h5><localize key="create_createUnder">Create an item under</localize> {{currentNode.name}}</h5>
<ul class="umb-actions umb-actions-child">
<li>
<a href="" umb-auto-focus ng-click="vm.createFile()">
<i class="large icon-script"></i>
<span class="menu-label"><localize key="create_newJavascriptFile">New javascript file</localize></span>
</a>
</li>
<li>
<a href="" ng-click="vm.showCreateFolder()">
<i class="large icon-folder"></i>
<span class="menu-label"><localize key="general_folder"></localize></span>
</a>
</li>
</ul>
</div>
<div class="umb-pane" ng-if="vm.creatingFolder">
<form novalidate name="createFolderForm"
ng-submit="vm.createFolder()"
val-form-manager>
<div ng-show="error">
<h5 class="text-error">{{error.errorMsg}}</h5>
<p class="text-error">{{error.data.message}}</p>
</div>
<umb-control-group label="Enter a folder name" hide-label="false">
<input type="text" name="folderName" ng-model="vm.folderName" class="umb-textstring textstring input-block-level" umb-auto-focus required />
</umb-control-group>
<button type="submit" class="btn btn-primary"><localize key="general_create">Create</localize></button>
</form>
</div>
</div>
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar" ng-if="!vm.creatingFolder">
<button class="btn" ng-click="nav.hideDialog(true)">
<localize key="buttons_somethingElse">Do something else</localize>
</button>
</div>

View File

@@ -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 {

View File

@@ -197,6 +197,11 @@
<key alias="documentTypeWithoutTemplate">Document Type without a template</key>
<key alias="newFolder">New folder</key>
<key alias="newDataType">New data type</key>
<key alias="newJavascriptFile">New javascript file</key>
<key alias="newEmptyPartialView">New empty partial view</key>
<key alias="newPartialViewFromSnippet">New partial view from snippet</key>
<key alias="newEmptyPartialViewMacro">New empty partial view macro</key>
<key alias="newPartialViewMacroFromSnippet">New partial view macro from snippet</key>
</area>
<area alias="dashboard">
<key alias="browser">Browse your website</key>

View File

@@ -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);
}
/// <summary>
/// Used to get a list of available templates/snippets to base a new Partial View og Partial View Macro from
/// </summary>
/// <param name="type">This is a string but will be 'partialViews', 'partialViewMacros'</param>
/// <returns>Returns a list of <see cref="SnippetDisplay"/> if a correct type is sent</returns>
public IEnumerable<SnippetDisplay> GetSnippets(string type)
{
if (string.IsNullOrWhiteSpace(type))
{
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
IEnumerable<string> 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});
}
/// <summary>
/// Used to scaffold the json object for the editors for 'scripts', 'partialViews', 'partialViewMacros'
/// </summary>
/// <param name="type">This is a string but will be 'scripts' 'partialViews', 'partialViewMacros'</param>
/// <param name="id"></param>
/// <param name="snippetName"></param>
/// <returns></returns>
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<IPartialView, CodeFileDisplay>(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<IPartialView, CodeFileDisplay>(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<Script, CodeFileDisplay>(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;
}
/// <summary>
/// Used to delete a specific file from disk via the FileService
/// </summary>
@@ -150,7 +245,7 @@ namespace Umbraco.Web.Editors
}
/// <summary>
/// Used to save/update an existing file after its initial creation
/// Used to create or update a 'partialview', 'partialviewmacro' or 'script' file
/// </summary>
/// <param name="display"></param>
/// <returns>The updated CodeFileDisplay model</returns>
@@ -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<IPartialView> CreateOrUpdatePartialView(CodeFileDisplay display)
{
Attempt<IPartialView> 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<IPartialView> CreateOrUpdatePartialViewMacro(CodeFileDisplay display)
{
Attempt<IPartialView> 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;
}
}
}

View File

@@ -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; }
}
}

View File

@@ -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<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
//refresh action
menu.Items.Add<RefreshNode, ActionRefresh>(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<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
//refresh action
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
}
// TODO: Wire up new delete dialog
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
return menu;

View File

@@ -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<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
//refresh action
menu.Items.Add<RefreshNode, ActionRefresh>(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<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
//refresh action
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
}
// TODO: Wire up new delete dialog
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
return menu;

View File

@@ -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<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
//refresh action
menu.Items.Add<RefreshNode, ActionRefresh>(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<ActionNew>(Services.TextService.Localize(string.Format("actions/{0}", ActionNew.Instance.Alias)));
//refresh action
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
}
// TODO: Wire up new delete dialog
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
return menu;

View File

@@ -338,6 +338,7 @@
<Compile Include="Models\ContentEditing\PropertyGroupBasic.cs" />
<Compile Include="Models\ContentEditing\PropertyTypeBasic.cs" />
<Compile Include="Models\ContentEditing\SimpleNotificationModel.cs" />
<Compile Include="Models\ContentEditing\SnippetDisplay.cs" />
<Compile Include="Models\ContentEditing\TemplateDisplay.cs" />
<Compile Include="Models\LocalPackageInstallModel.cs" />
<Compile Include="Models\Mapping\CodeFileDisplayMapper.cs" />