Compare commits
48 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f3b364022a | |||
| 56ae2b709d | |||
| 0acc202740 | |||
| 4ad0c1bb89 | |||
| 67da15330e | |||
| a458e7daf0 | |||
| d85cb9e15e | |||
| 19a4cf774b | |||
| ab00ba8a12 | |||
| 57e2a19023 | |||
| daa80a7bf6 | |||
| 8152e7cb92 | |||
| adccb4161e | |||
| 72a0187295 | |||
| 24d6287918 | |||
| 55900a3464 | |||
| 36e9bb4d78 | |||
| 639d04381e | |||
| 2465eb233e | |||
| 7f905bce0e | |||
| 205ea22daa | |||
| f3e78e990f | |||
| 2f7b532209 | |||
| abebb40461 | |||
| 3b54db9b49 | |||
| 1defc1e0e4 | |||
| a7e626f4a7 | |||
| 04f6a01196 | |||
| ef64fbb839 | |||
| 2424a1c04b | |||
| c8c7de065d | |||
| 61d71d0552 | |||
| a09755ef7f | |||
| afae06a866 | |||
| 051af5c48e | |||
| 1fb05fcca7 | |||
| 49d24dada7 | |||
| ef9dd6d803 | |||
| a162f21a70 | |||
| ace111aefb | |||
| dfe3798aab | |||
| 975535a9e2 | |||
| e7f7631d1e | |||
| 23304aca0b | |||
| 845dd4673c | |||
| 14e402878a | |||
| 5a2687d520 | |||
| 4c330c8654 |
@@ -1,3 +1,3 @@
|
||||
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
|
||||
7.6.0
|
||||
alpha055
|
||||
alpha056
|
||||
+1
-1
@@ -12,4 +12,4 @@ using System.Resources;
|
||||
[assembly: AssemblyVersion("1.0.*")]
|
||||
|
||||
[assembly: AssemblyFileVersion("7.6.0")]
|
||||
[assembly: AssemblyInformationalVersion("7.6.0-alpha055")]
|
||||
[assembly: AssemblyInformationalVersion("7.6.0-alpha056")]
|
||||
@@ -24,7 +24,7 @@ namespace Umbraco.Core.Configuration
|
||||
/// Gets the version comment (like beta or RC).
|
||||
/// </summary>
|
||||
/// <value>The version comment.</value>
|
||||
public static string CurrentComment { get { return "alpha055"; } }
|
||||
public static string CurrentComment { get { return "alpha056"; } }
|
||||
|
||||
// Get the version of the umbraco.dll by looking at a class in that dll
|
||||
// Had to do it like this due to medium trust issues, see: http://haacked.com/archive/2010/11/04/assembly-location-and-medium-trust.aspx
|
||||
|
||||
@@ -112,9 +112,15 @@
|
||||
|
||||
public const string Languages = "languages";
|
||||
|
||||
public const string PartialViews = "partialViews";
|
||||
|
||||
public const string PartialViewMacros = "partialViewMacros";
|
||||
|
||||
public const string Scripts = "scripts";
|
||||
|
||||
//TODO: Fill in the rest!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -4,7 +4,7 @@ using Umbraco.Core.Models;
|
||||
|
||||
namespace Umbraco.Core
|
||||
{
|
||||
|
||||
|
||||
public static partial class Constants
|
||||
{
|
||||
|
||||
@@ -37,6 +37,11 @@ namespace Umbraco.Core
|
||||
public const string MemberGroup = "member-group";
|
||||
|
||||
public const string RelationType = "relation-type";
|
||||
|
||||
// forms
|
||||
public const string FormsForm = "forms-form";
|
||||
public const string FormsWorkflow = "forms-workflow";
|
||||
public const string FormsRecord = "forms-record";
|
||||
|
||||
// string entity types
|
||||
|
||||
@@ -82,6 +87,12 @@ namespace Umbraco.Core
|
||||
return Stylesheet;
|
||||
case UmbracoObjectTypes.RelationType:
|
||||
return RelationType;
|
||||
case UmbracoObjectTypes.FormsForm:
|
||||
return FormsForm;
|
||||
case UmbracoObjectTypes.FormsWorkflow:
|
||||
return FormsWorkflow;
|
||||
case UmbracoObjectTypes.FormsRecord:
|
||||
return FormsRecord;
|
||||
}
|
||||
throw new NotSupportedException(string.Format("UmbracoObjectType \"{0}\" does not have a matching EntityType.", umbracoObjectType));
|
||||
}
|
||||
@@ -118,6 +129,12 @@ namespace Umbraco.Core
|
||||
return UmbracoObjectTypes.Stylesheet;
|
||||
case RelationType:
|
||||
return UmbracoObjectTypes.RelationType;
|
||||
case FormsForm:
|
||||
return UmbracoObjectTypes.FormsForm;
|
||||
case FormsWorkflow:
|
||||
return UmbracoObjectTypes.FormsWorkflow;
|
||||
case FormsRecord:
|
||||
return UmbracoObjectTypes.FormsRecord;
|
||||
}
|
||||
throw new NotSupportedException(
|
||||
string.Format("EntityType \"{0}\" does not have a matching UmbracoObjectType.", entityType));
|
||||
|
||||
@@ -162,6 +162,36 @@ namespace Umbraco.Core
|
||||
/// Guid for a relation type.
|
||||
/// </summary>
|
||||
public static readonly Guid RelationTypeGuid = new Guid(RelationType);
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Forms Form.
|
||||
/// </summary>
|
||||
public const string FormsForm = "F5A9F787-6593-46F0-B8FF-BFD9BCA9F6BB";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Forms Form.
|
||||
/// </summary>
|
||||
public static readonly Guid FormsFormGuid = new Guid(FormsForm);
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Forms Workflow.
|
||||
/// </summary>
|
||||
public const string FormsWorkflow = "42D7BF9B-A362-4FEE-B45A-674D5C064B70";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Forms Workflow.
|
||||
/// </summary>
|
||||
public static readonly Guid FormsWorkflowGuid = new Guid(FormsWorkflow);
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Forms Record.
|
||||
/// </summary>
|
||||
public const string FormsRecord = "CFED6CE4-9359-443E-9977-9956FEB1D867";
|
||||
|
||||
/// <summary>
|
||||
/// Guid for a Forms Record.
|
||||
/// </summary>
|
||||
public static readonly Guid FormsRecordGuid = new Guid(FormsRecord);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,12 +11,12 @@ namespace Umbraco.Core.Deploy
|
||||
public interface IGridCellValueConnector
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether the connector supports a specified grid editor alias.
|
||||
/// Gets a value indicating whether the connector supports a specified grid editor view.
|
||||
/// </summary>
|
||||
/// <param name="alias">The grid editor alias.</param>
|
||||
/// <remarks>A value indicating whether the connector supports the grid editor alias.</remarks>
|
||||
/// <remarks>Note that <paramref name="alias" /> can be string.Empty to indicate the "default" connector.</remarks>
|
||||
bool IsConnector(string alias);
|
||||
/// <param name="view">The grid editor view. It needs to be the view instead of the alias as the view is really what identifies what kind of connector should be used. Alias can be anything and you can have multiple different aliases using the same kind of view.</param>
|
||||
/// <remarks>A value indicating whether the connector supports the grid editor view.</remarks>
|
||||
/// <remarks>Note that <paramref name="view" /> can be string.Empty to indicate the "default" connector.</remarks>
|
||||
bool IsConnector(string view);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value to be deployed from the control value as a string.
|
||||
|
||||
@@ -143,6 +143,27 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.RelationType)]
|
||||
[FriendlyName("Relation Type")]
|
||||
RelationType
|
||||
RelationType,
|
||||
|
||||
/// <summary>
|
||||
/// Forms Form
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.FormsForm)]
|
||||
[FriendlyName("Form")]
|
||||
FormsForm,
|
||||
|
||||
/// <summary>
|
||||
/// Forms Workflow
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.FormsWorkflow)]
|
||||
[FriendlyName("Workflow")]
|
||||
FormsWorkflow,
|
||||
|
||||
/// <summary>
|
||||
/// Forms Record
|
||||
/// </summary>
|
||||
[UmbracoObjectType(Constants.ObjectTypes.FormsRecord)]
|
||||
[FriendlyName("Record")]
|
||||
FormsRecord
|
||||
}
|
||||
}
|
||||
@@ -164,7 +164,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
//each order by param needs to be in a bracket! see: https://github.com/toptensoftware/PetaPoco/issues/177
|
||||
query.OrderBy(orderBy == null
|
||||
? "(umbracoNode.id)"
|
||||
? "(umbracoNode.id)"
|
||||
: string.Join(",", orderBy.Select(x => string.Format("({0})", SqlSyntax.GetQuotedColumnName(x)))));
|
||||
|
||||
var pagedResult = Database.Page<ContentXmlDto>(pageIndex + 1, pageSize, query);
|
||||
@@ -462,14 +462,14 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
totalRecords = Convert.ToInt32(pagedResult.TotalItems);
|
||||
|
||||
//NOTE: We need to check the actual items returned, not the 'totalRecords', that is because if you request a page number
|
||||
// that doesn't actually have any data on it, the totalRecords will still indicate there are records but there are none in
|
||||
// that doesn't actually have any data on it, the totalRecords will still indicate there are records but there are none in
|
||||
// the pageResult, then the GetAll will actually return ALL records in the db.
|
||||
if (pagedResult.Items.Any())
|
||||
{
|
||||
//Crete the inner paged query that was used above to get the paged result, we'll use that as the inner sub query
|
||||
var args = sqlNodeIdsWithSort.Arguments;
|
||||
string sqlStringCount, sqlStringPage;
|
||||
Database.BuildPageQueries<TDto>(pageIndex * pageSize, pageSize, sqlNodeIdsWithSort.SQL, ref args, out sqlStringCount, out sqlStringPage);
|
||||
Database.BuildPageQueries<TDto>(pageIndex * pageSize, pageSize, sqlNodeIdsWithSort.SQL, ref args, out sqlStringCount, out sqlStringPage);
|
||||
|
||||
//We need to make this FULL query an inner join on the paged ID query
|
||||
var splitQuery = sqlQueryFull.SQL.Split(new[] { "WHERE " }, StringSplitOptions.None);
|
||||
@@ -503,7 +503,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
{
|
||||
if (documentDefs.Count == 0) return new Dictionary<int, PropertyCollection>();
|
||||
|
||||
//we need to parse the original SQL statement and reduce the columns to just cmsContent.nodeId, cmsContentVersion.VersionId so that we can use
|
||||
//we need to parse the original SQL statement and reduce the columns to just cmsContent.nodeId, cmsContentVersion.VersionId so that we can use
|
||||
// the statement to go get the property data for all of the items by using an inner join
|
||||
var parsedOriginalSql = "SELECT {0} " + docSql.SQL.Substring(docSql.SQL.IndexOf("FROM", StringComparison.Ordinal));
|
||||
//now remove everything from an Orderby clause and beyond
|
||||
@@ -514,7 +514,7 @@ namespace Umbraco.Core.Persistence.Repositories
|
||||
|
||||
//This retrieves all pre-values for all data types that are referenced for all property types
|
||||
// that exist in the data set.
|
||||
//Benchmarks show that eagerly loading these so that we can lazily read the property data
|
||||
//Benchmarks show that eagerly loading these so that we can lazily read the property data
|
||||
// below (with the use of Query intead of Fetch) go about 30% faster, so we'll eagerly load
|
||||
// this now since we cannot execute another reader inside of reading the property data.
|
||||
var preValsSql = new Sql(@"SELECT a.id, a.value, a.sortorder, a.alias, a.datatypeNodeId
|
||||
@@ -533,11 +533,11 @@ WHERE EXISTS(
|
||||
|
||||
//It's Important with the sort order here! We require this to be sorted by node id,
|
||||
// this is required because this data set can be huge depending on the page size. Due
|
||||
// to it's size we need to be smart about iterating over the property values to build
|
||||
// the document. Before we used to use Linq to get the property data for a given content node
|
||||
// to it's size we need to be smart about iterating over the property values to build
|
||||
// the document. Before we used to use Linq to get the property data for a given content node
|
||||
// and perform a Distinct() call. This kills performance because that would mean if we had 7000 nodes
|
||||
// and on each iteration we will perform a lookup on potentially 100,000 property rows against the node
|
||||
// id which turns out to be a crazy amount of iterations. Instead we know it's sorted by this value we'll
|
||||
// id which turns out to be a crazy amount of iterations. Instead we know it's sorted by this value we'll
|
||||
// keep an index stored of the rows being read so we never have to re-iterate the entire data set
|
||||
// on each document iteration.
|
||||
var propSql = new Sql(@"SELECT cmsPropertyData.*
|
||||
@@ -563,6 +563,7 @@ ORDER BY contentNodeId, propertytypeid
|
||||
|
||||
//keep track of the current property data item being enumerated
|
||||
var propertyDataSetEnumerator = allPropertyData.GetEnumerator();
|
||||
var hasCurrent = false; // initially there is no enumerator.Current
|
||||
|
||||
try
|
||||
{
|
||||
@@ -570,7 +571,7 @@ ORDER BY contentNodeId, propertytypeid
|
||||
// which allows us to more efficiently iterate over the large data set of property values
|
||||
foreach (var def in documentDefs.OrderBy(x => x.Id))
|
||||
{
|
||||
//get the resolved proeprties from our local cache, or resolve them and put them in cache
|
||||
// get the resolved properties from our local cache, or resolve them and put them in cache
|
||||
PropertyType[] compositionProperties;
|
||||
if (resolvedCompositionProperties.ContainsKey(def.Composition.Id))
|
||||
{
|
||||
@@ -582,28 +583,20 @@ ORDER BY contentNodeId, propertytypeid
|
||||
resolvedCompositionProperties[def.Composition.Id] = compositionProperties;
|
||||
}
|
||||
|
||||
// assemble the dtos for this def
|
||||
// use the available enumerator.Current if any else move to next
|
||||
var propertyDataDtos = new List<PropertyDataDto>();
|
||||
|
||||
//Check if there is a current enumerated item and check if we match and add it
|
||||
if (propertyDataSetEnumerator.Current != null)
|
||||
{
|
||||
if (propertyDataSetEnumerator.Current.NodeId == def.Id)
|
||||
{
|
||||
propertyDataDtos.Add(propertyDataSetEnumerator.Current);
|
||||
}
|
||||
}
|
||||
//Move to the next position, see if we match and add it, if not exit
|
||||
while (propertyDataSetEnumerator.MoveNext())
|
||||
while (hasCurrent || propertyDataSetEnumerator.MoveNext())
|
||||
{
|
||||
if (propertyDataSetEnumerator.Current.NodeId == def.Id)
|
||||
{
|
||||
hasCurrent = false; // enumerator.Current is not available
|
||||
propertyDataDtos.Add(propertyDataSetEnumerator.Current);
|
||||
}
|
||||
else
|
||||
{
|
||||
//the node id has changed so we need to exit the loop,
|
||||
//the enumerator position will be maintained
|
||||
break;
|
||||
hasCurrent = true; // enumerator.Current is available for another def
|
||||
break; // no more propertyDataDto for this def
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@ using System.Web;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Configuration.Grid;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
|
||||
@@ -1382,6 +1382,7 @@ namespace Umbraco.Core.Services
|
||||
_mediaFileSystem.GenerateThumbnails(filestream, filepath, propertyType);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#region Event Handlers
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Profiling;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
|
||||
namespace Umbraco.Tests.IO
|
||||
@@ -18,6 +18,9 @@ namespace Umbraco.Tests.IO
|
||||
//init the config singleton
|
||||
var config = SettingsForTests.GetDefault();
|
||||
SettingsForTests.ConfigureSettings(config);
|
||||
|
||||
// media fs wants this
|
||||
ApplicationContext.Current = new ApplicationContext(CacheHelper.CreateDisabledCacheHelper(), new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -42,7 +45,6 @@ namespace Umbraco.Tests.IO
|
||||
Assert.Throws<InvalidOperationException>(() => FileSystemProviderManager.Current.GetFileSystemProvider<InvalidTypedFileSystem>());
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Used in unit tests, for a typed file system we need to inherit from FileSystemWrapper and they MUST have a ctor
|
||||
/// that only accepts a base IFileSystem object
|
||||
|
||||
@@ -67,6 +67,66 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
return repository;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This tests the regression issue of U4-9438
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The problem was the iteration of the property data in VersionableRepositoryBase when a content item
|
||||
/// in the list actually doesn't have any property types, it would still skip over a property row.
|
||||
/// To test, we have 3 content items, the first has properties, the second doesn't and the third does.
|
||||
/// </remarks>
|
||||
[Test]
|
||||
public void Property_Data_Assigned_Correctly()
|
||||
{
|
||||
// Arrange
|
||||
var provider = new PetaPocoUnitOfWorkProvider(Logger);
|
||||
var unitOfWork = provider.GetUnitOfWork();
|
||||
ContentTypeRepository contentTypeRepository;
|
||||
|
||||
var allContent = new List<IContent>();
|
||||
using (var repository = CreateRepository(unitOfWork, out contentTypeRepository))
|
||||
{
|
||||
var emptyContentType = MockedContentTypes.CreateBasicContentType();
|
||||
var hasPropertiesContentType = MockedContentTypes.CreateSimpleContentType("umbTextpage1", "Textpage");
|
||||
var content1 = MockedContent.CreateSimpleContent(hasPropertiesContentType);
|
||||
var content2 = MockedContent.CreateBasicContent(emptyContentType);
|
||||
var content3 = MockedContent.CreateSimpleContent(hasPropertiesContentType);
|
||||
|
||||
// Act
|
||||
contentTypeRepository.AddOrUpdate(emptyContentType);
|
||||
contentTypeRepository.AddOrUpdate(hasPropertiesContentType);
|
||||
repository.AddOrUpdate(content1);
|
||||
repository.AddOrUpdate(content2);
|
||||
repository.AddOrUpdate(content3);
|
||||
unitOfWork.Commit();
|
||||
|
||||
allContent.Add(content1);
|
||||
allContent.Add(content2);
|
||||
allContent.Add(content3);
|
||||
}
|
||||
|
||||
// Assert
|
||||
using (var repository = CreateRepository(unitOfWork, out contentTypeRepository))
|
||||
{
|
||||
//this will cause the GetPropertyCollection to execute and we need to ensure that
|
||||
// all of the properties and property types are all correct
|
||||
var result = repository.GetAll(allContent.Select(x => x.Id).ToArray()).ToArray();
|
||||
|
||||
foreach (var content in result)
|
||||
{
|
||||
foreach (var contentProperty in content.Properties)
|
||||
{
|
||||
//prior to the fix, the 2nd document iteration in the GetPropertyCollection would have caused
|
||||
//the enumerator to move forward past the first property of the 3rd document which would have
|
||||
//ended up not assiging a property to the 3rd document. This would have ended up with the 3rd
|
||||
//document still having 3 properties but the last one would not have been assigned an identity
|
||||
//because the property data would not have been assigned.
|
||||
Assert.IsTrue(contentProperty.HasIdentity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Rebuild_Xml_Structures_With_Non_Latest_Version()
|
||||
{
|
||||
|
||||
@@ -297,7 +297,7 @@ namespace Umbraco.Tests.Plugins
|
||||
public void Resolves_Trees()
|
||||
{
|
||||
var trees = _manager.ResolveTrees();
|
||||
Assert.AreEqual(39, trees.Count());
|
||||
Assert.AreEqual(37, trees.Count());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
||||
@@ -6,9 +6,18 @@ namespace Umbraco.Tests.TestHelpers.Entities
|
||||
{
|
||||
public class MockedContent
|
||||
{
|
||||
public static Content CreateBasicContent(IContentType contentType)
|
||||
{
|
||||
var content = new Content("Home", -1, contentType) { Level = 1, SortOrder = 1, CreatorId = 0, WriterId = 0 };
|
||||
|
||||
content.ResetDirtyProperties(false);
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
public static Content CreateSimpleContent(IContentType contentType)
|
||||
{
|
||||
var content = new Content("Home", -1, contentType) { Language = "en-US", Level = 1, SortOrder = 1, CreatorId = 0, WriterId = 0 };
|
||||
var content = new Content("Home", -1, contentType) { Level = 1, SortOrder = 1, CreatorId = 0, WriterId = 0 };
|
||||
object obj =
|
||||
new
|
||||
{
|
||||
@@ -26,7 +35,7 @@ namespace Umbraco.Tests.TestHelpers.Entities
|
||||
|
||||
public static Content CreateSimpleContent(IContentType contentType, string name, int parentId)
|
||||
{
|
||||
var content = new Content(name, parentId, contentType) { Language = "en-US", CreatorId = 0, WriterId = 0 };
|
||||
var content = new Content(name, parentId, contentType) { CreatorId = 0, WriterId = 0 };
|
||||
object obj =
|
||||
new
|
||||
{
|
||||
@@ -44,7 +53,7 @@ namespace Umbraco.Tests.TestHelpers.Entities
|
||||
|
||||
public static Content CreateSimpleContent(IContentType contentType, string name, IContent parent)
|
||||
{
|
||||
var content = new Content(name, parent, contentType) { Language = "en-US", CreatorId = 0, WriterId = 0 };
|
||||
var content = new Content(name, parent, contentType) { CreatorId = 0, WriterId = 0 };
|
||||
object obj =
|
||||
new
|
||||
{
|
||||
@@ -62,7 +71,7 @@ namespace Umbraco.Tests.TestHelpers.Entities
|
||||
|
||||
public static Content CreateTextpageContent(IContentType contentType, string name, int parentId)
|
||||
{
|
||||
var content = new Content(name, parentId, contentType) { Language = "en-US", CreatorId = 0, WriterId = 0};
|
||||
var content = new Content(name, parentId, contentType) { CreatorId = 0, WriterId = 0};
|
||||
object obj =
|
||||
new
|
||||
{
|
||||
@@ -81,7 +90,7 @@ namespace Umbraco.Tests.TestHelpers.Entities
|
||||
|
||||
public static Content CreateSimpleContentWithSpecialDatabaseTypes(IContentType contentType, string name, int parentId, string decimalValue, string intValue, DateTime datetimeValue)
|
||||
{
|
||||
var content = new Content(name, parentId, contentType) { Language = "en-US", CreatorId = 0, WriterId = 0 };
|
||||
var content = new Content(name, parentId, contentType) { CreatorId = 0, WriterId = 0 };
|
||||
object obj = new
|
||||
{
|
||||
decimalProperty = decimalValue,
|
||||
@@ -96,7 +105,7 @@ namespace Umbraco.Tests.TestHelpers.Entities
|
||||
|
||||
public static Content CreateAllTypesContent(IContentType contentType, string name, int parentId)
|
||||
{
|
||||
var content = new Content("Random Content Name", parentId, contentType) { Language = "en-US", Level = 1, SortOrder = 1, CreatorId = 0, WriterId = 0 };
|
||||
var content = new Content("Random Content Name", parentId, contentType) { Level = 1, SortOrder = 1, CreatorId = 0, WriterId = 0 };
|
||||
|
||||
content.SetValue("isTrue", true);
|
||||
content.SetValue("number", 42);
|
||||
@@ -130,7 +139,7 @@ namespace Umbraco.Tests.TestHelpers.Entities
|
||||
for (int i = 0; i < amount; i++)
|
||||
{
|
||||
var name = "Textpage No-" + i;
|
||||
var content = new Content(name, parentId, contentType) { Language = "en-US", CreatorId = 0, WriterId = 0 };
|
||||
var content = new Content(name, parentId, contentType) { CreatorId = 0, WriterId = 0 };
|
||||
object obj =
|
||||
new
|
||||
{
|
||||
|
||||
@@ -7,6 +7,13 @@ namespace Umbraco.Tests.TestHelpers.Entities
|
||||
{
|
||||
public class MockedContentTypes
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a content type without any properties
|
||||
/// </summary>
|
||||
/// <param name="alias"></param>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="parent"></param>
|
||||
/// <returns></returns>
|
||||
public static ContentType CreateBasicContentType(string alias = "basePage", string name = "Base Page",
|
||||
ContentType parent = null)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,183 @@
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name umbraco.resources.codefileResource
|
||||
* @description Loads in data for files that contain code such as js scripts, partial views and partial view macros
|
||||
**/
|
||||
function codefileResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
|
||||
return {
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.codefileResource#getByPath
|
||||
* @methodOf umbraco.resources.codefileResource
|
||||
*
|
||||
* @description
|
||||
* Gets a codefile item with a given path
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* codefileResource.getByPath('scripts', 'oooh-la-la.js')
|
||||
* .then(function(codefile) {
|
||||
* alert('its here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* <pre>
|
||||
* codefileResource.getByPath('partialView', 'Grid%2fEditors%2fBase.cshtml')
|
||||
* .then(function(codefile) {
|
||||
* alert('its here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {type} the type of script (partialView, partialViewMacro, script)
|
||||
* @param {virtualpath} the virtual path of the script
|
||||
* @returns {Promise} resourcePromise object.
|
||||
*
|
||||
*/
|
||||
getByPath: function (type, virtualpath) {
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"codeFileApiBaseUrl",
|
||||
"GetByPath",
|
||||
[{ type: type }, {virtualPath: virtualpath }])),
|
||||
"Failed to retrieve data for " + type + " from virtual path " + virtualpath);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.codefileResource#getByAlias
|
||||
* @methodOf umbraco.resources.codefileResource
|
||||
*
|
||||
* @description
|
||||
* Gets a template item with a given alias
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* codefileResource.getByAlias("upload")
|
||||
* .then(function(template) {
|
||||
* alert('its here!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {String} alias Alias of template to retrieve
|
||||
* @returns {Promise} resourcePromise object.
|
||||
*
|
||||
*/
|
||||
getByAlias: function (alias) {
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"templateApiBaseUrl",
|
||||
"GetByAlias",
|
||||
[{ alias: alias }])),
|
||||
"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
|
||||
* @methodOf umbraco.resources.codefileResource
|
||||
*
|
||||
* @description
|
||||
* Deletes a codefile with a given type & path
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* codefileResource.deleteByPath('scripts', 'oooh-la-la.js')
|
||||
* .then(function() {
|
||||
* alert('its gone!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* <pre>
|
||||
* codefileResource.deleteByPath('partialViews', 'Grid%2fEditors%2fBase.cshtml')
|
||||
* .then(function() {
|
||||
* alert('its gone!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {type} the type of script (partialViews, partialViewMacros, scripts)
|
||||
* @param {virtualpath} the virtual path of the script
|
||||
* @returns {Promise} resourcePromise object.
|
||||
*
|
||||
*/
|
||||
deleteByPath: function (type, virtualpath) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"codeFileApiBaseUrl",
|
||||
"Delete",
|
||||
[{ type: type }, { virtualPath: virtualpath}])),
|
||||
"Failed to delete item: " + virtualpath);
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.resources.codefileResource#save
|
||||
* @methodOf umbraco.resources.codefileResource
|
||||
*
|
||||
* @description
|
||||
* Saves or update a codeFile
|
||||
*
|
||||
* ##usage
|
||||
* <pre>
|
||||
* codefileResource.save(codeFile)
|
||||
* .then(function(codeFile) {
|
||||
* alert('its saved!');
|
||||
* });
|
||||
* </pre>
|
||||
*
|
||||
* @param {Object} template object to save
|
||||
* @returns {Promise} resourcePromise object.
|
||||
*
|
||||
*/
|
||||
save: function (codeFile) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"codeFileApiBaseUrl",
|
||||
"PostSave"),
|
||||
codeFile),
|
||||
"Failed to save data for code file " + codeFile.virtualPath);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
angular.module("umbraco.resources").factory("codefileResource", codefileResource);
|
||||
@@ -19,14 +19,14 @@ function memberTypeResource($q, $http, umbRequestHelper, umbDataFormatter) {
|
||||
_.each(filterContentTypes, function (item) {
|
||||
query += "filterContentTypes=" + item + "&";
|
||||
});
|
||||
// if filterContentTypes array is empty we need a empty variable in the querystring otherwise the service returns a error
|
||||
// if filterContentTypes array is empty we need a empty variable in the querystring otherwise the service returns a error
|
||||
if (filterContentTypes.length === 0) {
|
||||
query += "filterContentTypes=&";
|
||||
}
|
||||
_.each(filterPropertyTypes, function (item) {
|
||||
query += "filterPropertyTypes=" + item + "&";
|
||||
});
|
||||
// if filterPropertyTypes array is empty we need a empty variable in the querystring otherwise the service returns a error
|
||||
// if filterPropertyTypes array is empty we need a empty variable in the querystring otherwise the service returns a error
|
||||
if (filterPropertyTypes.length === 0) {
|
||||
query += "filterPropertyTypes=&";
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
function templateHelperService() {
|
||||
|
||||
//crappy hack due to dictionary items not in umbracoNode table
|
||||
function getInsertDictionarySnippet(nodeName) {
|
||||
return "@Umbraco.GetDictionaryValue(\"" + nodeName + "\")";
|
||||
}
|
||||
|
||||
function getInsertPartialSnippet(nodeName) {
|
||||
return "@Html.Partial(\"" + nodeName + "\")";
|
||||
}
|
||||
|
||||
function getQuerySnippet(queryExpression) {
|
||||
var code = "\n@{\n" + "\tvar selection = " + queryExpression + ";\n}\n";
|
||||
code += "<ul>\n" +
|
||||
"\t@foreach(var item in selection){\n" +
|
||||
"\t\t<li>\n" +
|
||||
"\t\t\t<a href=\"@item.Url\">@item.Name</a>\n" +
|
||||
"\t\t</li>\n" +
|
||||
"\t}\n" +
|
||||
"</ul>\n\n";
|
||||
return code;
|
||||
}
|
||||
|
||||
function getRenderBodySnippet() {
|
||||
return "@RenderBody()";
|
||||
}
|
||||
|
||||
function getRenderSectionSnippet(sectionName, mandatory) {
|
||||
return "@RenderSection(\"" + sectionName + "\", " + mandatory + ")";
|
||||
}
|
||||
|
||||
function getAddSectionSnippet(sectionName) {
|
||||
return "@section " + sectionName + "\r\n{\r\n\r\n\t{0}\r\n\r\n}\r\n";
|
||||
}
|
||||
|
||||
////////////
|
||||
|
||||
var service = {
|
||||
getInsertDictionarySnippet: getInsertDictionarySnippet,
|
||||
getInsertPartialSnippet: getInsertPartialSnippet,
|
||||
getQuerySnippet: getQuerySnippet,
|
||||
getRenderBodySnippet: getRenderBodySnippet,
|
||||
getRenderSectionSnippet: getRenderSectionSnippet,
|
||||
getAddSectionSnippet: getAddSectionSnippet
|
||||
};
|
||||
|
||||
return service;
|
||||
|
||||
}
|
||||
|
||||
angular.module('umbraco.services').factory('templateHelper', templateHelperService);
|
||||
|
||||
|
||||
})();
|
||||
@@ -1,61 +1,46 @@
|
||||
<div ng-controller="Umbraco.Overlays.InsertOverlay as vm">
|
||||
|
||||
<div class="umb-insert-code-boxes">
|
||||
|
||||
<div class="umb-insert-code-box" ng-click="vm.openPageFieldOverlay()">
|
||||
<div ng-if="model.allowedTypes.umbracoField" class="umb-insert-code-box" ng-click="vm.openPageFieldOverlay()">
|
||||
<div class="umb-insert-code-box__title"><localize key="template_insertPageField" /></div>
|
||||
<div class="umb-insert-code-box__description"><localize key="template_insertPageFieldDesc" /></div>
|
||||
</div>
|
||||
|
||||
<div class="umb-insert-code-box" ng-click="vm.openPartialOverlay()">
|
||||
<div ng-if="model.allowedTypes.partial" class="umb-insert-code-box" ng-click="vm.openPartialOverlay()">
|
||||
<div class="umb-insert-code-box__title"><localize key="template_insertPartialView" /></div>
|
||||
<div class="umb-insert-code-box__description">
|
||||
<localize key="template_insertPartialViewDesc" />
|
||||
<localize key="template_insertPartialViewDesc" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="umb-insert-code-box" ng-click="vm.openMacroPicker()">
|
||||
<div ng-if="model.allowedTypes.macro" class="umb-insert-code-box" ng-click="vm.openMacroPicker()">
|
||||
<div class="umb-insert-code-box__title"><localize key="template_insertMacro" /></div>
|
||||
<div class="umb-insert-code-box__description">
|
||||
<localize key="template_insertMacroDesc" />
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="umb-insert-code-box" ng-click="vm.openDictionaryItemOverlay()">
|
||||
<div ng-if="model.allowedTypes.dictionary" class="umb-insert-code-box" ng-click="vm.openDictionaryItemOverlay()">
|
||||
<div class="umb-insert-code-box__title"><localize key="template_insertDictionaryItem" /></div>
|
||||
<div class="umb-insert-code-box__description"><localize key="template_insertDictionaryItemDesc" /></div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<umb-overlay
|
||||
ng-if="vm.macroPickerOverlay.show"
|
||||
model="vm.macroPickerOverlay"
|
||||
view="vm.macroPickerOverlay.view"
|
||||
position="right">
|
||||
</umb-overlay>
|
||||
|
||||
<umb-overlay
|
||||
ng-if="vm.pageFieldOverlay.show"
|
||||
model="vm.pageFieldOverlay"
|
||||
position="right"
|
||||
view="vm.pageFieldOverlay.view">
|
||||
</umb-overlay>
|
||||
|
||||
<umb-overlay
|
||||
ng-if="vm.dictionaryItemOverlay.show"
|
||||
model="vm.dictionaryItemOverlay"
|
||||
position="right"
|
||||
view="vm.dictionaryItemOverlay.view">
|
||||
</umb-overlay>
|
||||
|
||||
<umb-overlay
|
||||
ng-if="vm.partialItemOverlay.show"
|
||||
model="vm.partialItemOverlay"
|
||||
view="vm.partialItemOverlay.view"
|
||||
position="right">
|
||||
</umb-overlay>
|
||||
|
||||
<umb-overlay ng-if="vm.macroPickerOverlay.show"
|
||||
model="vm.macroPickerOverlay"
|
||||
view="vm.macroPickerOverlay.view"
|
||||
position="right">
|
||||
</umb-overlay>
|
||||
<umb-overlay ng-if="vm.pageFieldOverlay.show"
|
||||
model="vm.pageFieldOverlay"
|
||||
position="right"
|
||||
view="vm.pageFieldOverlay.view">
|
||||
</umb-overlay>
|
||||
<umb-overlay ng-if="vm.dictionaryItemOverlay.show"
|
||||
model="vm.dictionaryItemOverlay"
|
||||
position="right"
|
||||
view="vm.dictionaryItemOverlay.view">
|
||||
</umb-overlay>
|
||||
<umb-overlay ng-if="vm.partialItemOverlay.show"
|
||||
model="vm.partialItemOverlay"
|
||||
view="vm.partialItemOverlay.view"
|
||||
position="right">
|
||||
</umb-overlay>
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/**
|
||||
* @ngdoc controller
|
||||
* @name Umbraco.Editors.DocumentType.DeleteController
|
||||
* @name Umbraco.Editors.MemberTypes.DeleteController
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* The controller for deleting content
|
||||
* The controller for deleting member types
|
||||
*/
|
||||
function MemberTypesDeleteController($scope, memberTypeResource, treeService, navigationService) {
|
||||
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @ngdoc controller
|
||||
* @name Umbraco.Editors.PartialViewMacros.DeleteController
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* The controller for deleting partial view macros
|
||||
*/
|
||||
function PartialViewMacrosDeleteController($scope, codefileResource, treeService, navigationService) {
|
||||
|
||||
$scope.performDelete = function() {
|
||||
|
||||
//mark it for deletion (used in the UI)
|
||||
$scope.currentNode.loading = true;
|
||||
|
||||
var virtualPath = $scope.currentNode.parentId + $scope.currentNode.name;
|
||||
|
||||
codefileResource.deleteByPath('partialViewMacros', virtualPath)
|
||||
.then(function() {
|
||||
$scope.currentNode.loading = false;
|
||||
//get the root node before we remove it
|
||||
var rootNode = treeService.getTreeRoot($scope.currentNode);
|
||||
//TODO: Need to sync tree, etc...
|
||||
treeService.removeNode($scope.currentNode);
|
||||
navigationService.hideMenu();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.cancel = function() {
|
||||
navigationService.hideDialog();
|
||||
};
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.PartialViewMacros.DeleteController", PartialViewMacrosDeleteController);
|
||||
@@ -0,0 +1,12 @@
|
||||
<div class="umb-dialog umb-pane" ng-controller="Umbraco.Editors.PartialViewMacros.DeleteController">
|
||||
<div class="umb-dialog-body">
|
||||
|
||||
<p class="umb-abstract">
|
||||
<localize key="defaultdialogs_confirmdelete">Are you sure you want to delete</localize> <strong>{{currentNode.name}}</strong> ?
|
||||
</p>
|
||||
|
||||
<umb-confirm on-confirm="performDelete" on-cancel="cancel">
|
||||
</umb-confirm>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,314 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function partialViewMacrosEditController($scope, $routeParams, codefileResource, assetsService, notificationsService, editorState, navigationService, appState, macroService, angularHelper, $timeout, contentEditingHelper, localizationService, templateHelper) {
|
||||
|
||||
var vm = this;
|
||||
var localizeSaving = localizationService.localize("general_saving");
|
||||
|
||||
vm.page = {};
|
||||
vm.page.loading = true;
|
||||
vm.partialViewMacroFile = {};
|
||||
|
||||
//menu
|
||||
vm.page.menu = {};
|
||||
vm.page.menu.currentSection = appState.getSectionState("currentSection");
|
||||
vm.page.menu.currentNode = null;
|
||||
|
||||
// bind functions to view model
|
||||
vm.save = save;
|
||||
vm.openPageFieldOverlay = openPageFieldOverlay;
|
||||
vm.openDictionaryItemOverlay = openDictionaryItemOverlay;
|
||||
vm.openQueryBuilderOverlay = openQueryBuilderOverlay;
|
||||
vm.openMacroOverlay = openMacroOverlay;
|
||||
vm.openInsertOverlay = openInsertOverlay;
|
||||
|
||||
/* Functions bound to view model */
|
||||
|
||||
function save() {
|
||||
|
||||
vm.page.saveButtonState = "busy";
|
||||
vm.partialViewMacro.content = vm.editor.getValue();
|
||||
|
||||
contentEditingHelper.contentEditorPerformSave({
|
||||
statusMessage: localizeSaving,
|
||||
saveMethod: codefileResource.save,
|
||||
scope: $scope,
|
||||
content: vm.partialViewMacro,
|
||||
// We do not redirect on failure for partial view macros - this is because it is not possible to actually save the partial view
|
||||
// when server side validation fails - as opposed to content where we are capable of saving the content
|
||||
// item if server side validation fails
|
||||
redirectOnFailure: false,
|
||||
rebindCallback: function (orignal, saved) {}
|
||||
}).then(function (saved) {
|
||||
|
||||
localizationService.localize("speechBubbles_partialViewSavedHeader").then(function (headerValue) {
|
||||
localizationService.localize("speechBubbles_partialViewSavedText").then(function(msgValue) {
|
||||
notificationsService.success(headerValue, msgValue);
|
||||
});
|
||||
});
|
||||
|
||||
vm.page.saveButtonState = "success";
|
||||
vm.partialViewMacro = saved;
|
||||
|
||||
//sync state
|
||||
editorState.set(vm.partialViewMacro);
|
||||
|
||||
// normal tree sync
|
||||
navigationService.syncTree({ tree: "partialViewMacros", path: vm.partialViewMacro.path, forceReload: true }).then(function (syncArgs) {
|
||||
vm.page.menu.currentNode = syncArgs.node;
|
||||
});
|
||||
|
||||
// clear $dirty state on form
|
||||
setFormState("pristine");
|
||||
|
||||
}, function (err) {
|
||||
|
||||
vm.page.saveButtonState = "error";
|
||||
|
||||
localizationService.localize("speechBubbles_validationFailedHeader").then(function (headerValue) {
|
||||
localizationService.localize("speechBubbles_validationFailedMessage").then(function(msgValue) {
|
||||
notificationsService.error(headerValue, msgValue);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function openInsertOverlay() {
|
||||
|
||||
vm.insertOverlay = {
|
||||
view: "insert",
|
||||
allowedTypes: {
|
||||
macro: true,
|
||||
dictionary: true,
|
||||
umbracoField: true
|
||||
},
|
||||
hideSubmitButton: true,
|
||||
show: true,
|
||||
submit: function(model) {
|
||||
|
||||
switch(model.insert.type) {
|
||||
case "macro":
|
||||
var macroObject = macroService.collectValueData(model.insert.selectedMacro, model.insert.macroParams, "Mvc");
|
||||
insert(macroObject.syntax);
|
||||
break;
|
||||
|
||||
case "dictionary":
|
||||
var code = templateHelper.getInsertDictionarySnippet(model.insert.node.name);
|
||||
insert(code);
|
||||
break;
|
||||
|
||||
case "umbracoField":
|
||||
insert(model.insert.umbracoField);
|
||||
break;
|
||||
}
|
||||
|
||||
vm.insertOverlay.show = false;
|
||||
vm.insertOverlay = null;
|
||||
|
||||
},
|
||||
close: function(oldModel) {
|
||||
// close the dialog
|
||||
vm.insertOverlay.show = false;
|
||||
vm.insertOverlay = null;
|
||||
// focus editor
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
function openMacroOverlay() {
|
||||
|
||||
vm.macroPickerOverlay = {
|
||||
view: "macropicker",
|
||||
dialogData: {},
|
||||
show: true,
|
||||
title: "Insert macro",
|
||||
submit: function (model) {
|
||||
|
||||
var macroObject = macroService.collectValueData(model.selectedMacro, model.macroParams, "Mvc");
|
||||
insert(macroObject.syntax);
|
||||
|
||||
vm.macroPickerOverlay.show = false;
|
||||
vm.macroPickerOverlay = null;
|
||||
|
||||
},
|
||||
close: function(oldModel) {
|
||||
// close the dialog
|
||||
vm.macroPickerOverlay.show = false;
|
||||
vm.macroPickerOverlay = null;
|
||||
// focus editor
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function openPageFieldOverlay() {
|
||||
vm.pageFieldOverlay = {
|
||||
submitButtonLabel: "Insert",
|
||||
closeButtonlabel: "Cancel",
|
||||
view: "insertfield",
|
||||
show: true,
|
||||
submit: function (model) {
|
||||
insert(model.umbracoField);
|
||||
vm.pageFieldOverlay.show = false;
|
||||
vm.pageFieldOverlay = null;
|
||||
},
|
||||
close: function (model) {
|
||||
// close the dialog
|
||||
vm.pageFieldOverlay.show = false;
|
||||
vm.pageFieldOverlay = null;
|
||||
// focus editor
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function openDictionaryItemOverlay() {
|
||||
vm.dictionaryItemOverlay = {
|
||||
view: "treepicker",
|
||||
section: "settings",
|
||||
treeAlias: "dictionary",
|
||||
entityType: "dictionary",
|
||||
multiPicker: false,
|
||||
show: true,
|
||||
title: "Insert dictionary item",
|
||||
select: function(node){
|
||||
|
||||
var code = templateHelper.getInsertDictionarySnippet(node.name);
|
||||
insert(code);
|
||||
|
||||
vm.dictionaryItemOverlay.show = false;
|
||||
vm.dictionaryItemOverlay = null;
|
||||
},
|
||||
close: function (model) {
|
||||
// close dialog
|
||||
vm.dictionaryItemOverlay.show = false;
|
||||
vm.dictionaryItemOverlay = null;
|
||||
// focus editor
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function openQueryBuilderOverlay() {
|
||||
vm.queryBuilderOverlay = {
|
||||
view: "querybuilder",
|
||||
show: true,
|
||||
title: "Query for content",
|
||||
|
||||
submit: function (model) {
|
||||
|
||||
var code = templateHelper.getQuerySnippet(model.result.queryExpression);
|
||||
insert(code);
|
||||
|
||||
vm.queryBuilderOverlay.show = false;
|
||||
vm.queryBuilderOverlay = null;
|
||||
},
|
||||
|
||||
close: function (model) {
|
||||
// close dialog
|
||||
vm.queryBuilderOverlay.show = false;
|
||||
vm.queryBuilderOverlay = null;
|
||||
// focus editor
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/* Local functions */
|
||||
|
||||
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) {
|
||||
ready(partialViewMacro);
|
||||
});
|
||||
} else {
|
||||
codefileResource.getByPath('partialViewMacros', $routeParams.id).then(function (partialViewMacro) {
|
||||
ready(partialViewMacro);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function ready(partialViewMacro) {
|
||||
|
||||
vm.page.loading = false;
|
||||
vm.partialViewMacro = partialViewMacro;
|
||||
|
||||
//sync state
|
||||
editorState.set(vm.partialViewMacro);
|
||||
navigationService.syncTree({ tree: "partialViewMacros", path: vm.partialViewMacro.virtualPath, forceReload: true }).then(function (syncArgs) {
|
||||
vm.page.menu.currentNode = syncArgs.node;
|
||||
});
|
||||
|
||||
// ace configuration
|
||||
vm.aceOption = {
|
||||
mode: "razor",
|
||||
theme: "chrome",
|
||||
showPrintMargin: false,
|
||||
advanced: {
|
||||
fontSize: '14px'
|
||||
},
|
||||
onLoad: function(_editor) {
|
||||
vm.editor = _editor;
|
||||
|
||||
// initial cursor placement
|
||||
// Keep cursor in name field if we are create a new template
|
||||
// else set the cursor at the bottom of the code editor
|
||||
if(!$routeParams.create) {
|
||||
$timeout(function(){
|
||||
vm.editor.navigateFileEnd();
|
||||
vm.editor.focus();
|
||||
persistCurrentLocation();
|
||||
});
|
||||
}
|
||||
|
||||
//change on blur, focus
|
||||
vm.editor.on("blur", persistCurrentLocation);
|
||||
vm.editor.on("focus", persistCurrentLocation);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function insert(str) {
|
||||
vm.editor.moveCursorToPosition(vm.currentPosition);
|
||||
vm.editor.insert(str);
|
||||
vm.editor.focus();
|
||||
|
||||
// set form state to $dirty
|
||||
setFormState("dirty");
|
||||
}
|
||||
|
||||
function persistCurrentLocation() {
|
||||
vm.currentPosition = vm.editor.getCursorPosition();
|
||||
}
|
||||
|
||||
function setFormState(state) {
|
||||
|
||||
// get the current form
|
||||
var currentForm = angularHelper.getCurrentForm($scope);
|
||||
|
||||
// set state
|
||||
if(state === "dirty") {
|
||||
currentForm.$setDirty();
|
||||
} else if(state === "pristine") {
|
||||
currentForm.$setPristine();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
init();
|
||||
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.PartialViewMacros.EditController", partialViewMacrosEditController);
|
||||
})();
|
||||
@@ -0,0 +1,123 @@
|
||||
<div ng-controller="Umbraco.Editors.PartialViewMacros.EditController as vm">
|
||||
|
||||
<umb-load-indicator ng-if="vm.page.loading"></umb-load-indicator>
|
||||
|
||||
<form name="contentForm"
|
||||
ng-submit="vm.save()"
|
||||
novalidate
|
||||
val-form-manager>
|
||||
|
||||
<umb-editor-view ng-if="!vm.page.loading">
|
||||
|
||||
<umb-editor-header
|
||||
name="vm.partialViewMacro.name"
|
||||
hide-alias="true"
|
||||
description="vm.partialViewMacro.virtualPath"
|
||||
menu="vm.page.menu"
|
||||
description-locked="true"
|
||||
hide-icon="true">
|
||||
</umb-editor-header>
|
||||
|
||||
<umb-editor-container>
|
||||
|
||||
<div class="flex" style="margin-bottom: 30px;">
|
||||
|
||||
<div class="flex" style="margin-left: auto;">
|
||||
<div class="btn-group umb-era-button-group dropdown" style="margin-right: 10px;">
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="umb-era-button umb-button--s"
|
||||
ng-click="vm.openInsertOverlay()">
|
||||
<i class="icon icon-add"></i> Insert
|
||||
</button>
|
||||
|
||||
<a class="umb-era-button umb-button--s dropdown-toggle umb-button-group__toggle" data-toggle="dropdown">
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
|
||||
<ul aria-labelledby="dLabel" class="dropdown-menu bottom-up umb-button-group__sub-buttons" role="menu">
|
||||
<li><a href="" ng-click="vm.openPageFieldOverlay()">Value</a></li>
|
||||
<li><a href="" ng-click="vm.openMacroOverlay()">Macro</a></li>
|
||||
<li><a href="" ng-click="vm.openDictionaryItemOverlay()">Dictionary</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
style="margin-right: 10px;"
|
||||
class="umb-era-button umb-button--s"
|
||||
ng-click="vm.openQueryBuilderOverlay()">
|
||||
<i class="icon icon-wand"></i> Query builder
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div
|
||||
auto-scale="85"
|
||||
umb-ace-editor="vm.aceOption"
|
||||
model="vm.partialViewMacro.content">
|
||||
</div>
|
||||
|
||||
|
||||
</umb-editor-container>
|
||||
|
||||
<umb-editor-footer>
|
||||
|
||||
<umb-editor-footer-content-right>
|
||||
|
||||
<umb-button
|
||||
type="submit"
|
||||
button-style="success"
|
||||
state="vm.page.saveButtonState"
|
||||
shortcut="ctrl+s"
|
||||
label="Save"
|
||||
label-key="buttons_save">
|
||||
</umb-button>
|
||||
|
||||
</umb-editor-footer-content-right>
|
||||
|
||||
</umb-editor-footer>
|
||||
|
||||
</umb-editor-view>
|
||||
</form>
|
||||
|
||||
<umb-overlay
|
||||
ng-if="vm.insertOverlay.show"
|
||||
model="vm.insertOverlay"
|
||||
view="vm.insertOverlay.view"
|
||||
position="right">
|
||||
</umb-overlay>
|
||||
|
||||
<umb-overlay
|
||||
ng-if="vm.macroPickerOverlay.show"
|
||||
model="vm.macroPickerOverlay"
|
||||
view="vm.macroPickerOverlay.view"
|
||||
position="right">
|
||||
</umb-overlay>
|
||||
|
||||
<umb-overlay
|
||||
ng-if="vm.pageFieldOverlay.show"
|
||||
model="vm.pageFieldOverlay"
|
||||
position="right"
|
||||
view="vm.pageFieldOverlay.view">
|
||||
</umb-overlay>
|
||||
|
||||
<umb-overlay
|
||||
ng-if="vm.dictionaryItemOverlay.show"
|
||||
model="vm.dictionaryItemOverlay"
|
||||
position="right"
|
||||
view="vm.dictionaryItemOverlay.view">
|
||||
</umb-overlay>
|
||||
|
||||
<umb-overlay
|
||||
ng-if="vm.queryBuilderOverlay.show"
|
||||
model="vm.queryBuilderOverlay"
|
||||
position="right"
|
||||
view="vm.queryBuilderOverlay.view">
|
||||
</umb-overlay>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @ngdoc controller
|
||||
* @name Umbraco.Editors.PartialViews.DeleteController
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* The controller for deleting partial views
|
||||
*/
|
||||
function PartialViewsDeleteController($scope, codefileResource, treeService, navigationService) {
|
||||
|
||||
$scope.performDelete = function() {
|
||||
|
||||
//mark it for deletion (used in the UI)
|
||||
$scope.currentNode.loading = true;
|
||||
|
||||
var virtualPath = $scope.currentNode.parentId + $scope.currentNode.name;
|
||||
|
||||
codefileResource.deleteByPath('partialViews', virtualPath)
|
||||
.then(function() {
|
||||
$scope.currentNode.loading = false;
|
||||
//get the root node before we remove it
|
||||
var rootNode = treeService.getTreeRoot($scope.currentNode);
|
||||
//TODO: Need to sync tree, etc...
|
||||
treeService.removeNode($scope.currentNode);
|
||||
navigationService.hideMenu();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.cancel = function() {
|
||||
navigationService.hideDialog();
|
||||
};
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.PartialViews.DeleteController", PartialViewsDeleteController);
|
||||
@@ -0,0 +1,12 @@
|
||||
<div class="umb-dialog umb-pane" ng-controller="Umbraco.Editors.PartialViews.DeleteController">
|
||||
<div class="umb-dialog-body">
|
||||
|
||||
<p class="umb-abstract">
|
||||
<localize key="defaultdialogs_confirmdelete">Are you sure you want to delete</localize> <strong>{{currentNode.name}}</strong> ?
|
||||
</p>
|
||||
|
||||
<umb-confirm on-confirm="performDelete" on-cancel="cancel">
|
||||
</umb-confirm>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,314 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function PartialViewsEditController($scope, $routeParams, codefileResource, assetsService, notificationsService, editorState, navigationService, appState, macroService, angularHelper, $timeout, contentEditingHelper, localizationService, templateHelper) {
|
||||
|
||||
var vm = this;
|
||||
var localizeSaving = localizationService.localize("general_saving");
|
||||
|
||||
vm.page = {};
|
||||
vm.page.loading = true;
|
||||
vm.partialView = {};
|
||||
|
||||
//menu
|
||||
vm.page.menu = {};
|
||||
vm.page.menu.currentSection = appState.getSectionState("currentSection");
|
||||
vm.page.menu.currentNode = null;
|
||||
|
||||
// bind functions to view model
|
||||
vm.save = save;
|
||||
vm.openPageFieldOverlay = openPageFieldOverlay;
|
||||
vm.openDictionaryItemOverlay = openDictionaryItemOverlay;
|
||||
vm.openQueryBuilderOverlay = openQueryBuilderOverlay;
|
||||
vm.openMacroOverlay = openMacroOverlay;
|
||||
vm.openInsertOverlay = openInsertOverlay;
|
||||
|
||||
/* Functions bound to view model */
|
||||
|
||||
function save() {
|
||||
|
||||
vm.page.saveButtonState = "busy";
|
||||
vm.partialView.content = vm.editor.getValue();
|
||||
|
||||
contentEditingHelper.contentEditorPerformSave({
|
||||
statusMessage: localizeSaving,
|
||||
saveMethod: codefileResource.save,
|
||||
scope: $scope,
|
||||
content: vm.partialView,
|
||||
//We do not redirect on failure for partialviews - this is because it is not possible to actually save the partialviews
|
||||
// type when server side validation fails - as opposed to content where we are capable of saving the content
|
||||
// item if server side validation fails
|
||||
redirectOnFailure: false,
|
||||
rebindCallback: function (orignal, saved) {}
|
||||
}).then(function (saved) {
|
||||
|
||||
localizationService.localize("speechBubbles_partialViewSavedHeader").then(function (headerValue) {
|
||||
localizationService.localize("speechBubbles_partialViewSavedText").then(function(msgValue) {
|
||||
notificationsService.success(headerValue, msgValue);
|
||||
});
|
||||
});
|
||||
|
||||
vm.page.saveButtonState = "success";
|
||||
vm.partialView = saved;
|
||||
|
||||
//sync state
|
||||
editorState.set(vm.partialView);
|
||||
|
||||
// normal tree sync
|
||||
navigationService.syncTree({ tree: "partialViews", path: vm.partialView.path, forceReload: true }).then(function (syncArgs) {
|
||||
vm.page.menu.currentNode = syncArgs.node;
|
||||
});
|
||||
|
||||
// clear $dirty state on form
|
||||
setFormState("pristine");
|
||||
|
||||
}, function (err) {
|
||||
|
||||
vm.page.saveButtonState = "error";
|
||||
|
||||
localizationService.localize("speechBubbles_validationFailedHeader").then(function (headerValue) {
|
||||
localizationService.localize("speechBubbles_validationFailedMessage").then(function(msgValue) {
|
||||
notificationsService.error(headerValue, msgValue);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function openInsertOverlay() {
|
||||
|
||||
vm.insertOverlay = {
|
||||
view: "insert",
|
||||
allowedTypes: {
|
||||
macro: true,
|
||||
dictionary: true,
|
||||
umbracoField: true
|
||||
},
|
||||
hideSubmitButton: true,
|
||||
show: true,
|
||||
submit: function(model) {
|
||||
|
||||
switch(model.insert.type) {
|
||||
case "macro":
|
||||
var macroObject = macroService.collectValueData(model.insert.selectedMacro, model.insert.macroParams, "Mvc");
|
||||
insert(macroObject.syntax);
|
||||
break;
|
||||
|
||||
case "dictionary":
|
||||
var code = templateHelper.getInsertDictionarySnippet(model.insert.node.name);
|
||||
insert(code);
|
||||
break;
|
||||
|
||||
case "umbracoField":
|
||||
insert(model.insert.umbracoField);
|
||||
break;
|
||||
}
|
||||
|
||||
vm.insertOverlay.show = false;
|
||||
vm.insertOverlay = null;
|
||||
|
||||
},
|
||||
close: function(oldModel) {
|
||||
// close the dialog
|
||||
vm.insertOverlay.show = false;
|
||||
vm.insertOverlay = null;
|
||||
// focus editor
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
function openMacroOverlay() {
|
||||
|
||||
vm.macroPickerOverlay = {
|
||||
view: "macropicker",
|
||||
dialogData: {},
|
||||
show: true,
|
||||
title: "Insert macro",
|
||||
submit: function (model) {
|
||||
|
||||
var macroObject = macroService.collectValueData(model.selectedMacro, model.macroParams, "Mvc");
|
||||
insert(macroObject.syntax);
|
||||
|
||||
vm.macroPickerOverlay.show = false;
|
||||
vm.macroPickerOverlay = null;
|
||||
|
||||
},
|
||||
close: function(oldModel) {
|
||||
// close the dialog
|
||||
vm.macroPickerOverlay.show = false;
|
||||
vm.macroPickerOverlay = null;
|
||||
// focus editor
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function openPageFieldOverlay() {
|
||||
vm.pageFieldOverlay = {
|
||||
submitButtonLabel: "Insert",
|
||||
closeButtonlabel: "Cancel",
|
||||
view: "insertfield",
|
||||
show: true,
|
||||
submit: function (model) {
|
||||
insert(model.umbracoField);
|
||||
vm.pageFieldOverlay.show = false;
|
||||
vm.pageFieldOverlay = null;
|
||||
},
|
||||
close: function (model) {
|
||||
// close the dialog
|
||||
vm.pageFieldOverlay.show = false;
|
||||
vm.pageFieldOverlay = null;
|
||||
// focus editor
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function openDictionaryItemOverlay() {
|
||||
vm.dictionaryItemOverlay = {
|
||||
view: "treepicker",
|
||||
section: "settings",
|
||||
treeAlias: "dictionary",
|
||||
entityType: "dictionary",
|
||||
multiPicker: false,
|
||||
show: true,
|
||||
title: "Insert dictionary item",
|
||||
select: function(node){
|
||||
|
||||
var code = templateHelper.getInsertDictionarySnippet(node.name);
|
||||
insert(code);
|
||||
|
||||
vm.dictionaryItemOverlay.show = false;
|
||||
vm.dictionaryItemOverlay = null;
|
||||
},
|
||||
close: function (model) {
|
||||
// close dialog
|
||||
vm.dictionaryItemOverlay.show = false;
|
||||
vm.dictionaryItemOverlay = null;
|
||||
// focus editor
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function openQueryBuilderOverlay() {
|
||||
vm.queryBuilderOverlay = {
|
||||
view: "querybuilder",
|
||||
show: true,
|
||||
title: "Query for content",
|
||||
|
||||
submit: function (model) {
|
||||
|
||||
var code = templateHelper.getQuerySnippet(model.result.queryExpression);
|
||||
insert(code);
|
||||
|
||||
vm.queryBuilderOverlay.show = false;
|
||||
vm.queryBuilderOverlay = null;
|
||||
},
|
||||
|
||||
close: function (model) {
|
||||
// close dialog
|
||||
vm.queryBuilderOverlay.show = false;
|
||||
vm.queryBuilderOverlay = null;
|
||||
// focus editor
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/* Local functions */
|
||||
|
||||
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) {
|
||||
ready(partialView);
|
||||
});
|
||||
} else {
|
||||
codefileResource.getByPath('partialViews', $routeParams.id).then(function (partialView) {
|
||||
ready(partialView);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function ready(partialView) {
|
||||
|
||||
vm.page.loading = false;
|
||||
vm.partialView = partialView;
|
||||
|
||||
//sync state
|
||||
editorState.set(vm.partialView);
|
||||
navigationService.syncTree({ tree: "partialViews", path: vm.partialView.virtualPath, forceReload: true }).then(function (syncArgs) {
|
||||
vm.page.menu.currentNode = syncArgs.node;
|
||||
});
|
||||
|
||||
// ace configuration
|
||||
vm.aceOption = {
|
||||
mode: "razor",
|
||||
theme: "chrome",
|
||||
showPrintMargin: false,
|
||||
advanced: {
|
||||
fontSize: '14px'
|
||||
},
|
||||
onLoad: function(_editor) {
|
||||
vm.editor = _editor;
|
||||
|
||||
// initial cursor placement
|
||||
// Keep cursor in name field if we are create a new template
|
||||
// else set the cursor at the bottom of the code editor
|
||||
if(!$routeParams.create) {
|
||||
$timeout(function(){
|
||||
vm.editor.navigateFileEnd();
|
||||
vm.editor.focus();
|
||||
persistCurrentLocation();
|
||||
});
|
||||
}
|
||||
|
||||
//change on blur, focus
|
||||
vm.editor.on("blur", persistCurrentLocation);
|
||||
vm.editor.on("focus", persistCurrentLocation);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function insert(str) {
|
||||
vm.editor.moveCursorToPosition(vm.currentPosition);
|
||||
vm.editor.insert(str);
|
||||
vm.editor.focus();
|
||||
|
||||
// set form state to $dirty
|
||||
setFormState("dirty");
|
||||
}
|
||||
|
||||
function persistCurrentLocation() {
|
||||
vm.currentPosition = vm.editor.getCursorPosition();
|
||||
}
|
||||
|
||||
function setFormState(state) {
|
||||
|
||||
// get the current form
|
||||
var currentForm = angularHelper.getCurrentForm($scope);
|
||||
|
||||
// set state
|
||||
if(state === "dirty") {
|
||||
currentForm.$setDirty();
|
||||
} else if(state === "pristine") {
|
||||
currentForm.$setPristine();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
init();
|
||||
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.PartialViews.EditController", PartialViewsEditController);
|
||||
})();
|
||||
@@ -0,0 +1,123 @@
|
||||
<div ng-controller="Umbraco.Editors.PartialViews.EditController as vm">
|
||||
|
||||
<umb-load-indicator ng-if="vm.page.loading"></umb-load-indicator>
|
||||
|
||||
<form name="contentForm"
|
||||
ng-submit="vm.save()"
|
||||
novalidate
|
||||
val-form-manager>
|
||||
|
||||
<umb-editor-view ng-if="!vm.page.loading">
|
||||
|
||||
<umb-editor-header
|
||||
name="vm.partialView.name"
|
||||
hide-alias="true"
|
||||
description="vm.partialView.virtualPath"
|
||||
menu="vm.page.menu"
|
||||
description-locked="true"
|
||||
hide-icon="true">
|
||||
</umb-editor-header>
|
||||
|
||||
<umb-editor-container>
|
||||
|
||||
<div class="flex" style="margin-bottom: 30px;">
|
||||
|
||||
<div class="flex" style="margin-left: auto;">
|
||||
<div class="btn-group umb-era-button-group dropdown" style="margin-right: 10px;">
|
||||
|
||||
<button
|
||||
type="button"
|
||||
class="umb-era-button umb-button--s"
|
||||
ng-click="vm.openInsertOverlay()">
|
||||
<i class="icon icon-add"></i> Insert
|
||||
</button>
|
||||
|
||||
<a class="umb-era-button umb-button--s dropdown-toggle umb-button-group__toggle" data-toggle="dropdown">
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
|
||||
<ul aria-labelledby="dLabel" class="dropdown-menu bottom-up umb-button-group__sub-buttons" role="menu">
|
||||
<li><a href="" ng-click="vm.openPageFieldOverlay()">Value</a></li>
|
||||
<li><a href="" ng-click="vm.openMacroOverlay()">Macro</a></li>
|
||||
<li><a href="" ng-click="vm.openDictionaryItemOverlay()">Dictionary</a></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
style="margin-right: 10px;"
|
||||
class="umb-era-button umb-button--s"
|
||||
ng-click="vm.openQueryBuilderOverlay()">
|
||||
<i class="icon icon-wand"></i> Query builder
|
||||
</button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div
|
||||
auto-scale="85"
|
||||
umb-ace-editor="vm.aceOption"
|
||||
model="vm.partialView.content">
|
||||
</div>
|
||||
|
||||
|
||||
</umb-editor-container>
|
||||
|
||||
<umb-editor-footer>
|
||||
|
||||
<umb-editor-footer-content-right>
|
||||
|
||||
<umb-button
|
||||
type="submit"
|
||||
button-style="success"
|
||||
state="vm.page.saveButtonState"
|
||||
shortcut="ctrl+s"
|
||||
label="Save"
|
||||
label-key="buttons_save">
|
||||
</umb-button>
|
||||
|
||||
</umb-editor-footer-content-right>
|
||||
|
||||
</umb-editor-footer>
|
||||
|
||||
</umb-editor-view>
|
||||
</form>
|
||||
|
||||
<umb-overlay
|
||||
ng-if="vm.insertOverlay.show"
|
||||
model="vm.insertOverlay"
|
||||
view="vm.insertOverlay.view"
|
||||
position="right">
|
||||
</umb-overlay>
|
||||
|
||||
<umb-overlay
|
||||
ng-if="vm.macroPickerOverlay.show"
|
||||
model="vm.macroPickerOverlay"
|
||||
view="vm.macroPickerOverlay.view"
|
||||
position="right">
|
||||
</umb-overlay>
|
||||
|
||||
<umb-overlay
|
||||
ng-if="vm.pageFieldOverlay.show"
|
||||
model="vm.pageFieldOverlay"
|
||||
position="right"
|
||||
view="vm.pageFieldOverlay.view">
|
||||
</umb-overlay>
|
||||
|
||||
<umb-overlay
|
||||
ng-if="vm.dictionaryItemOverlay.show"
|
||||
model="vm.dictionaryItemOverlay"
|
||||
position="right"
|
||||
view="vm.dictionaryItemOverlay.view">
|
||||
</umb-overlay>
|
||||
|
||||
<umb-overlay
|
||||
ng-if="vm.queryBuilderOverlay.show"
|
||||
model="vm.queryBuilderOverlay"
|
||||
position="right"
|
||||
view="vm.queryBuilderOverlay.view">
|
||||
</umb-overlay>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* @ngdoc controller
|
||||
* @name Umbraco.Editors.Scripts.DeleteController
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* The controller for deleting scripts
|
||||
*/
|
||||
function ScriptsDeleteController($scope, codefileResource, treeService, navigationService) {
|
||||
|
||||
$scope.performDelete = function() {
|
||||
|
||||
//mark it for deletion (used in the UI)
|
||||
$scope.currentNode.loading = true;
|
||||
|
||||
var virtualPath = $scope.currentNode.parentId + $scope.currentNode.name;
|
||||
|
||||
codefileResource.deleteByPath('scripts', virtualPath)
|
||||
.then(function() {
|
||||
$scope.currentNode.loading = false;
|
||||
//get the root node before we remove it
|
||||
var rootNode = treeService.getTreeRoot($scope.currentNode);
|
||||
//TODO: Need to sync tree, etc...
|
||||
treeService.removeNode($scope.currentNode);
|
||||
navigationService.hideMenu();
|
||||
});
|
||||
};
|
||||
|
||||
$scope.cancel = function() {
|
||||
navigationService.hideDialog();
|
||||
};
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.Scripts.DeleteController", ScriptsDeleteController);
|
||||
@@ -0,0 +1,12 @@
|
||||
<div class="umb-dialog umb-pane" ng-controller="Umbraco.Editors.Scripts.DeleteController">
|
||||
<div class="umb-dialog-body">
|
||||
|
||||
<p class="umb-abstract">
|
||||
<localize key="defaultdialogs_confirmdelete">Are you sure you want to delete</localize> <strong>{{currentNode.name}}</strong> ?
|
||||
</p>
|
||||
|
||||
<umb-confirm on-confirm="performDelete" on-cancel="cancel">
|
||||
</umb-confirm>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,137 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function ScriptsEditController($scope, $routeParams, $timeout, appState, editorState, navigationService, assetsService, codefileResource, contentEditingHelper, notificationsService, localizationService) {
|
||||
|
||||
var vm = this;
|
||||
var currentPosition = null;
|
||||
var localizeSaving = localizationService.localize("general_saving");
|
||||
|
||||
vm.page = {};
|
||||
vm.page.loading = true;
|
||||
vm.page.menu = {};
|
||||
vm.page.menu.currentSection = appState.getSectionState("currentSection");
|
||||
vm.page.menu.currentNode = null;
|
||||
vm.page.saveButtonState = "init";
|
||||
|
||||
vm.script = {};
|
||||
|
||||
// bind functions to view model
|
||||
vm.save = save;
|
||||
|
||||
/* Function bound to view model */
|
||||
|
||||
function save() {
|
||||
|
||||
vm.page.saveButtonState = "busy";
|
||||
|
||||
vm.script.content = vm.editor.getValue();
|
||||
|
||||
contentEditingHelper.contentEditorPerformSave({
|
||||
statusMessage: localizeSaving,
|
||||
saveMethod: codefileResource.save,
|
||||
scope: $scope,
|
||||
content: vm.script,
|
||||
// We do not redirect on failure for scripts - this is because it is not possible to actually save the script
|
||||
// when server side validation fails - as opposed to content where we are capable of saving the content
|
||||
// item if server side validation fails
|
||||
redirectOnFailure: false,
|
||||
rebindCallback: function (orignal, saved) {}
|
||||
}).then(function (saved) {
|
||||
|
||||
localizationService.localize("speechBubbles_fileSavedHeader").then(function (headerValue) {
|
||||
localizationService.localize("speechBubbles_fileSavedText").then(function(msgValue) {
|
||||
notificationsService.success(headerValue, msgValue);
|
||||
});
|
||||
});
|
||||
|
||||
vm.page.saveButtonState = "success";
|
||||
vm.script = saved;
|
||||
|
||||
//sync state
|
||||
editorState.set(vm.script);
|
||||
|
||||
// sync tree
|
||||
navigationService.syncTree({ tree: "scripts", path: vm.script.virtualPath, forceReload: true }).then(function (syncArgs) {
|
||||
vm.page.menu.currentNode = syncArgs.node;
|
||||
});
|
||||
|
||||
}, function (err) {
|
||||
|
||||
vm.page.saveButtonState = "error";
|
||||
|
||||
localizationService.localize("speechBubbles_validationFailedHeader").then(function (headerValue) {
|
||||
localizationService.localize("speechBubbles_validationFailedMessage").then(function(msgValue) {
|
||||
notificationsService.error(headerValue, msgValue);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
/* Local functions */
|
||||
|
||||
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 (script) {
|
||||
ready(script);
|
||||
});
|
||||
} else {
|
||||
codefileResource.getByPath('scripts', $routeParams.id).then(function (script) {
|
||||
ready(script);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function ready(script) {
|
||||
|
||||
vm.page.loading = false;
|
||||
|
||||
vm.script = script;
|
||||
|
||||
//sync state
|
||||
editorState.set(vm.script);
|
||||
|
||||
navigationService.syncTree({ tree: "scripts", path: vm.script.virtualPath, forceReload: true }).then(function (syncArgs) {
|
||||
vm.page.menu.currentNode = syncArgs.node;
|
||||
});
|
||||
|
||||
vm.aceOption = {
|
||||
mode: "javascript",
|
||||
theme: "chrome",
|
||||
showPrintMargin: false,
|
||||
advanced: {
|
||||
fontSize: '14px'
|
||||
},
|
||||
onLoad: function(_editor) {
|
||||
|
||||
vm.editor = _editor;
|
||||
|
||||
// initial cursor placement
|
||||
// Keep cursor in name field if we are create a new script
|
||||
// else set the cursor at the bottom of the code editor
|
||||
if(!$routeParams.create) {
|
||||
$timeout(function(){
|
||||
vm.editor.navigateFileEnd();
|
||||
vm.editor.focus();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.Scripts.EditController", ScriptsEditController);
|
||||
})();
|
||||
@@ -0,0 +1,51 @@
|
||||
<div ng-controller="Umbraco.Editors.Scripts.EditController as vm">
|
||||
|
||||
<umb-load-indicator ng-if="vm.page.loading"></umb-load-indicator>
|
||||
|
||||
<form name="scriptsForm"
|
||||
ng-submit="vm.save()"
|
||||
novalidate
|
||||
val-form-manager>
|
||||
|
||||
<umb-editor-view ng-if="!vm.page.loading">
|
||||
|
||||
<umb-editor-header
|
||||
name="vm.script.name"
|
||||
hide-alias="true"
|
||||
description="vm.script.virtualPath"
|
||||
description-locked="true"
|
||||
menu="vm.page.menu"
|
||||
hide-icon="true">
|
||||
</umb-editor-header>
|
||||
|
||||
<umb-editor-container>
|
||||
|
||||
<div
|
||||
auto-scale="85"
|
||||
umb-ace-editor="vm.aceOption"
|
||||
model="vm.script.content">
|
||||
</div>
|
||||
|
||||
</umb-editor-container>
|
||||
|
||||
<umb-editor-footer>
|
||||
|
||||
<umb-editor-footer-content-right>
|
||||
|
||||
<umb-button
|
||||
type="submit"
|
||||
button-style="success"
|
||||
state="vm.page.saveButtonState"
|
||||
shortcut="ctrl+s"
|
||||
label="Save"
|
||||
label-key="buttons_save">
|
||||
</umb-button>
|
||||
|
||||
</umb-editor-footer-content-right>
|
||||
|
||||
</umb-editor-footer>
|
||||
|
||||
</umb-editor-view>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
@@ -1,7 +1,7 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function TemplatesEditController($scope, $routeParams, $timeout, templateResource, assetsService, notificationsService, editorState, navigationService, appState, macroService, treeService, contentEditingHelper, localizationService, angularHelper) {
|
||||
function TemplatesEditController($scope, $routeParams, $timeout, templateResource, assetsService, notificationsService, editorState, navigationService, appState, macroService, treeService, contentEditingHelper, localizationService, angularHelper, templateHelper) {
|
||||
|
||||
var vm = this;
|
||||
var oldMasterTemplateAlias = null;
|
||||
@@ -26,14 +26,20 @@
|
||||
saveMethod: templateResource.save,
|
||||
scope: $scope,
|
||||
content: vm.template,
|
||||
//We do not redirect on failure for templates - this is because it is not possible to actually save the doc
|
||||
//We do not redirect on failure for templates - this is because it is not possible to actually save the template
|
||||
// type when server side validation fails - as opposed to content where we are capable of saving the content
|
||||
// item if server side validation fails
|
||||
redirectOnFailure: false,
|
||||
rebindCallback: function (orignal, saved) {}
|
||||
}).then(function (saved) {
|
||||
|
||||
notificationsService.success("Template saved");
|
||||
localizationService.localize("speechBubbles_templateSavedHeader").then(function (headerValue) {
|
||||
localizationService.localize("speechBubbles_templateSavedText").then(function(msgValue) {
|
||||
notificationsService.success(headerValue, msgValue);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
vm.page.saveButtonState = "success";
|
||||
vm.template = saved;
|
||||
|
||||
@@ -169,27 +175,30 @@
|
||||
|
||||
vm.insertOverlay = {
|
||||
view: "insert",
|
||||
allowedTypes: {
|
||||
macro: true,
|
||||
dictionary: true,
|
||||
partial: true,
|
||||
umbracoField: true
|
||||
},
|
||||
hideSubmitButton: true,
|
||||
show: true,
|
||||
submit: function(model) {
|
||||
|
||||
switch(model.insert.type) {
|
||||
case "macro":
|
||||
|
||||
case "macro":
|
||||
var macroObject = macroService.collectValueData(model.insert.selectedMacro, model.insert.macroParams, "Mvc");
|
||||
insert(macroObject.syntax);
|
||||
break;
|
||||
|
||||
case "dictionary":
|
||||
//crappy hack due to dictionary items not in umbracoNode table
|
||||
var code = "@Umbraco.GetDictionaryValue(\"" + model.insert.node.name + "\")";
|
||||
var code = templateHelper.getInsertDictionarySnippet(model.insert.node.name);
|
||||
insert(code);
|
||||
break;
|
||||
|
||||
case "partial":
|
||||
//crappy hack due to dictionary items not in umbracoNode table
|
||||
var nodeNameWithPath = model.insert.node.id.replace(".cshtml", "");
|
||||
var code = "@Html.Partial(\"" + nodeNameWithPath + "\")";
|
||||
var code = templateHelper.getInsertPartialSnippet(model.insert.node.name);
|
||||
insert(code);
|
||||
break;
|
||||
|
||||
@@ -274,8 +283,7 @@
|
||||
show: true,
|
||||
title: localizationService.localize("template_insertDictionaryItem"),
|
||||
select: function(node){
|
||||
//crappy hack due to dictionary items not in umbracoNode table
|
||||
var code = "@Umbraco.GetDictionaryValue(\"" + node.name + "\")";
|
||||
var code = templateHelper.getInsertDictionarySnippet(node.name);
|
||||
insert(code);
|
||||
|
||||
vm.dictionaryItemOverlay.show = false;
|
||||
@@ -301,9 +309,8 @@
|
||||
show: true,
|
||||
title: localizationService.localize("template_insertPartialView"),
|
||||
select: function(node){
|
||||
//crappy hack due to dictionary items not in umbracoNode table
|
||||
var nodeNameWithPath = node.id.replace(".cshtml", "");
|
||||
var code = "@Html.Partial(\"" + nodeNameWithPath + "\")";
|
||||
|
||||
var code = templateHelper.getInsertPartialSnippet(node.name);
|
||||
insert(code);
|
||||
|
||||
vm.partialItemOverlay.show = false;
|
||||
@@ -324,18 +331,9 @@
|
||||
view: "querybuilder",
|
||||
show: true,
|
||||
title: localizationService.localize("template_queryBuilder"),
|
||||
|
||||
submit: function (model) {
|
||||
|
||||
var code = "\n@{\n" + "\tvar selection = " + model.result.queryExpression + ";\n}\n";
|
||||
code += "<ul>\n" +
|
||||
"\t@foreach(var item in selection){\n" +
|
||||
"\t\t<li>\n" +
|
||||
"\t\t\t<a href=\"@item.Url\">@item.Name</a>\n" +
|
||||
"\t\t</li>\n" +
|
||||
"\t}\n" +
|
||||
"</ul>\n\n";
|
||||
|
||||
var code = templateHelper.getQuerySnippet(model.result.queryExpression);
|
||||
insert(code);
|
||||
|
||||
vm.queryBuilderOverlay.show = false;
|
||||
@@ -363,15 +361,18 @@
|
||||
submit: function(model) {
|
||||
|
||||
if (model.insertType === 'renderBody') {
|
||||
insert("@RenderBody()");
|
||||
var code = templateHelper.getRenderBodySnippet();
|
||||
insert(code);
|
||||
}
|
||||
|
||||
if (model.insertType === 'renderSection') {
|
||||
insert("@RenderSection(\"" + model.renderSectionName + "\", " + model.mandatoryRenderSection + ")");
|
||||
var code = templateHelper.getRenderSectionSnippet(model.renderSectionName, model.mandatoryRenderSection);
|
||||
insert(code);
|
||||
}
|
||||
|
||||
if (model.insertType === 'addSection') {
|
||||
wrap("@section " + model.sectionName + "\r\n{\r\n\r\n\t{0}\r\n\r\n}\r\n");
|
||||
var code = templateHelper.getAddSectionSnippet(model.sectionName);
|
||||
wrap(code);
|
||||
}
|
||||
|
||||
vm.sectionsOverlay.show = false;
|
||||
|
||||
@@ -101,6 +101,13 @@
|
||||
$setPristine: function() {}
|
||||
}
|
||||
}
|
||||
},
|
||||
templateHelper: {
|
||||
getInsertDictionary: function() { return ""; },
|
||||
getInsertPartialSnippet: function() { return ""; },
|
||||
getQuerySnippet: function() { return ""; },
|
||||
getRenderBodySnippet: function() { return ""; },
|
||||
getRenderSectionSnippet: function() { return ""; }
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
describe('service: templateHelper', function () {
|
||||
|
||||
var templateHelper;
|
||||
|
||||
beforeEach(module("umbraco.services"));
|
||||
|
||||
beforeEach(inject(function ($injector) {
|
||||
templateHelper = $injector.get('templateHelper');
|
||||
}));
|
||||
|
||||
afterEach(inject(function ($rootScope) {
|
||||
$rootScope.$apply();
|
||||
}));
|
||||
|
||||
describe('getInsertDictionarySnippet', function () {
|
||||
|
||||
it('should return the snippet for inserting a dictionary item', function () {
|
||||
var snippet = '@Umbraco.GetDictionaryValue("nodeName")';
|
||||
expect(templateHelper.getInsertDictionarySnippet('nodeName')).toBe(snippet);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('getInsertPartialSnippet', function () {
|
||||
|
||||
it('should return the snippet for inserting a partial', function () {
|
||||
var snippet = '@Html.Partial("nodeName")';
|
||||
expect(templateHelper.getInsertPartialSnippet("nodeName")).toBe(snippet);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('getQuerySnippet', function () {
|
||||
|
||||
it('should return the snippet for a query', function () {
|
||||
var queryExpression = "queryExpression";
|
||||
var snippet = "\n@{\n" + "\tvar selection = " + queryExpression + ";\n}\n";
|
||||
snippet += "<ul>\n" +
|
||||
"\t@foreach(var item in selection){\n" +
|
||||
"\t\t<li>\n" +
|
||||
"\t\t\t<a href=\"@item.Url\">@item.Name</a>\n" +
|
||||
"\t\t</li>\n" +
|
||||
"\t}\n" +
|
||||
"</ul>\n\n";
|
||||
|
||||
expect(templateHelper.getQuerySnippet(queryExpression)).toBe(snippet);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('getRenderBodySnippet', function () {
|
||||
|
||||
it('should return the snippet for render body', function () {
|
||||
var snippet = '@RenderBody()';
|
||||
expect(templateHelper.getRenderBodySnippet()).toBe(snippet);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('getRenderSectionSnippet', function () {
|
||||
|
||||
it('should return the snippet for defining a section', function () {
|
||||
var snippet = '@RenderSection("sectionName", false)';
|
||||
expect(templateHelper.getRenderSectionSnippet("sectionName", false)).toBe(snippet);
|
||||
});
|
||||
|
||||
it('should return the snippet for defining a mandatory section', function () {
|
||||
var snippet = '@RenderSection("sectionName", true)';
|
||||
expect(templateHelper.getRenderSectionSnippet("sectionName", true)).toBe(snippet);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('getAddSectionSnippet', function () {
|
||||
|
||||
it('should return the snippet for implementing a section', function () {
|
||||
var sectionName = "sectionName";
|
||||
var snippet = "@section " + sectionName + "\r\n{\r\n\r\n\t{0}\r\n\r\n}\r\n";
|
||||
expect(templateHelper.getAddSectionSnippet(sectionName)).toEqual(snippet);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
@@ -563,13 +563,6 @@
|
||||
<Compile Include="Umbraco\Settings\Stylesheet\Property\EditStyleSheetProperty.aspx.designer.cs">
|
||||
<DependentUpon>EditStyleSheetProperty.aspx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Umbraco\Settings\Views\EditView.aspx.cs">
|
||||
<DependentUpon>EditView.aspx</DependentUpon>
|
||||
<SubType>ASPXCodeBehind</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Umbraco\Settings\Views\EditView.aspx.designer.cs">
|
||||
<DependentUpon>EditView.aspx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Umbraco\TreeInit.aspx.cs">
|
||||
<DependentUpon>treeInit.aspx</DependentUpon>
|
||||
<SubType>ASPXCodeBehind</SubType>
|
||||
@@ -752,7 +745,6 @@
|
||||
<Content Include="Umbraco\Images\thumbs_med.png" />
|
||||
<Content Include="Umbraco\Images\thumbs_smll.png" />
|
||||
<Content Include="Umbraco\Images\Umbraco\settingView.gif" />
|
||||
<Content Include="Umbraco\Settings\Views\EditView.aspx" />
|
||||
<Content Include="Umbraco_Client\Application\Extensions.js" />
|
||||
<Content Include="Umbraco_Client\Application\JQuery\jquery.validate.min.js" />
|
||||
<Content Include="Umbraco_Client\Application\JQuery\jquery.validate.unobtrusive.min.js" />
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
<!--Settings-->
|
||||
<add initialize="true" sortOrder="0" alias="documentTypes" application="settings" title="Document Types" iconClosed="icon-folder" iconOpen="icon-folder-open" type="Umbraco.Web.Trees.ContentTypeTreeController, umbraco" />
|
||||
<add application="settings" alias="templates" title="Templates" iconClosed="icon-folder" iconOpen="icon-folder-open" type="Umbraco.Web.Trees.TemplatesTreeController, umbraco" initialize="true" sortOrder="1" />
|
||||
<add application="settings" alias="partialViews" title="Partial Views" silent="false" initialize="true" iconClosed="icon-folder" iconOpen="icon-folder" type="Umbraco.Web.Trees.PartialViewsTree, umbraco" sortOrder="2" />
|
||||
<add application="settings" alias="partialViews" title="Partial Views" silent="false" initialize="true" iconClosed="icon-folder" iconOpen="icon-folder" type="Umbraco.Web.Trees.PartialViewsTreeController, umbraco" sortOrder="2" />
|
||||
<add application="settings" alias="stylesheets" title="Stylesheets" type="umbraco.loadStylesheets, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="3" />
|
||||
<add application="settings" alias="stylesheetProperty" title="Stylesheet Property" type="umbraco.loadStylesheetProperty, umbraco" iconClosed="" iconOpen="" initialize="false" sortOrder="0" />
|
||||
<add application="settings" alias="scripts" title="Scripts" type="umbraco.loadScripts, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="4" />
|
||||
<add application="settings" alias="scripts" title="Scripts" type="Umbraco.Web.Trees.ScriptTreeController, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="4" />
|
||||
<add application="settings" alias="languages" title="Languages" iconClosed="icon-folder" iconOpen="icon-folder-open" type="Umbraco.Web.Trees.LanguageTreeController, umbraco" sortOrder="5" />
|
||||
<add application="settings" alias="dictionary" title="Dictionary" type="umbraco.loadDictionary, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="6" />
|
||||
<add initialize="true" sortOrder="7" alias="mediaTypes" application="settings" title="Media Types" iconClosed="icon-folder" iconOpen="icon-folder-open" type="Umbraco.Web.Trees.MediaTypeTreeController, umbraco" />
|
||||
@@ -22,7 +22,7 @@
|
||||
<add application="developer" alias="macros" title="Macros" type="umbraco.loadMacros, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="2" />
|
||||
<add application="developer" alias="relationTypes" title="Relation Types" type="umbraco.loadRelationTypes, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="4" />
|
||||
<add application="developer" alias="xslt" title="XSLT Files" type="umbraco.loadXslt, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="5" />
|
||||
<add application="developer" alias="partialViewMacros" type="Umbraco.Web.Trees.PartialViewMacrosTree, umbraco" silent="false" initialize="true" sortOrder="6" title="Partial View Macro Files" iconClosed="icon-folder" iconOpen="icon-folder" />
|
||||
<add application="developer" alias="partialViewMacros" type="Umbraco.Web.Trees.PartialViewMacrosTreeController, umbraco" silent="false" initialize="true" sortOrder="6" title="Partial View Macro Files" iconClosed="icon-folder" iconOpen="icon-folder" />
|
||||
<!--Users-->
|
||||
<add application="users" alias="users" title="Users" type="umbraco.loadUsers, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="0" />
|
||||
<add application="users" alias="userTypes" title="User Types" type="umbraco.cms.presentation.Trees.UserTypes, umbraco" iconClosed="icon-folder" iconOpen="icon-folder" sortOrder="1" />
|
||||
@@ -41,5 +41,4 @@
|
||||
<add initialize="true" sortOrder="0" alias="form" application="forms" title="Forms" iconClosed="icon-folder" iconOpen="icon-folder-open" type="Umbraco.Forms.Web.Trees.FormTreeController, Umbraco.Forms.Web" />
|
||||
<add initialize="true" sortOrder="3" alias="prevaluesource" application="forms" title="Prevalue sources" iconClosed="icon-folder" iconOpen="icon-folder-open" type="Umbraco.Forms.Web.Trees.PreValueSourceTreeController, Umbraco.Forms.Web" />
|
||||
<add initialize="true" sortOrder="3" alias="formsecurity" application="users" title="Forms Security" iconClosed="icon-folder" iconOpen="icon-folder-open" type="Umbraco.Forms.Web.Trees.FormSecurityTreeController, Umbraco.Forms.Web" />
|
||||
|
||||
</trees>
|
||||
@@ -1,88 +0,0 @@
|
||||
<%@ Page Language="C#" MasterPageFile="../../masterpages/umbracoPage.Master" AutoEventWireup="True"
|
||||
CodeBehind="EditView.aspx.cs" Inherits="Umbraco.Web.UI.Umbraco.Settings.Views.EditView"
|
||||
ValidateRequest="False" %>
|
||||
|
||||
<%@ OutputCache Location="None" %>
|
||||
|
||||
<%@ Import Namespace="Umbraco.Core" %>
|
||||
<%@ Import Namespace="Umbraco.Core.IO" %>
|
||||
<%@ Import Namespace="Umbraco.Web" %>
|
||||
<%@ Register TagPrefix="cc1" Namespace="umbraco.uicontrols" Assembly="controls" %>
|
||||
<%@ Register TagPrefix="umb" Namespace="ClientDependency.Core.Controls" Assembly="ClientDependency.Core" %>
|
||||
|
||||
<asp:Content ID="DocTypeContent" ContentPlaceHolderID="DocType" runat="server">
|
||||
<!DOCTYPE html>
|
||||
</asp:Content>
|
||||
|
||||
<asp:Content ContentPlaceHolderID="head" runat="server">
|
||||
|
||||
<umb:JsInclude ID="JsInclude1" runat="server" FilePath="Editors/EditView.js" PathNameAlias="UmbracoClient" />
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
//we need to have this as a global object since we reference this object with callbacks.
|
||||
var editViewEditor;
|
||||
|
||||
(function ($) {
|
||||
$(document).ready(function () {
|
||||
//create and assign a new EditView object
|
||||
editViewEditor = new Umbraco.Editors.EditView({
|
||||
treeSyncPath: "<%=TemplateTreeSyncPath%>",
|
||||
currentTreeType: "<%=CurrentTreeType%>",
|
||||
editorType: "<%= EditorType.ToString() %>",
|
||||
originalFileName: "<%=OriginalFileName %>",
|
||||
restServiceLocation: "<%= Url.GetSaveFileServicePath() %>",
|
||||
masterPageDropDown: $("#<%= MasterTemplate.ClientID %>"),
|
||||
nameTxtBox: $("#<%= NameTxt.ClientID %>"),
|
||||
aliasTxtBox: $("#<%= AliasTxt.ClientID %>"),
|
||||
saveButton: $("#<%= ((Control)SaveButton).ClientID %>"),
|
||||
templateId: '<%= Request.CleanForXss("templateID") %>',
|
||||
codeEditorElementId: '<%= editorSource.ClientID %>',
|
||||
modalUrl: "<%= IOHelper.ResolveUrl(SystemDirectories.Umbraco) %>/dialogs/editMacro.aspx"
|
||||
});
|
||||
|
||||
//initialize it.
|
||||
editViewEditor.init();
|
||||
|
||||
//bind save shortcut
|
||||
UmbClientMgr.appActions().bindSaveShortCut();
|
||||
});
|
||||
})(jQuery);
|
||||
|
||||
</script>
|
||||
|
||||
</asp:Content>
|
||||
|
||||
|
||||
<asp:Content ContentPlaceHolderID="body" runat="server">
|
||||
|
||||
<cc1:TabView ID="Panel1" runat="server" hasMenu="true">
|
||||
|
||||
<cc1:Pane ID="Pane8" runat="server" >
|
||||
<cc1:PropertyPanel ID="pp_source" runat="server">
|
||||
<cc1:CodeArea ID="editorSource" runat="server" CodeBase="Razor" ClientSaveMethod="doSubmit" AutoResize="false" />
|
||||
</cc1:PropertyPanel>
|
||||
</cc1:Pane>
|
||||
|
||||
<cc1:Pane ID="Pane7" runat="server" >
|
||||
|
||||
<cc1:PropertyPanel ID="pp_name" runat="server">
|
||||
<asp:Literal runat="server" ID="PathPrefix"></asp:Literal>
|
||||
<asp:TextBox ID="NameTxt" runat="server"></asp:TextBox>
|
||||
</cc1:PropertyPanel>
|
||||
|
||||
<cc1:PropertyPanel ID="pp_alias" runat="server">
|
||||
<asp:TextBox ID="AliasTxt" runat="server"></asp:TextBox>
|
||||
</cc1:PropertyPanel>
|
||||
|
||||
<cc1:PropertyPanel ID="pp_masterTemplate" runat="server">
|
||||
<asp:DropDownList ID="MasterTemplate" runat="server" />
|
||||
</cc1:PropertyPanel>
|
||||
|
||||
|
||||
</cc1:Pane>
|
||||
|
||||
|
||||
</cc1:TabView>
|
||||
|
||||
</asp:Content>
|
||||
@@ -1,280 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.UI;
|
||||
using System.Web.UI.WebControls;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Web.Trees;
|
||||
using Umbraco.Web.UI.Controls;
|
||||
using umbraco;
|
||||
using umbraco.BasePages;
|
||||
using umbraco.cms.businesslogic.template;
|
||||
using umbraco.cms.helpers;
|
||||
using umbraco.cms.presentation.Trees;
|
||||
using Umbraco.Core;
|
||||
using umbraco.uicontrols;
|
||||
|
||||
namespace Umbraco.Web.UI.Umbraco.Settings.Views
|
||||
{
|
||||
public partial class EditView : global::umbraco.BasePages.UmbracoEnsuredPage
|
||||
{
|
||||
private Template _template;
|
||||
public MenuButton SaveButton;
|
||||
|
||||
public EditView()
|
||||
{
|
||||
CurrentApp = global::umbraco.BusinessLogic.DefaultApps.settings.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The type of MVC/Umbraco view the editor is editing
|
||||
/// </summary>
|
||||
public enum ViewEditorType
|
||||
{
|
||||
Template,
|
||||
PartialView,
|
||||
PartialViewMacro
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the type of view being edited
|
||||
/// </summary>
|
||||
protected ViewEditorType EditorType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_template != null) return ViewEditorType.Template;
|
||||
if (Request.QueryString["treeType"].IsNullOrWhiteSpace() == false && Request.QueryString["treeType"].InvariantEquals("partialViewMacros")) return ViewEditorType.PartialViewMacro;
|
||||
return ViewEditorType.PartialView;
|
||||
}
|
||||
}
|
||||
|
||||
protected string TemplateTreeSyncPath { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// This view is shared between different trees so we'll look for the query string
|
||||
/// </summary>
|
||||
protected string CurrentTreeType
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Request.QueryString["treeType"].IsNullOrWhiteSpace())
|
||||
{
|
||||
return TreeDefinitionCollection.Instance.FindTree<PartialViewsTree>().Tree.Alias;
|
||||
}
|
||||
return Request.CleanForXss("treeType");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the original file name that the editor was loaded with
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// this is used for editing a partial view
|
||||
/// </remarks>
|
||||
protected string OriginalFileName { get; private set; }
|
||||
|
||||
protected override void OnLoad(EventArgs e)
|
||||
{
|
||||
base.OnLoad(e);
|
||||
|
||||
if (!IsPostBack)
|
||||
{
|
||||
|
||||
//configure screen for editing a template
|
||||
if (_template != null)
|
||||
{
|
||||
MasterTemplate.Items.Add(new ListItem(ui.Text("none"), "0"));
|
||||
var selectedTemplate = string.Empty;
|
||||
|
||||
foreach (var t in Template.GetAllAsList())
|
||||
{
|
||||
if (t.Id == _template.Id) continue;
|
||||
|
||||
var li = new ListItem(t.Text, t.Id.ToString(CultureInfo.InvariantCulture));
|
||||
li.Attributes.Add("id", t.Alias.Replace(" ", "") + ".cshtml");
|
||||
MasterTemplate.Items.Add(li);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (_template.MasterTemplate > 0)
|
||||
MasterTemplate.SelectedValue = _template.MasterTemplate.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.Error<EditView>("An error occurred setting a master template id", ex);
|
||||
}
|
||||
|
||||
MasterTemplate.SelectedValue = selectedTemplate;
|
||||
NameTxt.Text = _template.GetRawText();
|
||||
AliasTxt.Text = _template.Alias;
|
||||
editorSource.Text = _template.Design;
|
||||
PathPrefix.Visible = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
//configure editor for editing a file....
|
||||
|
||||
NameTxt.Text = OriginalFileName;
|
||||
var svce = ApplicationContext.Current.Services.FileService;
|
||||
var file = EditorType == ViewEditorType.PartialView
|
||||
? svce.GetPartialView(OriginalFileName)
|
||||
: svce.GetPartialViewMacro(OriginalFileName);
|
||||
editorSource.Text = file.Content;
|
||||
|
||||
const string prefixFormat = "<span style=\"display: inline-block; height: 20px; line-height: 20px; margin-bottom: 0px; padding: 4px 6px;\">{0}</span>";
|
||||
PathPrefix.Text = string.Format(prefixFormat, EditorType == ViewEditorType.PartialView
|
||||
? "Partials/"
|
||||
: "MacroPartials/");
|
||||
}
|
||||
}
|
||||
|
||||
ClientTools
|
||||
.SetActiveTreeType(CurrentTreeType)
|
||||
.SyncTree(TemplateTreeSyncPath, false);
|
||||
}
|
||||
|
||||
|
||||
protected override void OnInit(EventArgs e)
|
||||
{
|
||||
base.OnInit(e);
|
||||
|
||||
//check if a templateId is assigned, meaning we are editing a template
|
||||
if (!Request.QueryString["templateID"].IsNullOrWhiteSpace())
|
||||
{
|
||||
_template = new Template(int.Parse(Request.QueryString["templateID"]));
|
||||
TemplateTreeSyncPath = "-1,init," + _template.Path.Replace("-1,", "");
|
||||
}
|
||||
else if (!Request.QueryString["file"].IsNullOrWhiteSpace())
|
||||
{
|
||||
//we are editing a view (i.e. partial view)
|
||||
OriginalFileName = HttpUtility.UrlDecode(Request.QueryString["file"]);
|
||||
|
||||
//TemplateTreeSyncPath = "-1,init," + Path.GetFileName(OriginalFileName);
|
||||
|
||||
TemplateTreeSyncPath = DeepLink.GetTreePathFromFilePath(OriginalFileName.TrimStart("MacroPartials/").TrimStart("Partials/"));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException("Cannot render the editor without a supplied templateId or a file");
|
||||
}
|
||||
|
||||
Panel1.hasMenu = true;
|
||||
var editor = Panel1.NewTabPage(ui.Text("template"));
|
||||
editor.Controls.Add(Pane8);
|
||||
|
||||
var props = Panel1.NewTabPage(ui.Text("properties"));
|
||||
props.Controls.Add(Pane7);
|
||||
|
||||
|
||||
SaveButton = Panel1.Menu.NewButton();
|
||||
SaveButton.Text = ui.Text("save");
|
||||
SaveButton.ButtonType = MenuButtonType.Primary;
|
||||
SaveButton.ID = "save";
|
||||
SaveButton.CssClass = "client-side";
|
||||
|
||||
Panel1.Text = ui.Text("edittemplate");
|
||||
pp_name.Text = ui.Text("name", base.getUser());
|
||||
pp_alias.Text = ui.Text("alias", base.getUser());
|
||||
pp_masterTemplate.Text = ui.Text("mastertemplate", base.getUser());
|
||||
|
||||
// Editing buttons
|
||||
MenuIconI umbField = editorSource.Menu.NewIcon();
|
||||
umbField.ImageURL = UmbracoPath + "/images/editor/insField.gif";
|
||||
umbField.OnClickCommand =
|
||||
ClientTools.Scripts.OpenModalWindow(
|
||||
IOHelper.ResolveUrl(SystemDirectories.Umbraco) + "/dialogs/umbracoField.aspx?objectId=" +
|
||||
editorSource.ClientID + "&tagName=UMBRACOGETDATA&mvcView=true", ui.Text("template", "insertPageField"), 640, 550);
|
||||
umbField.AltText = ui.Text("template", "insertPageField");
|
||||
|
||||
|
||||
// TODO: Update icon
|
||||
MenuIconI umbDictionary = editorSource.Menu.NewIcon();
|
||||
umbDictionary.ImageURL = GlobalSettings.Path + "/images/editor/dictionaryItem.gif";
|
||||
umbDictionary.OnClickCommand =
|
||||
ClientTools.Scripts.OpenModalWindow(
|
||||
IOHelper.ResolveUrl(SystemDirectories.Umbraco) + "/dialogs/umbracoField.aspx?objectId=" +
|
||||
editorSource.ClientID + "&tagName=UMBRACOGETDICTIONARY&mvcView=true", ui.Text("template", "insertDictionaryItem"),
|
||||
640, 550);
|
||||
umbDictionary.AltText = "Insert umbraco dictionary item";
|
||||
|
||||
var macroSplitButton = new InsertMacroSplitButton
|
||||
{
|
||||
ClientCallbackInsertMacroMarkup = "function(alias) {editViewEditor.insertMacroMarkup(alias);}",
|
||||
ClientCallbackOpenMacroModel = "function(alias) {editViewEditor.openMacroModal(alias);}"
|
||||
};
|
||||
editorSource.Menu.InsertNewControl(macroSplitButton, 40);
|
||||
|
||||
MenuIconI umbTemplateQueryBuilder = editorSource.Menu.NewIcon();
|
||||
umbTemplateQueryBuilder.ImageURL = UmbracoPath + "/images/editor/inshtml.gif";
|
||||
umbTemplateQueryBuilder.OnClickCommand = "editViewEditor.openQueryModal()";
|
||||
umbTemplateQueryBuilder.AltText = "Open query builder";
|
||||
|
||||
if (_template == null)
|
||||
{
|
||||
InitializeEditorForPartialView();
|
||||
}
|
||||
else
|
||||
{
|
||||
InitializeEditorForTemplate();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected override void OnPreRender(EventArgs e)
|
||||
{
|
||||
base.OnPreRender(e);
|
||||
ScriptManager.GetCurrent(Page).Services.Add(new ServiceReference("../webservices/codeEditorSave.asmx"));
|
||||
ScriptManager.GetCurrent(Page).Services.Add(new ServiceReference("../webservices/legacyAjaxCalls.asmx"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configure the editor for partial view editing
|
||||
/// </summary>
|
||||
private void InitializeEditorForPartialView()
|
||||
{
|
||||
pp_masterTemplate.Visible = false;
|
||||
pp_alias.Visible = false;
|
||||
pp_name.Text = "Filename";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configure the editor for editing a template
|
||||
/// </summary>
|
||||
private void InitializeEditorForTemplate()
|
||||
{
|
||||
|
||||
//TODO: implement content placeholders, etc... just like we had in v5
|
||||
|
||||
editorSource.Menu.InsertSplitter();
|
||||
|
||||
MenuIconI umbRenderBody = editorSource.Menu.NewIcon();
|
||||
umbRenderBody.ImageURL = UmbracoPath + "/images/editor/renderbody.gif";
|
||||
//umbContainer.AltText = ui.Text("template", "insertContentAreaPlaceHolder");
|
||||
umbRenderBody.AltText = "Insert @RenderBody()";
|
||||
|
||||
umbRenderBody.OnClickCommand = "editViewEditor.insertRenderBody()";
|
||||
|
||||
MenuIconI umbSection = editorSource.Menu.NewIcon();
|
||||
umbSection.ImageURL = UmbracoPath + "/images/editor/masterpagePlaceHolder.gif";
|
||||
//umbContainer.AltText = ui.Text("template", "insertContentAreaPlaceHolder");
|
||||
umbSection.AltText = "Insert Section";
|
||||
|
||||
umbSection.OnClickCommand = "editViewEditor.openSnippetModal('section')";
|
||||
|
||||
MenuIconI umbRenderSection = editorSource.Menu.NewIcon();
|
||||
umbRenderSection.ImageURL = UmbracoPath + "/images/editor/masterpageContent.gif";
|
||||
//umbContainer.AltText = ui.Text("template", "insertContentAreaPlaceHolder");
|
||||
umbRenderSection.AltText = "Insert @RenderSection";
|
||||
|
||||
umbRenderSection.OnClickCommand = "editViewEditor.openSnippetModal('rendersection')";
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <auto-generated>
|
||||
// This code was generated by a tool.
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </auto-generated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
namespace Umbraco.Web.UI.Umbraco.Settings.Views {
|
||||
|
||||
|
||||
public partial class EditView {
|
||||
|
||||
/// <summary>
|
||||
/// JsInclude1 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::ClientDependency.Core.Controls.JsInclude JsInclude1;
|
||||
|
||||
/// <summary>
|
||||
/// Panel1 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::umbraco.uicontrols.TabView Panel1;
|
||||
|
||||
/// <summary>
|
||||
/// Pane8 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::umbraco.uicontrols.Pane Pane8;
|
||||
|
||||
/// <summary>
|
||||
/// pp_source control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::umbraco.uicontrols.PropertyPanel pp_source;
|
||||
|
||||
/// <summary>
|
||||
/// editorSource control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::umbraco.uicontrols.CodeArea editorSource;
|
||||
|
||||
/// <summary>
|
||||
/// Pane7 control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::umbraco.uicontrols.Pane Pane7;
|
||||
|
||||
/// <summary>
|
||||
/// pp_name control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::umbraco.uicontrols.PropertyPanel pp_name;
|
||||
|
||||
/// <summary>
|
||||
/// PathPrefix control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.Literal PathPrefix;
|
||||
|
||||
/// <summary>
|
||||
/// NameTxt control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.TextBox NameTxt;
|
||||
|
||||
/// <summary>
|
||||
/// pp_alias control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::umbraco.uicontrols.PropertyPanel pp_alias;
|
||||
|
||||
/// <summary>
|
||||
/// AliasTxt control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.TextBox AliasTxt;
|
||||
|
||||
/// <summary>
|
||||
/// pp_masterTemplate control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::umbraco.uicontrols.PropertyPanel pp_masterTemplate;
|
||||
|
||||
/// <summary>
|
||||
/// MasterTemplate control.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Auto-generated field.
|
||||
/// To modify move field declaration from designer file to code-behind file.
|
||||
/// </remarks>
|
||||
protected global::System.Web.UI.WebControls.DropDownList MasterTemplate;
|
||||
}
|
||||
}
|
||||
@@ -262,7 +262,7 @@ namespace Umbraco.Web.Editors
|
||||
},
|
||||
{
|
||||
"mediaTypeApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<MediaTypeController>(
|
||||
controller => controller.GetAllowedChildren("0"))
|
||||
controller => controller.GetAllowedChildren(0))
|
||||
},
|
||||
{
|
||||
"macroApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<MacroController>(
|
||||
@@ -367,6 +367,10 @@ namespace Umbraco.Web.Editors
|
||||
{
|
||||
"templateQueryApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<TemplateQueryController>(
|
||||
controller => controller.PostTemplateQuery(null))
|
||||
},
|
||||
{
|
||||
"codeFileApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl<CodeFileController>(
|
||||
controller => controller.GetByPath("", ""))
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -0,0 +1,234 @@
|
||||
using AutoMapper;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Web.Http;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.WebApi;
|
||||
using Umbraco.Web.WebApi.Filters;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
[PluginController("UmbracoApi")]
|
||||
[PrefixlessBodyModelValidator]
|
||||
[UmbracoApplicationAuthorizeAttribute(Core.Constants.Applications.Settings)]
|
||||
public class CodeFileController : BackOfficeNotificationsController
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Used to create a brand new file
|
||||
/// </summary>
|
||||
/// <param name="type">This is a string but will be 'scripts' 'partialViews', 'partialViewMacros'</param>
|
||||
/// <param name="display"></param>
|
||||
/// <returns>Will return a simple 200 if file creation succeeds</returns>
|
||||
[ValidationFilter]
|
||||
public HttpResponseMessage PostCreate(string type, CodeFileDisplay display)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Core.Constants.Trees.PartialViews:
|
||||
var view = new PartialView(display.VirtualPath);
|
||||
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);
|
||||
var resultMacro = Services.FileService.CreatePartialViewMacro(viewMacro, display.Snippet, Security.CurrentUser.Id);
|
||||
return resultMacro.Success == true ? Request.CreateResponse(HttpStatusCode.OK) : Request.CreateNotificationValidationErrorResponse(resultMacro.Exception.Message);
|
||||
|
||||
case Core.Constants.Trees.Scripts:
|
||||
var script = new Script(display.VirtualPath);
|
||||
Services.FileService.SaveScript(script, Security.CurrentUser.Id);
|
||||
return Request.CreateResponse(HttpStatusCode.OK);
|
||||
|
||||
default:
|
||||
return Request.CreateResponse(HttpStatusCode.NotFound);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to get a specific file from disk via the FileService
|
||||
/// </summary>
|
||||
/// <param name="type">This is a string but will be 'scripts' 'partialViews', 'partialViewMacros'</param>
|
||||
/// <param name="virtualPath">The filename or urlencoded path of the file to open</param>
|
||||
/// <returns>The file and its contents from the virtualPath</returns>
|
||||
public CodeFileDisplay GetByPath(string type, string virtualPath)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(type) || string.IsNullOrWhiteSpace(virtualPath))
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
virtualPath = System.Web.HttpUtility.UrlDecode(virtualPath);
|
||||
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case Core.Constants.Trees.PartialViews:
|
||||
var view = Services.FileService.GetPartialView(virtualPath);
|
||||
if (view != null)
|
||||
{
|
||||
var display = Mapper.Map<IPartialView, CodeFileDisplay>(view);
|
||||
display.FileType = Core.Constants.Trees.PartialViews;
|
||||
return display;
|
||||
}
|
||||
return null;
|
||||
|
||||
case Core.Constants.Trees.PartialViewMacros:
|
||||
var viewMacro = Services.FileService.GetPartialViewMacro(virtualPath);
|
||||
if (viewMacro != null)
|
||||
{
|
||||
var display = Mapper.Map<IPartialView, CodeFileDisplay>(viewMacro);
|
||||
display.FileType = Core.Constants.Trees.PartialViewMacros;
|
||||
return display;
|
||||
}
|
||||
return null;
|
||||
|
||||
case Core.Constants.Trees.Scripts:
|
||||
var script = Services.FileService.GetScriptByName(virtualPath);
|
||||
if (script != null)
|
||||
{
|
||||
var display = Mapper.Map<Script, CodeFileDisplay>(script);
|
||||
display.FileType = Core.Constants.Trees.Scripts;
|
||||
return display;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to delete a specific file from disk via the FileService
|
||||
/// </summary>
|
||||
/// <param name="type">This is a string but will be 'scripts' 'partialViews', 'partialViewMacros'</param>
|
||||
/// <param name="virtualPath">The filename or urlencoded path of the file to delete</param>
|
||||
/// <returns>Will return a simple 200 if file deletion succeeds</returns>
|
||||
[HttpDelete]
|
||||
[HttpPost]
|
||||
public HttpResponseMessage Delete(string type, string virtualPath)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(type) == false && string.IsNullOrWhiteSpace(virtualPath) == false)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Core.Constants.Trees.PartialViews:
|
||||
if (Services.FileService.DeletePartialView(virtualPath, Security.CurrentUser.Id))
|
||||
{
|
||||
return Request.CreateResponse(HttpStatusCode.OK);
|
||||
}
|
||||
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "No Partial View found with the specified path");
|
||||
|
||||
case Core.Constants.Trees.PartialViewMacros:
|
||||
if (Services.FileService.DeletePartialViewMacro(virtualPath, Security.CurrentUser.Id))
|
||||
{
|
||||
return Request.CreateResponse(HttpStatusCode.OK);
|
||||
}
|
||||
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "No Partial View Macro found with the specified path");
|
||||
|
||||
case Core.Constants.Trees.Scripts:
|
||||
if (Services.FileService.GetScriptByName(virtualPath) != null)
|
||||
{
|
||||
Services.FileService.DeleteScript(virtualPath, Security.CurrentUser.Id);
|
||||
return Request.CreateResponse(HttpStatusCode.OK);
|
||||
}
|
||||
return Request.CreateErrorResponse(HttpStatusCode.NotFound, "No Script found with the specified path");
|
||||
|
||||
default:
|
||||
return Request.CreateResponse(HttpStatusCode.NotFound);
|
||||
}
|
||||
}
|
||||
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to save/update an existing file after its initial creation
|
||||
/// </summary>
|
||||
/// <param name="display"></param>
|
||||
/// <returns>The updated CodeFileDisplay model</returns>
|
||||
public CodeFileDisplay PostSave(CodeFileDisplay display)
|
||||
{
|
||||
if (ModelState.IsValid == false)
|
||||
{
|
||||
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState));
|
||||
}
|
||||
|
||||
if (display == null || string.IsNullOrWhiteSpace(display.FileType))
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
|
||||
switch (display.FileType)
|
||||
{
|
||||
case Core.Constants.Trees.PartialViews:
|
||||
var view = Services.FileService.GetPartialView(display.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;
|
||||
var result = Services.FileService.SavePartialView(view, Security.CurrentUser.Id);
|
||||
if (result.Success == true)
|
||||
{
|
||||
return Mapper.Map(view, display);
|
||||
}
|
||||
|
||||
display.AddErrorNotification(
|
||||
Services.TextService.Localize("speechBubbles/partialViewErrorHeader"),
|
||||
Services.TextService.Localize("speechBubbles/partialViewErrorText"));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
break;
|
||||
|
||||
case Core.Constants.Trees.PartialViewMacros:
|
||||
var viewMacro = Services.FileService.GetPartialViewMacro(display.VirtualPath);
|
||||
if (viewMacro != null)
|
||||
{
|
||||
viewMacro.Content = display.Content;
|
||||
viewMacro.Path = display.Name;
|
||||
var result = Services.FileService.SavePartialViewMacro(viewMacro, Security.CurrentUser.Id);
|
||||
if (result.Success == false)
|
||||
{
|
||||
display.AddErrorNotification(
|
||||
Services.TextService.Localize("speechBubbles/macroPartialViewErrorHeader"),
|
||||
Services.TextService.Localize("speechBubbles/macroPartialViewErrorText"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
break;
|
||||
|
||||
case Core.Constants.Trees.Scripts:
|
||||
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);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
return display;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,11 +4,9 @@ using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Formatting;
|
||||
using System.Text;
|
||||
using System.Web.Http;
|
||||
using System.Web.Http.ModelBinding;
|
||||
using System.Web.Http.ModelBinding.Binders;
|
||||
using AutoMapper;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Logging;
|
||||
@@ -17,24 +15,15 @@ using Umbraco.Core.Models.Membership;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Publishing;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Web.Models;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
using Umbraco.Web.Models.Mapping;
|
||||
using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.Security;
|
||||
using Umbraco.Web.WebApi;
|
||||
using Umbraco.Web.WebApi.Binders;
|
||||
using Umbraco.Web.WebApi.Filters;
|
||||
using umbraco;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Dynamics;
|
||||
using umbraco.BusinessLogic.Actions;
|
||||
using umbraco.cms.businesslogic.web;
|
||||
using umbraco.presentation.preview;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
using Umbraco.Web.UI;
|
||||
using Constants = Umbraco.Core.Constants;
|
||||
using Notification = Umbraco.Web.Models.ContentEditing.Notification;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
|
||||
@@ -97,6 +97,13 @@ namespace Umbraco.Web.Editors
|
||||
var dictionary = new Dictionary<string, object>();
|
||||
//add the files if any
|
||||
var files = contentItem.UploadedFiles.Where(x => x.PropertyAlias == property.Alias).ToArray();
|
||||
if (files.Length > 0)
|
||||
{
|
||||
dictionary.Add("files", files);
|
||||
// add extra things needed to figure out where to put the files
|
||||
dictionary.Add("cuid", contentItem.PersistedContent.Key);
|
||||
dictionary.Add("puid", dboProperty.PropertyType.Key);
|
||||
}
|
||||
|
||||
foreach (var file in files)
|
||||
file.FileName = file.FileName.ToSafeFileName();
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
@@ -27,6 +28,7 @@ using Umbraco.Web.Mvc;
|
||||
using Umbraco.Web.WebApi;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Web.Http.Controllers;
|
||||
using Umbraco.Web.WebApi.Binders;
|
||||
using Umbraco.Web.WebApi.Filters;
|
||||
using umbraco;
|
||||
@@ -45,9 +47,22 @@ namespace Umbraco.Web.Editors
|
||||
/// access to ALL of the methods on this controller will need access to the media application.
|
||||
/// </remarks>
|
||||
[PluginController("UmbracoApi")]
|
||||
[UmbracoApplicationAuthorizeAttribute(Constants.Applications.Media)]
|
||||
[UmbracoApplicationAuthorize(Constants.Applications.Media)]
|
||||
[MediaControllerControllerConfiguration]
|
||||
public class MediaController : ContentControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Configures this controller with a custom action selector
|
||||
/// </summary>
|
||||
private class MediaControllerControllerConfigurationAttribute : Attribute, IControllerConfiguration
|
||||
{
|
||||
public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
|
||||
{
|
||||
controllerSettings.Services.Replace(typeof(IHttpActionSelector), new ParameterSwapControllerActionSelector(
|
||||
new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetChildren", "id", typeof(int), typeof(Guid), typeof(string))));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
@@ -173,40 +188,10 @@ namespace Umbraco.Web.Editors
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the child media objects
|
||||
/// Returns the child media objects - using the entity INT id
|
||||
/// </summary>
|
||||
[FilterAllowedOutgoingMedia(typeof(IEnumerable<ContentItemBasic<ContentPropertyBasic, IMedia>>), "Items")]
|
||||
public PagedResult<ContentItemBasic<ContentPropertyBasic, IMedia>> GetChildren(string id,
|
||||
int pageNumber = 0,
|
||||
int pageSize = 0,
|
||||
string orderBy = "SortOrder",
|
||||
Direction orderDirection = Direction.Ascending,
|
||||
bool orderBySystemField = true,
|
||||
string filter = "")
|
||||
{
|
||||
int idInt; Guid idGuid;
|
||||
|
||||
if (Guid.TryParse(id, out idGuid))
|
||||
{
|
||||
var entity = Services.EntityService.GetByKey(idGuid);
|
||||
if (entity != null)
|
||||
{
|
||||
return GetChildren(entity.Id, pageNumber, pageSize, orderBy, orderDirection, orderBySystemField, filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
}
|
||||
else if (int.TryParse(id, out idInt))
|
||||
{
|
||||
return GetChildren(idInt, pageNumber, pageSize, orderBy, orderDirection, orderBySystemField, filter);
|
||||
}
|
||||
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
private PagedResult<ContentItemBasic<ContentPropertyBasic, IMedia>> GetChildren(int id,
|
||||
public PagedResult<ContentItemBasic<ContentPropertyBasic, IMedia>> GetChildren(int id,
|
||||
int pageNumber = 0,
|
||||
int pageSize = 0,
|
||||
string orderBy = "SortOrder",
|
||||
@@ -240,6 +225,58 @@ namespace Umbraco.Web.Editors
|
||||
return pagedResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the child media objects - using the entity GUID id
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="pageNumber"></param>
|
||||
/// <param name="pageSize"></param>
|
||||
/// <param name="orderBy"></param>
|
||||
/// <param name="orderDirection"></param>
|
||||
/// <param name="orderBySystemField"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns></returns>
|
||||
[FilterAllowedOutgoingMedia(typeof(IEnumerable<ContentItemBasic<ContentPropertyBasic, IMedia>>), "Items")]
|
||||
public PagedResult<ContentItemBasic<ContentPropertyBasic, IMedia>> GetChildren(Guid id,
|
||||
int pageNumber = 0,
|
||||
int pageSize = 0,
|
||||
string orderBy = "SortOrder",
|
||||
Direction orderDirection = Direction.Ascending,
|
||||
bool orderBySystemField = true,
|
||||
string filter = "")
|
||||
{
|
||||
var entity = Services.EntityService.GetByKey(id);
|
||||
if (entity != null)
|
||||
{
|
||||
return GetChildren(entity.Id, pageNumber, pageSize, orderBy, orderDirection, orderBySystemField, filter);
|
||||
}
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
[Obsolete("Do not use this method, use either the overload with INT or GUID instead, this will be removed in future versions")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[UmbracoTreeAuthorize(Constants.Trees.MediaTypes, Constants.Trees.Media)]
|
||||
public PagedResult<ContentItemBasic<ContentPropertyBasic, IMedia>> GetChildren(string id,
|
||||
int pageNumber = 0,
|
||||
int pageSize = 0,
|
||||
string orderBy = "SortOrder",
|
||||
Direction orderDirection = Direction.Ascending,
|
||||
bool orderBySystemField = true,
|
||||
string filter = "")
|
||||
{
|
||||
foreach (var type in new[] { typeof(int), typeof(Guid) })
|
||||
{
|
||||
var parsed = id.TryConvertTo(type);
|
||||
if (parsed)
|
||||
{
|
||||
//oooh magic! will auto select the right overload
|
||||
return GetChildren((dynamic)parsed.Result);
|
||||
}
|
||||
}
|
||||
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Moves an item to the recycle bin, if it is already there then it will permanently delete it
|
||||
/// </summary>
|
||||
|
||||
@@ -13,6 +13,9 @@ using Umbraco.Web.WebApi;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Models.EntityBase;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Web.Http.Controllers;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
@@ -26,8 +29,21 @@ namespace Umbraco.Web.Editors
|
||||
[PluginController("UmbracoApi")]
|
||||
[UmbracoTreeAuthorize(Constants.Trees.MediaTypes)]
|
||||
[EnableOverrideAuthorization]
|
||||
[MediaTypeControllerControllerConfigurationAttribute]
|
||||
public class MediaTypeController : ContentTypeControllerBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Configures this controller with a custom action selector
|
||||
/// </summary>
|
||||
private class MediaTypeControllerControllerConfigurationAttribute : Attribute, IControllerConfiguration
|
||||
{
|
||||
public void Initialize(HttpControllerSettings controllerSettings, HttpControllerDescriptor controllerDescriptor)
|
||||
{
|
||||
controllerSettings.Services.Replace(typeof(IHttpActionSelector), new ParameterSwapControllerActionSelector(
|
||||
new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetAllowedChildren", "contentId", typeof(int), typeof(Guid), typeof(string))));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor
|
||||
/// </summary>
|
||||
@@ -172,26 +188,11 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the allowed child content type objects for the content item id passed in
|
||||
/// Returns the allowed child content type objects for the content item id passed in - based on an INT id
|
||||
/// </summary>
|
||||
/// <param name="contentId"></param>
|
||||
[UmbracoTreeAuthorize(Constants.Trees.MediaTypes, Constants.Trees.Media)]
|
||||
public IEnumerable<ContentTypeBasic> GetAllowedChildren(string contentId)
|
||||
{
|
||||
Guid idGuid = Guid.Empty;
|
||||
int idInt;
|
||||
if (Guid.TryParse(contentId, out idGuid)) {
|
||||
var entity = ApplicationContext.Services.EntityService.GetByKey(idGuid);
|
||||
return GetAllowedChildrenInternal(entity.Id);
|
||||
} else if (int.TryParse(contentId, out idInt))
|
||||
{
|
||||
return GetAllowedChildrenInternal(idInt);
|
||||
}
|
||||
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
private IEnumerable<ContentTypeBasic> GetAllowedChildrenInternal(int contentId)
|
||||
public IEnumerable<ContentTypeBasic> GetAllowedChildren(int contentId)
|
||||
{
|
||||
if (contentId == Constants.System.RecycleBinContent)
|
||||
return Enumerable.Empty<ContentTypeBasic>();
|
||||
@@ -231,6 +232,40 @@ namespace Umbraco.Web.Editors
|
||||
return basics;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the allowed child content type objects for the content item id passed in - based on a GUID id
|
||||
/// </summary>
|
||||
/// <param name="contentId"></param>
|
||||
[UmbracoTreeAuthorize(Constants.Trees.MediaTypes, Constants.Trees.Media)]
|
||||
public IEnumerable<ContentTypeBasic> GetAllowedChildren(Guid contentId)
|
||||
{
|
||||
var entity = ApplicationContext.Services.EntityService.GetByKey(contentId);
|
||||
if (entity != null)
|
||||
{
|
||||
return GetAllowedChildren(entity.Id);
|
||||
}
|
||||
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
[Obsolete("Do not use this method, use either the overload with INT or GUID instead, this will be removed in future versions")]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
[UmbracoTreeAuthorize(Constants.Trees.MediaTypes, Constants.Trees.Media)]
|
||||
public IEnumerable<ContentTypeBasic> GetAllowedChildren(string contentId)
|
||||
{
|
||||
foreach (var type in new[] { typeof(int), typeof(Guid) })
|
||||
{
|
||||
var parsed = contentId.TryConvertTo(type);
|
||||
if (parsed)
|
||||
{
|
||||
//oooh magic! will auto select the right overload
|
||||
return GetAllowedChildren((dynamic)parsed.Result);
|
||||
}
|
||||
}
|
||||
|
||||
throw new HttpResponseException(HttpStatusCode.NotFound);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Move the media type
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Web;
|
||||
using System.Web.Http.Controllers;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace Umbraco.Web.Editors
|
||||
{
|
||||
/// <summary>
|
||||
/// This is used to auto-select specific actions on controllers that would otherwise be ambiguous based on a single parameter type
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// As an example, lets say we have 2 methods: GetChildren(int id) and GetChildren(Guid id), by default Web Api won't allow this since
|
||||
/// it won't know what to select, but if this Tuple is passed in new Tuple{string, string}("GetChildren", "id")
|
||||
/// </remarks>
|
||||
internal class ParameterSwapControllerActionSelector : ApiControllerActionSelector
|
||||
{
|
||||
private readonly ParameterSwapInfo[] _actions;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor accepting a list of action name + parameter name
|
||||
/// </summary>
|
||||
/// <param name="actions"></param>
|
||||
public ParameterSwapControllerActionSelector(params ParameterSwapInfo[] actions)
|
||||
{
|
||||
_actions = actions;
|
||||
}
|
||||
public override HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
|
||||
{
|
||||
var found = _actions.FirstOrDefault(x => controllerContext.Request.RequestUri.GetLeftPart(UriPartial.Path).InvariantEndsWith(x.ActionName));
|
||||
|
||||
if (found != null)
|
||||
{
|
||||
var id = HttpUtility.ParseQueryString(controllerContext.Request.RequestUri.Query).Get(found.ParamName);
|
||||
|
||||
if (id != null)
|
||||
{
|
||||
var idTypes = found.SupportedTypes;
|
||||
|
||||
foreach (var idType in idTypes)
|
||||
{
|
||||
var converted = id.TryConvertTo(idType);
|
||||
if (converted)
|
||||
{
|
||||
var method = MatchByType(idType, controllerContext, found);
|
||||
if (method != null)
|
||||
return method;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return base.SelectAction(controllerContext);
|
||||
}
|
||||
|
||||
private static ReflectedHttpActionDescriptor MatchByType(Type idType, HttpControllerContext controllerContext, ParameterSwapInfo found)
|
||||
{
|
||||
var controllerType = controllerContext.Controller.GetType();
|
||||
var methods = controllerType.GetMethods().Where(info => info.Name == found.ActionName).ToArray();
|
||||
if (methods.Length > 1)
|
||||
{
|
||||
//choose the one that has the parameter with the T type
|
||||
var method = methods.FirstOrDefault(x => x.GetParameters().FirstOrDefault(p => p.Name == found.ParamName && p.ParameterType == idType) != null);
|
||||
|
||||
return new ReflectedHttpActionDescriptor(controllerContext.ControllerDescriptor, method);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
internal class ParameterSwapInfo
|
||||
{
|
||||
public string ActionName { get; private set; }
|
||||
public string ParamName { get; private set; }
|
||||
public Type[] SupportedTypes { get; private set; }
|
||||
|
||||
public ParameterSwapInfo(string actionName, string paramName, params Type[] supportedTypes)
|
||||
{
|
||||
ActionName = actionName;
|
||||
ParamName = paramName;
|
||||
SupportedTypes = supportedTypes;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Umbraco.Web.Models.ContentEditing
|
||||
{
|
||||
[DataContract(Name = "scriptFile", Namespace = "")]
|
||||
public class CodeFileDisplay : INotificationModel
|
||||
{
|
||||
[DataMember(Name = "virtualPath", IsRequired = true)]
|
||||
public string VirtualPath { get; set; }
|
||||
|
||||
[DataMember(Name = "name", IsRequired = true)]
|
||||
public string Name { get; set; }
|
||||
|
||||
[DataMember(Name = "content", IsRequired = true)]
|
||||
public string Content { get; set; }
|
||||
|
||||
[DataMember(Name = "fileType", IsRequired = true)]
|
||||
public string FileType { get; set; }
|
||||
|
||||
[DataMember(Name = "snippet")]
|
||||
[ReadOnly(true)]
|
||||
public string Snippet { get; set; }
|
||||
|
||||
public List<Notification> Notifications { get; private set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models.Mapping;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Web.Models.ContentEditing;
|
||||
|
||||
namespace Umbraco.Web.Models.Mapping
|
||||
{
|
||||
public class CodeFileDisplayMapper : MapperConfiguration
|
||||
{
|
||||
public override void ConfigureMappings(IConfiguration config, ApplicationContext applicationContext)
|
||||
{
|
||||
config.CreateMap<IPartialView, CodeFileDisplay>()
|
||||
.ForMember(x => x.FileType, exp => exp.Ignore())
|
||||
.ForMember(x => x.Notifications, exp => exp.Ignore())
|
||||
.ForMember(x => x.Snippet, exp => exp.Ignore());
|
||||
|
||||
config.CreateMap<Script, CodeFileDisplay>()
|
||||
.ForMember(x => x.FileType, exp => exp.Ignore())
|
||||
.ForMember(x => x.Notifications, exp => exp.Ignore())
|
||||
.ForMember(x => x.Snippet, exp => exp.Ignore());
|
||||
|
||||
config.CreateMap<CodeFileDisplay, IPartialView>()
|
||||
.ForMember(x => x.Id, exp => exp.Ignore())
|
||||
.ForMember(x => x.Key, exp => exp.Ignore())
|
||||
.ForMember(x => x.Path, exp => exp.Ignore())
|
||||
.ForMember(x => x.CreateDate, exp => exp.Ignore())
|
||||
.ForMember(x => x.UpdateDate, exp => exp.Ignore())
|
||||
.ForMember(x => x.Path, exp => exp.Ignore())
|
||||
.ForMember(x => x.Alias, exp => exp.Ignore())
|
||||
.ForMember(x => x.Name, exp => exp.Ignore())
|
||||
.ForMember(x => x.OriginalPath, exp => exp.Ignore())
|
||||
.ForMember(x => x.HasIdentity, exp => exp.Ignore());
|
||||
|
||||
config.CreateMap<CodeFileDisplay, Script>()
|
||||
.ForMember(x => x.Id, exp => exp.Ignore())
|
||||
.ForMember(x => x.Key, exp => exp.Ignore())
|
||||
.ForMember(x => x.Path, exp => exp.Ignore())
|
||||
.ForMember(x => x.CreateDate, exp => exp.Ignore())
|
||||
.ForMember(x => x.UpdateDate, exp => exp.Ignore())
|
||||
.ForMember(x => x.Path, exp => exp.Ignore())
|
||||
.ForMember(x => x.Alias, exp => exp.Ignore())
|
||||
.ForMember(x => x.Name, exp => exp.Ignore())
|
||||
.ForMember(x => x.OriginalPath, exp => exp.Ignore())
|
||||
.ForMember(x => x.HasIdentity, exp => exp.Ignore());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -125,9 +125,10 @@ namespace Umbraco.Web.Trees
|
||||
// use helper method to ensure we support both integer and guid lookups
|
||||
int iid;
|
||||
|
||||
// if it's the root node, we won't use the look up
|
||||
if (id != "-1")
|
||||
// look up from GUID if it's not an integer
|
||||
if (int.TryParse(id, out iid) == false)
|
||||
{
|
||||
|
||||
var idEntity = GetEntityFromId(id);
|
||||
if (idEntity == null)
|
||||
{
|
||||
@@ -135,10 +136,6 @@ namespace Umbraco.Web.Trees
|
||||
}
|
||||
iid = idEntity.Id;
|
||||
}
|
||||
else
|
||||
{
|
||||
iid = int.Parse(id);
|
||||
}
|
||||
|
||||
|
||||
//if a request is made for the root node data but the user's start node is not the default, then
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace Umbraco.Web.Trees
|
||||
{
|
||||
protected abstract string FilePath { get; }
|
||||
protected abstract string FileSearchPattern { get; }
|
||||
protected abstract string FileIcon { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Inheritors can override this method to modify the file node that is created.
|
||||
@@ -79,7 +80,7 @@ namespace Umbraco.Web.Trees
|
||||
if (filterByMultipleExtensions && Array.IndexOf<string>(allowedExtensions, file.Extension.ToLower().Trim('.')) < 0)
|
||||
continue;
|
||||
|
||||
var node = CreateTreeNode(orgPath + file.Name, orgPath, queryStrings, file.Name, "icon-file", false);
|
||||
var node = CreateTreeNode(System.Web.HttpUtility.UrlEncode(orgPath + file.Name), orgPath, queryStrings, file.Name, FileIcon, false);
|
||||
|
||||
OnRenderFileNode(ref node);
|
||||
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
using System.Text;
|
||||
using Umbraco.Core.IO;
|
||||
using umbraco.businesslogic;
|
||||
using umbraco.cms.presentation.Trees;
|
||||
using Umbraco.Core;
|
||||
|
||||
namespace Umbraco.Web.Trees
|
||||
{
|
||||
/// <summary>
|
||||
/// Tree for displaying partial view macros in the developer app
|
||||
/// </summary>
|
||||
[Tree(Constants.Applications.Developer, "partialViewMacros", "Partial View Macro Files", sortOrder: 6)]
|
||||
public class PartialViewMacrosTree : PartialViewsTree
|
||||
{
|
||||
public PartialViewMacrosTree(string application) : base(application)
|
||||
{
|
||||
}
|
||||
|
||||
protected override string FilePath
|
||||
{
|
||||
get { return SystemDirectories.MvcViews + "/MacroPartials/"; }
|
||||
}
|
||||
|
||||
public override void RenderJS(ref StringBuilder javascript)
|
||||
{
|
||||
javascript.Append(
|
||||
@"
|
||||
function openMacroPartialView(id) {
|
||||
UmbClientMgr.contentFrame('Settings/Views/EditView.aspx?treeType=partialViewMacros&file=' + id);
|
||||
}
|
||||
");
|
||||
|
||||
}/// <summary>
|
||||
/// Ensures that no folders can be added
|
||||
/// </summary>
|
||||
/// <param name="xNode"></param>
|
||||
protected override void OnRenderFolderNode(ref XmlTreeNode xNode)
|
||||
{
|
||||
base.OnRenderFolderNode(ref xNode);
|
||||
|
||||
xNode.NodeType = "partialViewMacrosFolder";
|
||||
}
|
||||
|
||||
protected override void ChangeNodeAction(XmlTreeNode xNode)
|
||||
{
|
||||
xNode.Action = xNode.Action.Replace("openFile", "openMacroPartialView");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.IO;
|
||||
using umbraco.BusinessLogic.Actions;
|
||||
using Umbraco.Web.Models.Trees;
|
||||
using System.Net.Http.Formatting;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Web.Trees
|
||||
{
|
||||
/// <summary>
|
||||
/// Tree for displaying partial view macros in the developer app
|
||||
/// </summary>
|
||||
[Tree(Constants.Applications.Developer, "partialViewMacros", "Partial View Macro Files", sortOrder: 6)]
|
||||
public class PartialViewMacrosTreeController : FileSystemTreeController
|
||||
{
|
||||
protected override string FilePath
|
||||
{
|
||||
get { return SystemDirectories.MacroPartials; }
|
||||
}
|
||||
|
||||
protected override string FileSearchPattern
|
||||
{
|
||||
get { return "*.cshtml"; }
|
||||
}
|
||||
|
||||
protected override string FileIcon
|
||||
{
|
||||
get { return "icon-article"; }
|
||||
}
|
||||
|
||||
protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings)
|
||||
{
|
||||
var menu = new MenuItemCollection();
|
||||
|
||||
if (id == Constants.System.Root.ToInvariantString())
|
||||
{
|
||||
|
||||
//refresh action
|
||||
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
// TODO: Wire up new delete dialog
|
||||
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
|
||||
return menu;
|
||||
}
|
||||
|
||||
protected override void OnRenderFileNode(ref TreeNode treeNode)
|
||||
{
|
||||
base.OnRenderFileNode(ref treeNode);
|
||||
}
|
||||
|
||||
protected override void OnRenderFolderNode(ref TreeNode treeNode)
|
||||
{
|
||||
//TODO: This isn't the best way to ensure a noop process for clicking a node but it works for now.
|
||||
treeNode.AdditionalData["jsClickCallback"] = "javascript:void(0);";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Web;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.IO;
|
||||
using umbraco.BusinessLogic.Actions;
|
||||
using umbraco.businesslogic;
|
||||
using umbraco.cms.businesslogic.template;
|
||||
using umbraco.cms.presentation.Trees;
|
||||
using umbraco.interfaces;
|
||||
|
||||
namespace Umbraco.Web.Trees
|
||||
{
|
||||
/// <summary>
|
||||
/// Tree for displaying partial views in the settings app
|
||||
/// </summary>
|
||||
[Tree(Constants.Applications.Settings, "partialViews", "Partial Views", sortOrder: 2)]
|
||||
public class PartialViewsTree : FileSystemTree
|
||||
{
|
||||
public PartialViewsTree(string application) : base(application) { }
|
||||
|
||||
public override void RenderJS(ref StringBuilder javascript)
|
||||
{
|
||||
javascript.Append(
|
||||
@"
|
||||
function openPartialView(id) {
|
||||
UmbClientMgr.contentFrame('Settings/Views/EditView.aspx?treeType=partialViews&file=' + id);
|
||||
}
|
||||
");
|
||||
}
|
||||
|
||||
protected override void CreateRootNode(ref XmlTreeNode rootNode)
|
||||
{
|
||||
rootNode.NodeType = TreeAlias;
|
||||
rootNode.NodeID = "init";
|
||||
}
|
||||
|
||||
protected override string FilePath
|
||||
{
|
||||
get { return SystemDirectories.MvcViews + "/Partials/"; }
|
||||
}
|
||||
|
||||
protected override string FileSearchPattern
|
||||
{
|
||||
get { return "*.cshtml"; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensures that no folders can be added
|
||||
/// </summary>
|
||||
/// <param name="xNode"></param>
|
||||
protected override void OnRenderFolderNode(ref XmlTreeNode xNode)
|
||||
{
|
||||
// We should allow folder hierarchy for organization in large sites.
|
||||
xNode.Action = "javascript:void(0);";
|
||||
xNode.NodeType = "partialViewsFolder";
|
||||
xNode.Menu = new List<IAction>(new IAction[]
|
||||
{
|
||||
ActionNew.Instance,
|
||||
ContextMenuSeperator.Instance,
|
||||
ActionDelete.Instance,
|
||||
ContextMenuSeperator.Instance,
|
||||
ActionRefresh.Instance
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
protected virtual void ChangeNodeAction(XmlTreeNode xNode)
|
||||
{
|
||||
xNode.Action = xNode.Action.Replace("openFile", "openPartialView");
|
||||
}
|
||||
|
||||
protected override void OnRenderFileNode(ref XmlTreeNode xNode)
|
||||
{
|
||||
ChangeNodeAction(xNode);
|
||||
xNode.Icon = "icon-article";
|
||||
xNode.OpenIcon = "icon-article";
|
||||
|
||||
xNode.Text = xNode.Text.StripFileExtension();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.IO;
|
||||
using umbraco.BusinessLogic.Actions;
|
||||
using Umbraco.Web.Models.Trees;
|
||||
using System.Net.Http.Formatting;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Web.Trees
|
||||
{
|
||||
/// <summary>
|
||||
/// Tree for displaying partial views in the settings app
|
||||
/// </summary>
|
||||
[Tree(Constants.Applications.Settings, "partialViews", "Partial Views", sortOrder: 2)]
|
||||
public class PartialViewsTreeController : FileSystemTreeController
|
||||
{
|
||||
protected override string FilePath
|
||||
{
|
||||
get { return SystemDirectories.PartialViews; }
|
||||
}
|
||||
|
||||
protected override string FileSearchPattern
|
||||
{
|
||||
get { return "*.cshtml"; }
|
||||
}
|
||||
protected override string FileIcon
|
||||
{
|
||||
get { return "icon-article"; }
|
||||
}
|
||||
|
||||
protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings)
|
||||
{
|
||||
var menu = new MenuItemCollection();
|
||||
|
||||
if (id == Constants.System.Root.ToInvariantString())
|
||||
{
|
||||
|
||||
//refresh action
|
||||
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
// TODO: Wire up new delete dialog
|
||||
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
|
||||
return menu;
|
||||
}
|
||||
|
||||
protected override void OnRenderFileNode(ref TreeNode treeNode)
|
||||
{
|
||||
base.OnRenderFileNode(ref treeNode);
|
||||
}
|
||||
|
||||
protected override void OnRenderFolderNode(ref TreeNode treeNode)
|
||||
{
|
||||
//TODO: This isn't the best way to ensure a noop process for clicking a node but it works for now.
|
||||
treeNode.AdditionalData["jsClickCallback"] = "javascript:void(0);";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.IO;
|
||||
using umbraco.BusinessLogic.Actions;
|
||||
using Umbraco.Web.Models.Trees;
|
||||
using System.Net.Http.Formatting;
|
||||
using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Web.Trees
|
||||
{
|
||||
[Tree(Constants.Applications.Settings, "scripts", "Scripts", sortOrder: 4)]
|
||||
public class ScriptTreeController : FileSystemTreeController
|
||||
{
|
||||
protected override string FilePath
|
||||
{
|
||||
get { return SystemDirectories.Scripts; }
|
||||
}
|
||||
|
||||
protected override string FileSearchPattern
|
||||
{
|
||||
get { return "*.js"; }
|
||||
}
|
||||
protected override string FileIcon
|
||||
{
|
||||
get { return "icon-script"; }
|
||||
}
|
||||
|
||||
protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings)
|
||||
{
|
||||
var menu = new MenuItemCollection();
|
||||
|
||||
if (id == Constants.System.Root.ToInvariantString())
|
||||
{
|
||||
|
||||
//refresh action
|
||||
menu.Items.Add<RefreshNode, ActionRefresh>(Services.TextService.Localize(string.Format("actions/{0}", ActionRefresh.Instance.Alias)), true);
|
||||
|
||||
return menu;
|
||||
}
|
||||
|
||||
// TODO: Wire up new delete dialog
|
||||
menu.Items.Add<ActionDelete>(Services.TextService.Localize(string.Format("actions/{0}", ActionDelete.Instance.Alias)));
|
||||
return menu;
|
||||
}
|
||||
|
||||
protected override void OnRenderFolderNode(ref TreeNode treeNode)
|
||||
{
|
||||
//TODO: This isn't the best way to ensure a noop process for clicking a node but it works for now.
|
||||
treeNode.AdditionalData["jsClickCallback"] = "javascript:void(0);";
|
||||
}
|
||||
|
||||
protected override void OnRenderFileNode(ref TreeNode treeNode)
|
||||
{
|
||||
base.OnRenderFileNode(ref treeNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -287,6 +287,8 @@
|
||||
<Compile Include="Editors\EditorValidator.cs" />
|
||||
<Compile Include="Editors\GravatarController.cs" />
|
||||
<Compile Include="Editors\TemplateController.cs" />
|
||||
<Compile Include="Editors\ParameterSwapControllerActionSelector.cs" />
|
||||
<Compile Include="Editors\CodeFileController.cs" />
|
||||
<Compile Include="HealthCheck\Checks\Config\AbstractConfigCheck.cs" />
|
||||
<Compile Include="HealthCheck\Checks\Config\AcceptableConfiguration.cs" />
|
||||
<Compile Include="HealthCheck\Checks\Config\ConfigurationService.cs" />
|
||||
@@ -339,11 +341,13 @@
|
||||
<Compile Include="Models\ContentEditing\SimpleNotificationModel.cs" />
|
||||
<Compile Include="Models\ContentEditing\TemplateDisplay.cs" />
|
||||
<Compile Include="Models\LocalPackageInstallModel.cs" />
|
||||
<Compile Include="Models\Mapping\CodeFileDisplayMapper.cs" />
|
||||
<Compile Include="Models\Mapping\ContentTypeModelMapperExtensions.cs" />
|
||||
<Compile Include="Models\Mapping\LockedCompositionsResolver.cs" />
|
||||
<Compile Include="Models\Mapping\PropertyGroupDisplayResolver.cs" />
|
||||
<Compile Include="Models\Mapping\TemplateModelMapper.cs" />
|
||||
<Compile Include="Models\PackageInstallResult.cs" />
|
||||
<Compile Include="Models\ContentEditing\CodeFileDisplay.cs" />
|
||||
<Compile Include="Models\SetPasswordModel.cs" />
|
||||
<Compile Include="Models\RequestPasswordResetModel.cs" />
|
||||
<Compile Include="Models\PublishedContentWithKeyBase.cs" />
|
||||
@@ -392,6 +396,7 @@
|
||||
<Compile Include="Trees\MemberTypeTreeController.cs" />
|
||||
<Compile Include="Security\OwinExtensions.cs" />
|
||||
<Compile Include="Security\WebAuthExtensions.cs" />
|
||||
<Compile Include="Trees\ScriptTreeController.cs" />
|
||||
<Compile Include="UmbracoDefaultOwinStartup.cs" />
|
||||
<Compile Include="IUmbracoContextAccessor.cs" />
|
||||
<Compile Include="Models\ContentEditing\Relation.cs" />
|
||||
@@ -1046,8 +1051,8 @@
|
||||
<Compile Include="Strategies\ServerRegistrationEventHandler.cs" />
|
||||
<Compile Include="Templates\TemplateRenderer.cs" />
|
||||
<Compile Include="Templates\TemplateUtilities.cs" />
|
||||
<Compile Include="Trees\PartialViewMacrosTree.cs" />
|
||||
<Compile Include="Trees\PartialViewsTree.cs" />
|
||||
<Compile Include="Trees\PartialViewMacrosTreeController.cs" />
|
||||
<Compile Include="Trees\PartialViewsTreeController.cs" />
|
||||
<Compile Include="UI\Controls\InsertMacroSplitButton.cs" />
|
||||
<Compile Include="UI\IAssignedApp.cs" />
|
||||
<Compile Include="UI\LegacyDialogHandler.cs" />
|
||||
|
||||
Reference in New Issue
Block a user