Compare commits

...

71 Commits

Author SHA1 Message Date
Claus f3b364022a bumping version for deploy. 2017-01-31 10:33:57 +01:00
Claus 56ae2b709d adding deploy entity types for forms. 2017-01-31 10:31:45 +01:00
Mads Rasmussen 0acc202740 Merge pull request #1712 from umbraco/temp-U4-9410
U4-9410 Hook up delete dialog for Code Files
2017-01-30 20:50:36 +01:00
Claus 4ad0c1bb89 cleaning usings. 2017-01-30 13:14:19 +01:00
Claus 67da15330e U4-9410 Hook up delete dialog for Code Files
delete dialogs for partialviews, partialviewmacros and scripts.
+ fixed codefileResource.
+ fixed comments in MemberTypesDeleteController.
2017-01-30 11:56:30 +01:00
Shannon a458e7daf0 Merge remote-tracking branch 'refs/remotes/origin/dev-v7' into dev-v7.6
# Conflicts:
#	build/UmbracoVersion.txt
#	src/SolutionInfo.cs
#	src/Umbraco.Core/Configuration/UmbracoVersion.cs
#	src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
#	src/Umbraco.Web/Umbraco.Web.csproj
2017-01-30 16:55:12 +11:00
Stephan d85cb9e15e Fix FileSystemProviderManagerTests 2017-01-28 10:04:43 +01:00
Mads Rasmussen 19a4cf774b Merge pull request #1680 from umbraco/temp-U4-9352
Implements CodeFileController
2017-01-27 10:49:07 +01:00
Mads Rasmussen ab00ba8a12 Merge branch 'dev-v7.6' into temp-U4-9352
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/views/templates/edit.controller.js
2017-01-27 10:39:31 +01:00
Claus 57e2a19023 changing parameter name for IGridCellValueConnector.IsConnector. 2017-01-27 10:16:01 +01:00
Claus daa80a7bf6 Merge pull request #1709 from umbraco/temp-U4-9435-2
U4-9435 Fix breaking change made in U4-9312
2017-01-27 09:05:47 +01:00
Shannon 8152e7cb92 Doh, forgot a file change for tests - fixes build 2017-01-27 16:55:29 +11:00
Shannon Deminick adccb4161e Merge pull request #1707 from umbraco/temp-u4-9438
U4-9438 - fix nasty issue with reading properties in VersionableRepos…
2017-01-27 16:52:10 +11:00
Shannon 72a0187295 Writes unit test to confirm the correct property data iteration in GetPropertyCollection 2017-01-27 16:50:44 +11:00
Shannon 24d6287918 Adds string overloads just in case 2017-01-27 16:21:01 +11:00
Shannon 55900a3464 Updates MediaController and MediaTypeController to have the same method signature supporting both INT and GUID with a custom action selector to handle the ambiguity 2017-01-27 16:09:35 +11:00
Sebastiaan Janssen a5a42854ef Bump version to alpha055 2017-01-26 22:02:18 +01:00
Warren Buckley 784c84a166 Merge pull request #1474 from umbraco/temp-U4-8963
U4-8963 Updates for ImageProcessor parameters to support background c…
2017-01-26 20:45:35 +00:00
Sebastiaan Janssen f5d78a4d04 Merge pull request #1708 from umbraco/temp-U4-9440
Fixes: U4-9440 Update the last few Danish translations for template e…
2017-01-26 19:51:54 +01:00
Mads Rasmussen b334e0ccb2 Fixes: U4-9440 Update the last few Danish translations for template editor 2017-01-26 19:45:05 +01:00
Sebastiaan Janssen 0a2e5badd0 Merge branch 'temp-template-editor' into dev-v7.6 2017-01-26 18:27:10 +01:00
Sebastiaan Janssen 90b0bf9d82 Merge branch 'dev-v7.6' into temp-template-editor 2017-01-26 18:26:32 +01:00
Sebastiaan Janssen 6bcd1e44f9 If translation is not done yet, better to leave it English so at least it kind of makes sense 2017-01-26 18:24:56 +01:00
Sebastiaan Janssen 36e9bb4d78 Merge pull request #1705 from umbraco/temp-v758-recyclebin-fix
Fixes U4-9437
2017-01-26 17:31:31 +01:00
Warren Buckley 4c06ead056 Merge pull request #1698 from umbraco/temp-U4-9419
fixes: U4-9419 The new content picker adds picked items in a random o…
2017-01-26 16:21:03 +00:00
Sebastiaan Janssen 639d04381e Bump version 2017-01-26 14:48:19 +01:00
mikkelhm 031340a2ac Adds case for IDictionaryItem when trying to get the Udi from an entity 2017-01-26 13:41:04 +01:00
Warren Buckley 2465eb233e Adds in same workaround as other trees like DataTypes & DocTypes where Folders/Containers set an inline piece of JS that does nothing & returns 2017-01-26 11:32:13 +00:00
Stephan 7f905bce0e U4-9438 - fix nasty issue with reading properties in VersionableRepositoryBase 2017-01-26 11:49:52 +01:00
Niels Hartvig 205ea22daa Fixes U4-9437 2017-01-25 17:34:34 +01:00
Warren Buckley c1fcb37642 Adds keys for DA file but appends them with DA to try & make it clear they need some translation love as my Danish is to be desired :) 2017-01-23 16:08:38 +00:00
Warren Buckley 0bba68a7f5 Added keys needed in EN lang files 2017-01-23 16:06:37 +00:00
Warren Buckley 47e4c12395 Adds in translations into the JSON objects we send back from the API as the display name (not the aliases for querying) 2017-01-23 16:04:14 +00:00
Warren Buckley 25822a7564 Fix up orderby translation in view and use our new JSON properties for display the tranlsated value for asc & desc 2017-01-23 16:01:05 +00:00
Warren Buckley 072f0d1520 Adds in some extra propeties on JSON to store localization label for ascending & descending & use correct key for MyWebstie/WebSite Root that was already in lang file 2017-01-23 15:53:18 +00:00
Warren Buckley f3e78e990f Fix up failing unit test for the number of Trees found - this has gone down due this test is for implementing interface ITree which is the legacy type of Trees, where the new PartialViews & PartialView Macros now use TreeController 2017-01-20 09:52:23 +00:00
Warren Buckley 2f7b532209 Adds in code summaries for C# doc generation. Removes unused references & some tidying up (mostly sensible R# suggestions) 2017-01-19 15:43:29 +00:00
Warren Buckley abebb40461 Update some copy/paste typos in code comments 2017-01-19 15:18:12 +00:00
Warren Buckley 3b54db9b49 Update main templat editor to use a localised notification 2017-01-19 15:14:46 +00:00
Warren Buckley 1defc1e0e4 Changed key for saving scripts - as it mentioned 'script view' Whats that?! So changed to more generic file 2017-01-19 15:14:14 +00:00
Warren Buckley a7e626f4a7 Localisation notification message for saving scripts 2017-01-19 15:05:05 +00:00
Warren Buckley 04f6a01196 Forgot to remove the old notification - as was display two 2017-01-19 15:04:36 +00:00
Warren Buckley ef64fbb839 Same change for the partialview editor - to display a localized success notifcation 2017-01-19 15:01:14 +00:00
Warren Buckley 2424a1c04b Adds in localised sucess notification when saving partial view macros 2017-01-19 14:57:23 +00:00
Warren Buckley c8c7de065d Forgot to update the var name in codeFileResource 2017-01-19 14:56:25 +00:00
Warren Buckley 61d71d0552 Update codeFileResource docs 2017-01-19 14:40:10 +00:00
Mads Rasmussen b8734e5eea fixes: U4-9419 The new content picker adds picked items in a random order 2017-01-19 15:11:37 +01:00
Per Ploug eefd13547c More localization of querybuilder 2017-01-19 12:53:39 +01:00
Mads Rasmussen a09755ef7f remove unused code in partial view editor 2017-01-19 11:19:34 +01:00
Niels Hartvig afae06a866 Adds support for icons and encoding of directories for Code files 2017-01-19 10:41:08 +01:00
Mads Rasmussen 86ffd66c8a update danish translations 2017-01-19 09:50:18 +01:00
Niels Hartvig 051af5c48e Wire up the editors and controllers 2017-01-19 09:49:27 +01:00
Niels Hartvig 1fb05fcca7 Merge remote-tracking branch 'refs/remotes/origin/temp-file-editors' into temp-U4-9352 2017-01-19 08:45:23 +01:00
Mads Rasmussen 49d24dada7 add partial views macros editor 2017-01-18 15:39:08 +01:00
Mads Rasmussen ef9dd6d803 add scripts editor 2017-01-18 15:38:40 +01:00
Mads Rasmussen 01f50a243b translate master template and no macros 2017-01-17 14:13:20 +01:00
Niels Hartvig a162f21a70 Fixing missing mapping - let the green build lights appear 2017-01-16 19:49:57 +01:00
Niels Hartvig ace111aefb Adding support for get, save and rename to new Partial View editor 2017-01-16 16:50:22 +01:00
Per Ploug 7a0ac625ff Last remaining dk translation strings
This needs a review by the dynamic writing duo vera and martin.
2017-01-16 10:13:32 +01:00
Niels Hartvig dfe3798aab More merge 2017-01-16 09:59:00 +01:00
Niels Hartvig 975535a9e2 Merge of insert overlay view 2017-01-13 13:33:55 +01:00
Niels Hartvig e7f7631d1e Fixes merge conflicts (needs updated ng-if in insert overlay) 2017-01-13 13:22:43 +01:00
Per Ploug 99f66fe6a3 The danish language files - WIP
The danish language has such elements when used to discusssed
semi-technical-english terms
2017-01-13 13:21:37 +01:00
Per Ploug b413a6eeae English translations 2017-01-13 13:20:49 +01:00
Per Ploug 9b9db23461 Replaces the last static strings with language keys 2017-01-13 13:20:38 +01:00
Mads Rasmussen 23304aca0b add unit tests for template helper 2017-01-10 15:16:16 +01:00
Mads Rasmussen 845dd4673c Add client side file for partial view editor 2017-01-10 15:15:56 +01:00
Niels Hartvig 14e402878a Merge conflict fixes 2017-01-10 14:49:19 +01:00
Niels Hartvig 5a2687d520 Merge of temp-template-editor 2017-01-10 14:47:33 +01:00
Niels Hartvig 4c330c8654 Implements CodeFileController 2017-01-09 22:54:28 +01:00
Claus b40a1fa613 U4-8963 Updates for ImageProcessor parameters to support background color 2016-09-12 12:47:12 +02:00
75 changed files with 2962 additions and 969 deletions
+1 -1
View File
@@ -1,3 +1,3 @@
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
7.6.0
alpha054
alpha056
+1 -1
View File
@@ -12,4 +12,4 @@ using System.Resources;
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("7.6.0")]
[assembly: AssemblyInformationalVersion("7.6.0-alpha054")]
[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 "alpha054"; } }
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
+7 -1
View File
@@ -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!
}
}
}
}
+18 -1
View File
@@ -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));
+30
View File
@@ -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.
+22 -1
View File
@@ -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
+3
View File
@@ -294,6 +294,9 @@ namespace Umbraco.Core
var relationType = entity as IRelationType;
if (relationType != null) return relationType.GetUdi();
var dictionaryItem = entity as IDictionaryItem;
if (dictionaryItem != null) return dictionaryItem.GetUdi();
throw new NotSupportedException(string.Format("Entity type {0} is not supported.", entity.GetType().FullName));
}
}
@@ -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]
@@ -367,5 +367,17 @@ namespace Umbraco.Tests.PropertyEditors
var urlString = mediaPath.GetCropUrl(imageCropperValue: cropperJson, height: 200);
Assert.AreEqual(mediaPath + "?anchor=center&mode=crop&height=200", urlString);
}
/// <summary>
/// Test to check result when using a background color with padding
/// </summary>
[Test]
public void GetCropUrl_BackgroundColorParameter()
{
var cropperJson = "{\"focalPoint\": {\"left\": 0.5,\"top\": 0.5},\"src\": \"" + mediaPath + "\",\"crops\": [{\"alias\": \"home\",\"width\": 270,\"height\": 161}]}";
var urlString = mediaPath.GetCropUrl(400, 400, cropperJson, imageCropMode: ImageCropMode.Pad, backgroundColor: "fff");
Assert.AreEqual(mediaPath + "?mode=pad&width=400&height=400&bgcolor=fff", urlString);
}
}
}
@@ -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,16 +1,16 @@
(function () {
"use strict";
function InsertOverlayController($scope) {
function InsertOverlayController($scope, localizationService) {
var vm = this;
if(!$scope.model.title) {
$scope.model.title = "Insert";
$scope.model.title = localizationService.localize("template_insert");
}
if(!$scope.model.subtitle) {
$scope.model.subtitle = "Choose what to insert into your template";
$scope.model.subtitle = localizationService.localize("template_insertDesc");
}
vm.openMacroPicker = openMacroPicker;
@@ -22,7 +22,7 @@
vm.macroPickerOverlay = {
view: "macropicker",
title: "Insert macro",
title: localizationService.localize("template_insertMacro"),
dialogData: {},
show: true,
submit: function(model) {
@@ -45,8 +45,8 @@
function openPageFieldOverlay() {
vm.pageFieldOverlay = {
title: "Insert value",
description: "Select a value from the currentpage",
title: localizationService.localize("template_insertPageField"),
description: localizationService.localize("template_insertPageFieldDesc"),
submitButtonLabel: "Insert",
closeButtonlabel: "Cancel",
view: "insertfield",
@@ -78,7 +78,8 @@
treeAlias: "dictionary",
entityType: "dictionary",
multiPicker: false,
title: "Insert dictionary item",
title: localizationService.localize("template_insertDictionaryItem"),
description: localizationService.localize("template_insertDictionaryItemDesc"),
show: true,
select: function(node){
@@ -108,7 +109,7 @@
entityType: "partialView",
multiPicker: false,
show: true,
title: "Insert partial view",
title: localizationService.localize("template_insertPartialView"),
select: function(node){
@@ -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_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>
@@ -27,12 +27,12 @@
</li>
</ul>
<umb-empty-state ng-if="nomacros"
position="center">
<localize key="defaultdialogs_nomacros">
<umb-empty-state
ng-if="nomacros"
position="center">
<localize key="defaultdialogs_noMacros">
There are no macros available to insert
</localize>
</umb-empty-state>
</div>
@@ -1,8 +1,14 @@
(function () {
"use strict";
function QueryBuilderOverlayController($scope, templateQueryResource) {
function QueryBuilderOverlayController($scope, templateQueryResource, localizationService) {
var everything = localizationService.localize("template_allContent");
var myWebsite = localizationService.localize("template_websiteRoot");
var ascendingTranslation = localizationService.localize("template_ascending");
var descendingTranslation = localizationService.localize("template_descending");
var vm = this;
vm.properties = [];
@@ -17,10 +23,10 @@
vm.query = {
contentType: {
name: "Everything"
name: everything
},
source: {
name: "My website"
name: myWebsite
},
filters: [
{
@@ -33,7 +39,13 @@
alias: "",
name: "",
},
direction: "ascending"
direction: "ascending", //This is the value for sorting sent to server
translation: {
currentLabel: ascendingTranslation, //This is the localized UI value in the the dialog
ascending: ascendingTranslation,
descending: descendingTranslation
}
}
};
@@ -74,7 +86,6 @@
vm.contentPickerOverlay = {
view: "contentpicker",
show: true,
submitButtonLabel: "Insert",
submit: function(model) {
var selectedNodeId = model.selection[0].id;
@@ -83,7 +94,7 @@
if (selectedNodeId > 0) {
query.source = { id: selectedNodeId, name: selectedNodeName };
} else {
query.source.name = "My website";
query.source.name = myWebsite;
delete query.source.id;
}
@@ -113,13 +124,21 @@
function trashFilter(query) {
query.filters.splice(query, 1);
//if we remove the last one, add a new one to generate ui for it.
if (query.filters.length == 0) {
query.filters.push({});
}
}
function changeSortOrder(query) {
if (query.sort.direction === "ascending") {
query.sort.direction = "descending";
query.sort.translation.currentLabel = query.sort.translation.descending;
} else {
query.sort.direction = "ascending";
query.sort.translation.currentLabel = query.sort.translation.ascending;
}
throttledFunc();
}
@@ -128,8 +147,10 @@
query.sort.property = property;
if (property.type === "datetime") {
query.sort.direction = "descending";
query.sort.translation.currentLabel = query.sort.translation.descending;
} else {
query.sort.direction = "ascending";
query.sort.translation.currentLabel = query.sort.translation.ascending;
}
throttledFunc();
}
@@ -5,7 +5,7 @@
<div class="row">
<div class="query-items">
<span><localize key="template_iWant">I Want</localize></span>
<span><localize key="template_iWant">I want</localize></span>
<div class="btn-group">
@@ -22,7 +22,7 @@
</div>
<span><localize key="template_fromt">from</localize></span>
<span><localize key="template_from">from</localize></span>
<a href class="btn btn-link" ng-click="vm.chooseSource(vm.query)">
{{vm.query.source.name}}
@@ -91,7 +91,7 @@
<i class="icon-add"></i>
</a>
<a href ng-if="vm.query.filters.length > 1" ng-click="vm.trashFilter(vm.query)">
<a href ng-click="vm.trashFilter(vm.query)">
<i class="icon-trash"></i>
</a>
@@ -100,7 +100,7 @@
<div class="query-items">
<span<localize key="template_orderBy">order by</localize></span>
<span><localize key="template_orderBy">order by</localize></span>
<div class="btn-group">
<a class="btn btn-link dropdown-toggle" data-toggle="dropdown" href="#">
@@ -119,7 +119,7 @@
</div>
<a href class="btn" ng-click="vm.changeSortOrder(vm.query)">
{{vm.query.sort.direction}}
{{vm.query.sort.translation.currentLabel}}
</a>
</div>
@@ -1,71 +1,59 @@
<div ng-controller="Umbraco.Overlays.TemplateSectionsOverlay as vm">
<div ng-if="!model.hasMaster" class="umb-insert-code-box" ng-click="vm.select('renderBody')">
<div class="umb-insert-code-box" ng-click="vm.select('renderBody')">
<div class="umb-insert-code-box__check" ng-class="{'umb-insert-code-box__check--checked': model.insertType === 'renderBody' }"><i class="icon icon-check"></i></div>
<div class="umb-insert-code-box__title">Render child template</div>
<div class="umb-insert-code-box__title"><localize key="template_renderBody" /></div>
<div class="umb-insert-code-box__description">
Renders the contents of a child template, by inserting a
<code>@RenderBody()</code> placeholder.
<localize key="template_renderBodyDesc" />
</div>
</div>
<div ng-if="!model.hasMaster" class="umb-insert-code-box" ng-click="vm.select('renderSection')">
<div class="umb-insert-code-box" ng-click="vm.select('renderSection')">
<div class="umb-insert-code-box__check" ng-class="{'umb-insert-code-box__check--checked': model.insertType === 'renderSection' }"><i class="icon icon-check"></i></div>
<div class="umb-insert-code-box__title">Render a named section</div>
<div class="umb-insert-code-box__title"><localize key="template_renderSection" /></div>
<div class="umb-insert-code-box__description">
Renders a named area of a child template, by insert a <code>@RenderSection(name)</code> placeholder.
This renders an area of a child template which is wrapped in a corresponding <code>@section [name]{ ... }</code> definition.
<localize key="template_renderSectionDesc" />
</div>
<div ng-if="model.insertType === 'renderSection'" style="margin-top: 20px;">
<div style="margin-bottom: 20px;">
<label class="bold">Section name <span class="red">*</span></label>
<label class="bold"><localize key="template_sectionName" /> <span class="red">*</span></label>
<input type="text" name="renderSectionName" class="-full-width-input" ng-model="model.renderSectionName" required umb-auto-focus />
<small class="red" val-msg-for="renderSectionName" val-toggle-msg="required"><localize key="required" /></small>
<div class="umb-insert-code-box__description">
Set the name of the section to render in this area of the template
</div>
</div>
<div>
<label>
<input type="checkbox" ng-model="model.mandatoryRenderSection" />
Make section mandatory
<input type="checkbox" ng-model="model.mandatoryRenderSection" /> <localize key="template_sectionMandatory" />
</label>
<div class="umb-insert-code-box__description">
If mandatory, the child template must contain a <code>@section</code> definition, otherwise an error is shown.
<localize key="template_sectionMandatoryDesc" />
</div>
</div>
</div>
</div>
<div ng-if="model.hasMaster" class="umb-insert-code-box" ng-click="vm.select('addSection')">
<div class="umb-insert-code-box" ng-click="vm.select('addSection')">
<div class="umb-insert-code-box__check" ng-class="{'umb-insert-code-box__check--checked': model.insertType === 'addSection' }"><i class="icon icon-check"></i></div>
<div class="umb-insert-code-box__title">Define a named section</div>
<div class="umb-insert-code-box__title"><localize key="template_defineSection" /></div>
<div class="umb-insert-code-box__description">
Defines a part of your template as a named section by wrapping it in
a <code>@section { ... }</code>. This can be rendered in a
specific area of the master of this template, by using <code>@RenderSection</code>.
<localize key="template_defineSectionDesc" />
</div>
<div ng-if="model.insertType === 'addSection'" style="margin-top: 20px;">
<div>
<label class="bold">Section name <span class="red">*</span></label>
<label class="bold"><localize key="template_sectionName" /> <span class="red">*</span></label>
<input type="text" name="sectionName" class="-full-width-input" ng-model="model.sectionName" required umb-auto-focus />
<small class="red" val-msg-for="sectionName" val-toggle-msg="required"><localize key="required" /></small>
<div class="umb-insert-code-box__description">
Give the section a name
</div>
</div>
</div>
</div>
</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>
@@ -259,18 +259,24 @@ function contentPickerController($scope, entityResource, editorState, iconHelper
});
function setEntityUrl(entity) {
// get url for content and media items
if(entityType !== "Member") {
entityResource.getUrl(entity.id, entityType).then(function(data){
// update url
entity.url = data;
// push item to render model
addSelectedItem(entity);
// update url
angular.forEach($scope.renderModel, function(item){
if(item.id === entity.id) {
item.url = data;
}
});
});
} else {
addSelectedItem(entity);
}
// add the selected item to the renderModel
// if it needs to show a url the item will get
// updated when the url comes back from server
addSelectedItem(entity);
}
function addSelectedItem(item) {
@@ -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;
@@ -220,7 +229,7 @@
view: "macropicker",
dialogData: {},
show: true,
title: "Insert macro",
title: localizationService.localize("template_insertMacro"),
submit: function (model) {
var macroObject = macroService.collectValueData(model.selectedMacro, model.macroParams, "Mvc");
@@ -247,6 +256,7 @@
closeButtonlabel: "Cancel",
view: "insertfield",
show: true,
title: localizationService.localize("template_insertPageField"),
submit: function (model) {
insert(model.umbracoField);
vm.pageFieldOverlay.show = false;
@@ -271,10 +281,9 @@
entityType: "dictionary",
multiPicker: false,
show: true,
title: "Insert dictionary item",
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;
@@ -298,11 +307,10 @@
entityType: "partialView",
multiPicker: false,
show: true,
title: "Insert Partial view",
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;
@@ -322,19 +330,10 @@
vm.queryBuilderOverlay = {
view: "querybuilder",
show: true,
title: "Query for content",
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;
@@ -356,21 +355,24 @@
vm.sectionsOverlay = {
view: "templatesections",
hasMaster: vm.template.masterTemplateAlias,
isMaster: vm.template.isMasterTemplate,
submitButtonLabel: "Insert",
show: true,
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;
@@ -401,7 +403,7 @@
vm.masterTemplateOverlay = {
view: "itempicker",
title: "Choose master template",
title: localizationService.localize("template_mastertemplate"),
availableItems: availableMasterTemplates,
show: true,
submit: function(model) {
@@ -443,23 +445,15 @@
}
function getMasterTemplateName(masterTemplateAlias, templates) {
if(masterTemplateAlias) {
var templateName = "";
angular.forEach(templates, function(template){
if(template.alias === masterTemplateAlias) {
templateName = template.name;
}
});
return templateName;
} else {
return "No master";
}
}
function removeMasterTemplate() {
@@ -33,7 +33,11 @@
class="umb-era-button umb-button--s"
ng-click="vm.openMasterTemplateOverlay()">
<i class="icon icon-layout"></i>
<span class="bold">Master template:</span> <span style="margin-left: 5px;">{{ vm.getMasterTemplateName(vm.template.masterTemplateAlias, vm.templates) }}</span>
<span class="bold"><localize key="template_mastertemplate">Master template</localize>:</span>
<span style="margin-left: 5px;">
<span ng-if="vm.template.masterTemplateAlias">{{ vm.getMasterTemplateName(vm.template.masterTemplateAlias, vm.templates) }}</span>
<span ng-if="!vm.template.masterTemplateAlias"><localize key="template_noMaster">No master</localize></span>
</span>
</button>
<a ng-if="vm.template.masterTemplateAlias" ng-click="vm.removeMasterTemplate()" class="umb-era-button umb-button--s dropdown-toggle umb-button-group__toggle">
@@ -62,7 +66,7 @@
<li><a href="" ng-click="vm.openPageFieldOverlay()"><localize key="template_insertPageField">Value</localize></a></li>
<li><a href="" ng-click="vm.openPartialOverlay()"><localize key="template_insertPartialView">Partial view</localize></a></li>
<li><a href="" ng-click="vm.openDictionaryItemOverlay()"><localize key="template_insertDictionaryItem">Dictionary</localize></a></li>
<li><a href="" ng-click="vm.openMacroOverlay()"><localize key="general_insertMacro">Macro</localize></a></li>
<li><a href="" ng-click="vm.openMacroOverlay()"><localize key="template_insertMacro">Macro</localize></a></li>
</ul>
</div>
@@ -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);
});
});
});
-8
View File
@@ -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" />
+3 -4
View File
@@ -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>
+106 -5
View File
@@ -291,6 +291,7 @@
<key alias="selectMember">Vælg medlem</key>
<key alias="selectMemberGroup">Vælg medlemsgruppe</key>
<key alias="noMacroParams">Der er ingen parametre for denne makro</key>
<key alias="noMacros">Der er ikke tilføjet nogen makroer</key>
<key alias="linkYour">Link dit</key>
<key alias="unLinkYour">Fjern link fra dit</key>
<key alias="account">konto</key>
@@ -1004,17 +1005,117 @@ Mange hilsner fra Umbraco robotten
<key alias="preview">Vis prøve</key>
<key alias="styles">Styles</key>
</area>
<area alias="template">
<key alias="edittemplate">Rediger skabelon</key>
<key alias="insertSections">Sektioner</key>
<key alias="insertContentArea">Indsæt indholdsområde</key>
<key alias="insertContentAreaPlaceHolder">Indsæt indholdsområdemarkering</key>
<key alias="insertDictionaryItem">Indsæt ordbogselement</key>
<key alias="insertMacro">Indsæt makro</key>
<key alias="insertPageField">Indsæt Umbraco sidefelt</key>
<key alias="insertContentAreaPlaceHolder">Indsæt pladsholder for indholdsområde</key>
<key alias="insert">Indsæt</key>
<key alias="insertDesc">Hvad vil du indsætte ?</key>
<key alias="insertDictionaryItem">Oversættelse</key>
<key alias="insertDictionaryItemDesc">Indsætter en oversætbar tekst, som skifter efter det sprog, som websitet vises i.</key>
<key alias="insertMacro">Makro</key>
<key alias="insertMacroDesc">
En makro er et element, som kan have forskellige indstillinger, når det indsættes.
Brug det som en genbrugelig del af dit design såsom gallerier, formularer og lister.
</key>
<key alias="insertPageField">Sideværdi</key>
<key alias="insertPageFieldDesc">
Viser værdien af et felt fra den nuværende side. Kan indstilles til at bruge rekursive værdier eller
vise en standardværdi i tilfælde af, at feltet er tomt.
</key>
<key alias="insertPartialView">Partial view</key>
<key alias="insertPartialViewDesc">
Et Partial View er et skabelonelement, som kan indsættes i andre skabeloner og derved
genbruges og deles på tværs af sideskabelonerne.
</key>
<key alias="mastertemplate">Master skabelon</key>
<key alias="quickGuide">Lynguide til Umbracos skabelontags</key>
<key alias="noMastertemplate">Ingen masterskabelon</key>
<key alias="noMaster">Ingen master</key>
<key alias="renderBody">Indsæt en underliggende skabelon</key>
<key alias="renderBodyDesc">
<![CDATA[
Henter indholdet af en underliggende skabelon ind, ved at
indsætte et <code>@RenderBody()</code> element.
]]>
</key>
<key alias="defineSection">Definer en sektion</key>
<key alias="defineSectionDesc">
<![CDATA[
Definerer en del af din skabelon som en navngivet sektion, ved at
omkranse den i <code>@section { ... }</code>. Herefter kan denne sektion flettes ind i
overliggende skabelon ved at indsætte et <code>@RenderSection</code> element.
]]>
</key>
<key alias="renderSection">Indsæt en sektion</key>
<key alias="renderSectionDesc">
<![CDATA[
Henter indholdet af en sektion fra den underliggende skabelon ind, ved at indsætte et
<code>@RenderSection(name)</code> element. Den underliggende skabelon skal have
defineret en sektion via et <code>@section [name]{ ... }</code> element.
]]>
</key>
<key alias="sectionName">Sektionsnavn</key>
<key alias="sectionMandatory">Sektionen er obligatorisk</key>
<key alias="sectionMandatoryDesc">
Hvis obligatorisk, skal underskabelonen indeholde en <code>@section</code> -definition.
</key>
<key alias="queryBuilder">Query builder</key>
<key alias="itemsReturned">sider returneret, på</key>
<key alias="iWant">Returner</key>
<key alias="allContent">alt indhold</key>
<key alias="contentOfType">indhold af typen &quot;%0%&quot;</key>
<key alias="from">fra</key>
<key alias="websiteRoot">mit website</key>
<key alias="where">hvor</key>
<key alias="and">og</key>
<key alias="is">er</key>
<key alias="isNot">ikke er</key>
<key alias="before">er før</key>
<key alias="beforeIncDate">er før (inkl. valgte dato)</key>
<key alias="after">er efter</key>
<key alias="afterIncDate">er efter (inkl. valgte dato)</key>
<key alias="equals">er</key>
<key alias="doesNotEqual">ikke er</key>
<key alias="contains">indeholder</key>
<key alias="doesNotContain">ikke indeholder</key>
<key alias="greaterThan">er større end</key>
<key alias="greaterThanEqual">er større end eller det samme som</key>
<key alias="lessThan">er mindre end</key>
<key alias="lessThanEqual">er mindre end eller det samme som</key>
<key alias="id">Id</key>
<key alias="name">Navn</key>
<key alias="createdDate">Oprettelsesdato</key>
<key alias="lastUpdatedDate">Sidste opdatering</key>
<key alias="orderBy">Sortér efter</key>
<key alias="ascending">stigende rækkefølge</key>
<key alias="descending">faldende rækkefølge</key>
<key alias="template">Skabelon</key>
</area>
<area alias="templateEditor">
<key alias="alternativeField">Alternativt felt</key>
<key alias="alternativeText">Alternativ tekst</key>
+67 -2
View File
@@ -305,6 +305,7 @@
<key alias="selectMemberGroup">Select member group</key>
<key alias="noIconsFound">No icons were found</key>
<key alias="noMacroParams">There are no parameters for this macro</key>
<key alias="noMacros">There are no macros available to insert</key>
<key alias="externalLoginProviders">External login providers</key>
<key alias="exceptionDetail">Exception Details</key>
<key alias="stacktrace">Stacktrace</key>
@@ -1032,6 +1033,9 @@ To manage your website, simply open the Umbraco back office and start adding con
<key alias="insertSections">Sections</key>
<key alias="insertContentArea">Insert content area</key>
<key alias="insertContentAreaPlaceHolder">Insert content area placeholder</key>
<key alias="insert">Insert</key>
<key alias="insertDesc">Choose what to insert into your template</key>
<key alias="insertDictionaryItem">Dictionary item</key>
<key alias="insertDictionaryItemDesc">A dictionary item is a placeholder for a translatable piece of text, which makes it easy to create designs for multilingual websites.</key>
@@ -1053,18 +1057,79 @@ To manage your website, simply open the Umbraco back office and start adding con
</key>
<key alias="mastertemplate">Master template</key>
<key alias="noMastertemplate">No master template</key>
<key alias="noMaster">No master</key>
<key alias="renderBody">Render child template</key>
<key alias="renderBodyDesc">
<![CDATA[
Renders the contents of a child template, by inserting a
<code>@RenderBody()</code> placeholder.
]]>
</key>
<key alias="defineSection">Define a named section</key>
<key alias="defineSectionDesc">
<![CDATA[
Defines a part of your template as a named section by wrapping it in
<code>@section { ... }</code>. This can be rendered in a
specific area of the parent of this template, by using <code>@RenderSection</code>.
]]>
</key>
<key alias="renderSection">Render a named section</key>
<key alias="renderSectionDesc">
<![CDATA[
Renders a named area of a child template, by inserting a <code>@RenderSection(name)</code> placeholder.
This renders an area of a child template which is wrapped in a corresponding <code>@section [name]{ ... }</code> definition.
]]>
</key>
<key alias="sectionName">Section Name</key>
<key alias="sectionMandatory">Section is mandatory</key>
<key alias="sectionMandatoryDesc">
If mandatory, the child template must contain a <code>@section</code> definition, otherwise an error is shown.
</key>
<key alias="queryBuilder">Query builder</key>
<key alias="itemsReturned">items returned, in</key>
<key alias="iWant">I want</key>
<key alias="iWant">I want</key>
<key alias="allContent">all content</key>
<key alias="contentOfType">content of type &quot;%0%&quot;</key>
<key alias="from">from</key>
<key alias="websiteRoot">my website</key>
<key alias="where">where</key>
<key alias="and">and</key>
<key alias="everything">everything</key>
<key alias="is">is</key>
<key alias="isNot">is not</key>
<key alias="before">before</key>
<key alias="beforeIncDate">before (including selected date)</key>
<key alias="after">after</key>
<key alias="afterIncDate">after (including selected date)</key>
<key alias="equals">equals</key>
<key alias="doesNotEqual">does not equal</key>
<key alias="contains">contains</key>
<key alias="doesNotContain">does not contain</key>
<key alias="greaterThan">greater than</key>
<key alias="greaterThanEqual">greater than or equal to</key>
<key alias="lessThan">less than</key>
<key alias="lessThanEqual">less than or equal to</key>
<key alias="id">Id</key>
<key alias="name">Name</key>
<key alias="createdDate">Created Date</key>
<key alias="lastUpdatedDate">Last Updated Date</key>
<key alias="orderBy">order by</key>
<key alias="ascending">ascending</key>
<key alias="descending">descending</key>
<key alias="template">Template</key>
</area>
<area alias="grid">
@@ -1027,13 +1027,105 @@ To manage your website, simply open the Umbraco back office and start adding con
</area>
<area alias="template">
<key alias="edittemplate">Edit template</key>
<key alias="insertSections">Sections</key>
<key alias="insertContentArea">Insert content area</key>
<key alias="insertContentAreaPlaceHolder">Insert content area placeholder</key>
<key alias="insertDictionaryItem">Insert dictionary item</key>
<key alias="insertMacro">Insert Macro</key>
<key alias="insertPageField">Insert Umbraco page field</key>
<key alias="insert">Insert</key>
<key alias="insertDesc">Choose what to insert into your template</key>
<key alias="insertDictionaryItem">Dictionary item</key>
<key alias="insertDictionaryItemDesc">A dictionary item is a placeholder for a translatable piece of text, which makes it easy to create designs for multilingual websites.</key>
<key alias="insertMacro">Macro</key>
<key alias="insertMacroDesc">
A Macro is a configurable component which is great for
reusable parts of your design, where you need the option to provide parameters,
such as galleries, forms and lists.
</key>
<key alias="insertPageField">Value</key>
<key alias="insertPageFieldDesc">Displays the value of a named field from the current page, with options to modify the value or fallback to alternative values.</key>
<key alias="insertPartialView">Partial view</key>
<key alias="insertPartialViewDesc">
A partial view is a separate template file which can be rendered inside another
template, it's great for reusing markup or for separating complex templates into separate files.
</key>
<key alias="mastertemplate">Master template</key>
<key alias="quickGuide">Quick Guide to Umbraco template tags</key>
<key alias="noMastertemplate">No master template</key>
<key alias="noMaster">No master</key>
<key alias="renderBody">Render child template</key>
<key alias="renderBodyDesc">
<![CDATA[
Renders the contents of a child template, by inserting a
<code>@RenderBody()</code> placeholder.
]]>
</key>
<key alias="defineSection">Define a named section</key>
<key alias="defineSectionDesc">
<![CDATA[
Defines a part of your template as a named section by wrapping it in
<code>@section { ... }</code>. This can be rendered in a
specific area of the parent of this template, by using <code>@RenderSection</code>.
]]>
</key>
<key alias="renderSection">Render a named section</key>
<key alias="renderSectionDesc">
<![CDATA[
Renders a named area of a child template, by inserting a <code>@RenderSection(name)</code> placeholder.
This renders an area of a child template which is wrapped in a corresponding <code>@section [name]{ ... }</code> definition.
]]>
</key>
<key alias="sectionName">Section Name</key>
<key alias="sectionMandatory">Section is mandatory</key>
<key alias="sectionMandatoryDesc">
If mandatory, the child template must contain a <code>@section</code> definition, otherwise an error is shown.
</key>
<key alias="queryBuilder">Query builder</key>
<key alias="itemsReturned">items returned, in</key>
<key alias="iWant">I want</key>
<key alias="allContent">all content</key>
<key alias="contentOfType">content of type &quot;%0%&quot;</key>
<key alias="from">from</key>
<key alias="websiteRoot">my website</key>
<key alias="where">where</key>
<key alias="and">and</key>
<key alias="is">is</key>
<key alias="isNot">is not</key>
<key alias="before">before</key>
<key alias="beforeIncDate">before (including selected date)</key>
<key alias="after">after</key>
<key alias="afterIncDate">after (including selected date)</key>
<key alias="equals">equals</key>
<key alias="doesNotEqual">does not equal</key>
<key alias="contains">contains</key>
<key alias="doesNotContain">does not contain</key>
<key alias="greaterThan">greater than</key>
<key alias="greaterThanEqual">greater than or equal to</key>
<key alias="lessThan">less than</key>
<key alias="lessThanEqual">less than or equal to</key>
<key alias="id">Id</key>
<key alias="name">Name</key>
<key alias="createdDate">Created Date</key>
<key alias="lastUpdatedDate">Last Updated Date</key>
<key alias="orderBy">order by</key>
<key alias="ascending">ascending</key>
<key alias="descending">descending</key>
<key alias="template">Template</key>
</area>
<area alias="grid">
@@ -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();
+70 -33
View File
@@ -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>
+52 -17
View File
@@ -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;
}
}
}
}
@@ -9,6 +9,7 @@ using System;
using System.Diagnostics;
using Umbraco.Web.Dynamics;
using Umbraco.Web.Models.TemplateQuery;
using Umbraco.Core.Services;
namespace Umbraco.Web.Editors
{
@@ -29,33 +30,44 @@ namespace Umbraco.Web.Editors
{ }
private static readonly IEnumerable<OperathorTerm> Terms = new List<OperathorTerm>()
private IEnumerable<OperathorTerm> Terms
{
get
{
new OperathorTerm("is", Operathor.Equals, new [] {"string"}),
new OperathorTerm("is not", Operathor.NotEquals, new [] {"string"}),
new OperathorTerm("before", Operathor.LessThan, new [] {"datetime"}),
new OperathorTerm("before (including selected date)", Operathor.LessThanEqualTo, new [] {"datetime"}),
new OperathorTerm("after", Operathor.GreaterThan, new [] {"datetime"}),
new OperathorTerm("after (including selected date)", Operathor.GreaterThanEqualTo, new [] {"datetime"}),
new OperathorTerm("equals", Operathor.Equals, new [] {"int"}),
new OperathorTerm("does not equal", Operathor.NotEquals, new [] {"int"}),
new OperathorTerm("contains", Operathor.Contains, new [] {"string"}),
new OperathorTerm("does not contain", Operathor.NotContains, new [] {"string"}),
new OperathorTerm("greater than", Operathor.GreaterThan, new [] {"int"}),
new OperathorTerm("greater than or equal to", Operathor.GreaterThanEqualTo, new [] {"int"}),
new OperathorTerm("less than", Operathor.LessThan, new [] {"int"}),
new OperathorTerm("less than or equal to", Operathor.LessThanEqualTo, new [] {"int"})
};
return new List<OperathorTerm>()
{
new OperathorTerm(Services.TextService.Localize("template/is"), Operathor.Equals, new [] {"string"}),
new OperathorTerm(Services.TextService.Localize("template/isNot"), Operathor.NotEquals, new [] {"string"}),
new OperathorTerm(Services.TextService.Localize("template/before"), Operathor.LessThan, new [] {"datetime"}),
new OperathorTerm(Services.TextService.Localize("template/beforeIncDate"), Operathor.LessThanEqualTo, new [] {"datetime"}),
new OperathorTerm(Services.TextService.Localize("template/after"), Operathor.GreaterThan, new [] {"datetime"}),
new OperathorTerm(Services.TextService.Localize("template/afterIncDate"), Operathor.GreaterThanEqualTo, new [] {"datetime"}),
new OperathorTerm(Services.TextService.Localize("template/equals"), Operathor.Equals, new [] {"int"}),
new OperathorTerm(Services.TextService.Localize("template/doesNotEqual"), Operathor.NotEquals, new [] {"int"}),
new OperathorTerm(Services.TextService.Localize("template/contains"), Operathor.Contains, new [] {"string"}),
new OperathorTerm(Services.TextService.Localize("template/doesNotContain"), Operathor.NotContains, new [] {"string"}),
new OperathorTerm(Services.TextService.Localize("template/greaterThan"), Operathor.GreaterThan, new [] {"int"}),
new OperathorTerm(Services.TextService.Localize("template/greaterThanEqual"), Operathor.GreaterThanEqualTo, new [] {"int"}),
new OperathorTerm(Services.TextService.Localize("template/lessThan"), Operathor.LessThan, new [] {"int"}),
new OperathorTerm(Services.TextService.Localize("template/lessThanEqual"), Operathor.LessThanEqualTo, new [] {"int"})
};
}
}
private static readonly IEnumerable<PropertyModel> Properties = new List<PropertyModel>()
private IEnumerable<PropertyModel> Properties
{
get
{
new PropertyModel() { Name = "Id", Alias = "Id", Type = "int" },
new PropertyModel() { Name = "Name", Alias = "Name", Type = "string" },
//new PropertyModel() { Name = "Url", Alias = "url", Type = "string" },
new PropertyModel() { Name = "Created Date", Alias = "CreateDate", Type = "datetime" },
new PropertyModel() { Name = "Last Updated Date", Alias = "UpdateDate", Type = "datetime" }
};
return new List<PropertyModel>()
{
new PropertyModel() {Name = Services.TextService.Localize("template/id"), Alias = "Id", Type = "int"},
new PropertyModel() {Name = Services.TextService.Localize("template/name"), Alias = "Name", Type = "string"},
//new PropertyModel() { Name = "Url", Alias = "url", Type = "string" },
new PropertyModel() {Name = Services.TextService.Localize("template/createdDate"), Alias = "CreateDate", Type = "datetime"},
new PropertyModel() {Name = Services.TextService.Localize("template/lastUpdatedDate"), Alias = "UpdateDate", Type = "datetime"}
};
}
}
public QueryResultModel PostTemplateQuery(QueryModel model)
{
@@ -297,9 +309,10 @@ namespace Umbraco.Web.Editors
{
var contentTypes =
ApplicationContext.Services.ContentTypeService.GetAllContentTypes()
.Select(x => new ContentTypeModel() { Alias = x.Alias, Name = x.Name })
.Select(x => new ContentTypeModel() { Alias = x.Alias, Name = Services.TextService.Localize("template/contentOfType", tokens: new string[] { x.Name } ) })
.OrderBy(x => x.Name).ToList();
contentTypes.Insert(0, new ContentTypeModel() { Alias = string.Empty, Name = "Everything" });
contentTypes.Insert(0, new ContentTypeModel() { Alias = string.Empty, Name = Services.TextService.Localize("template/allContent") });
return contentTypes;
}
@@ -228,12 +228,13 @@ namespace Umbraco.Web
bool cacheBuster = true,
string furtherOptions = null,
ImageCropRatioMode? ratioMode = null,
bool upScale = true)
bool upScale = true,
string backgroundColor = null)
{
return
new HtmlString(mediaItem.GetCropUrl(width, height, propertyAlias, cropAlias, quality, imageCropMode,
imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBuster, furtherOptions, ratioMode,
upScale));
upScale, backgroundColor));
}
[Obsolete("Use the UrlHelper.GetCropUrl extension instead")]
@@ -252,12 +253,13 @@ namespace Umbraco.Web
string cacheBusterValue = null,
string furtherOptions = null,
ImageCropRatioMode? ratioMode = null,
bool upScale = true)
bool upScale = true,
string backgroundColor = null)
{
return
new HtmlString(imageUrl.GetCropUrl(width, height, imageCropperValue, cropAlias, quality, imageCropMode,
imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBusterValue, furtherOptions, ratioMode,
upScale));
upScale, backgroundColor));
}
#endregion
@@ -91,10 +91,13 @@ namespace Umbraco.Web
/// </param>
/// <param name="ratioMode">
/// Use a dimension as a ratio
/// </param>
/// </param>
/// <param name="upScale">
/// If the image should be upscaled to requested dimensions
/// </param>
/// </param>
/// <param name="backgroundColor">
/// Changes the background color of the image. Used when adding a background when resizing image formats without an alpha channel.
/// </param>
/// <returns>
/// The <see cref="string"/>.
/// </returns>
@@ -112,7 +115,8 @@ namespace Umbraco.Web
bool cacheBuster = true,
string furtherOptions = null,
ImageCropRatioMode? ratioMode = null,
bool upScale = true)
bool upScale = true,
string backgroundColor = null)
{
if (mediaItem == null) throw new ArgumentNullException("mediaItem");
@@ -132,7 +136,7 @@ namespace Umbraco.Web
mediaItemUrl = stronglyTyped.Src;
return GetCropUrl(
mediaItemUrl, stronglyTyped, width, height, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions,
cacheBusterValue, furtherOptions, ratioMode, upScale);
cacheBusterValue, furtherOptions, ratioMode, upScale, backgroundColor);
}
//this shouldn't be the case but we'll check
@@ -143,14 +147,14 @@ namespace Umbraco.Web
mediaItemUrl = stronglyTyped.Src;
return GetCropUrl(
mediaItemUrl, stronglyTyped, width, height, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions,
cacheBusterValue, furtherOptions, ratioMode, upScale);
cacheBusterValue, furtherOptions, ratioMode, upScale, backgroundColor);
}
//it's a single string
mediaItemUrl = cropperValue.ToString();
return GetCropUrl(
mediaItemUrl, width, height, mediaItemUrl, cropAlias, quality, imageCropMode, imageCropAnchor, preferFocalPoint, useCropDimensions,
cacheBusterValue, furtherOptions, ratioMode, upScale);
cacheBusterValue, furtherOptions, ratioMode, upScale, backgroundColor);
}
/// <summary>
@@ -198,6 +202,9 @@ namespace Umbraco.Web
/// <param name="upScale">
/// If the image should be upscaled to requested dimensions
/// </param>
/// <param name="backgroundColor">
/// Changes the background color of the image. Used when adding a background when resizing image formats without an alpha channel.
/// </param>
/// <returns>
/// The <see cref="string"/>.
/// </returns>
@@ -215,7 +222,8 @@ namespace Umbraco.Web
string cacheBusterValue = null,
string furtherOptions = null,
ImageCropRatioMode? ratioMode = null,
bool upScale = true)
bool upScale = true,
string backgroundColor = null)
{
if (string.IsNullOrEmpty(imageUrl)) return string.Empty;
@@ -226,7 +234,7 @@ namespace Umbraco.Web
}
return GetCropUrl(
imageUrl, cropDataSet, width, height, cropAlias, quality, imageCropMode,
imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBusterValue, furtherOptions, ratioMode, upScale);
imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBusterValue, furtherOptions, ratioMode, upScale, backgroundColor);
}
public static string GetCropUrl(
@@ -243,7 +251,8 @@ namespace Umbraco.Web
string cacheBusterValue = null,
string furtherOptions = null,
ImageCropRatioMode? ratioMode = null,
bool upScale = true)
bool upScale = true,
string backgroundColor = null)
{
if (string.IsNullOrEmpty(imageUrl) == false)
{
@@ -350,6 +359,11 @@ namespace Umbraco.Web
imageProcessorUrl.Append("&upscale=false");
}
if (backgroundColor != null)
{
imageProcessorUrl.Append("&bgcolor=" + backgroundColor);
}
if (furtherOptions != null)
{
imageProcessorUrl.Append(furtherOptions);
@@ -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; }
}
}
@@ -36,6 +36,9 @@ namespace Umbraco.Web.Models.ContentEditing
[DataMember(Name = "masterTemplateAlias")]
public string MasterTemplateAlias { get; set; }
[DataMember(Name = "isMasterTemplate")]
public bool IsMasterTemplate { get; set; }
/// <summary>
/// This is used to add custom localized messages/strings to the response for the app to use for localized UI purposes.
/// </summary>
@@ -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);";
}
}
}
-88
View File
@@ -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);
}
}
}
+7 -2
View File
@@ -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" />
+12 -6
View File
@@ -114,6 +114,9 @@ namespace Umbraco.Web
/// Whether to HTML encode this URL - default is true - w3c standards require html attributes to be html encoded but this can be
/// set to false if using the result of this method for CSS.
/// </param>
/// <param name="backgroundColor">
/// Changes the background color of the image. Used when adding a background when resizing image formats without an alpha channel.
/// </param>
/// <returns>
/// The <see cref="string"/>.
/// </returns>
@@ -132,11 +135,12 @@ namespace Umbraco.Web
string furtherOptions = null,
ImageCropRatioMode? ratioMode = null,
bool upScale = true,
bool htmlEncode = true)
bool htmlEncode = true,
string backgroundColor = null)
{
var url = mediaItem.GetCropUrl(width, height, propertyAlias, cropAlias, quality, imageCropMode,
imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBuster, furtherOptions, ratioMode,
upScale);
upScale, backgroundColor);
return htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url);
}
@@ -190,6 +194,9 @@ namespace Umbraco.Web
/// Whether to HTML encode this URL - default is true - w3c standards require html attributes to be html encoded but this can be
/// set to false if using the result of this method for CSS.
/// </param>
/// <param name="backgroundColor">
/// Changes the background color of the image. Used when adding a background when resizing image formats without an alpha channel.
/// </param>
/// <returns>
/// The <see cref="string"/>.
/// </returns>
@@ -208,11 +215,12 @@ namespace Umbraco.Web
string furtherOptions = null,
ImageCropRatioMode? ratioMode = null,
bool upScale = true,
bool htmlEncode = true)
bool htmlEncode = true,
string backgroundColor = null)
{
var url = imageUrl.GetCropUrl(width, height, imageCropperValue, cropAlias, quality, imageCropMode,
imageCropAnchor, preferFocalPoint, useCropDimensions, cacheBusterValue, furtherOptions, ratioMode,
upScale);
upScale, backgroundColor);
return htmlEncode ? new HtmlString(HttpUtility.HtmlEncode(url)) : new HtmlString(url);
}
@@ -333,7 +341,5 @@ namespace Umbraco.Web
{
return url.SurfaceAction(action, typeof (T), additionalRouteVals);
}
}
}