Merge branch 'v10/dev' into v10/contrib
This commit is contained in:
@@ -305,7 +305,7 @@ stages:
|
||||
- powershell: sqllocaldb start mssqllocaldb
|
||||
displayName: Start localdb (Windows only)
|
||||
condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
|
||||
- powershell: docker run --name mssql -d -p 1433:1433 -e ACCEPT_EULA=Y -e SA_PASSWORD=$(SA_PASSWORD) -e MSSQL_PID=Developer mcr.microsoft.com/mssql/server:2019-latest
|
||||
- powershell: docker run --name mssql -d -p 1433:1433 -e ACCEPT_EULA=Y -e SA_PASSWORD=$(SA_PASSWORD) -e MSSQL_PID=Developer mcr.microsoft.com/mssql/server:2019-latest
|
||||
displayName: Start SQL Server (Linux only)
|
||||
condition: and(succeeded(), eq(variables['Agent.OS'], 'Linux'))
|
||||
- task: DotNetCoreCLI@2
|
||||
@@ -494,7 +494,6 @@ stages:
|
||||
displayName: NuGet release
|
||||
dependsOn:
|
||||
- Deploy_MyGet
|
||||
- Build_Docs
|
||||
condition: and(succeeded(), or(startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'), ${{parameters.nuGetDeploy}}))
|
||||
jobs:
|
||||
- job:
|
||||
@@ -523,6 +522,7 @@ stages:
|
||||
dependsOn:
|
||||
- Build
|
||||
- Deploy_NuGet
|
||||
- Build_Docs
|
||||
condition: and(succeeded(), or(startsWith(variables['Build.SourceBranch'], 'refs/heads/release/'), ${{parameters.uploadApiDocs}}))
|
||||
jobs:
|
||||
- job:
|
||||
|
||||
@@ -1630,6 +1630,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont
|
||||
<key alias="tabRules">Editor</key>
|
||||
</area>
|
||||
<area alias="template">
|
||||
<key alias="runtimeModeProduction"><![CDATA[Content is not editable when using runtime mode <code>Production</code>.]]></key>
|
||||
<key alias="deleteByIdFailed">Failed to delete template with ID %0%</key>
|
||||
<key alias="edittemplate">Edit template</key>
|
||||
<key alias="insertSections">Sections</key>
|
||||
|
||||
@@ -1683,6 +1683,7 @@ To manage your website, simply open the Umbraco backoffice and start adding cont
|
||||
<key alias="tabRules">Rich Text Editor</key>
|
||||
</area>
|
||||
<area alias="template">
|
||||
<key alias="runtimeModeProduction"><![CDATA[Content is not editable when using runtime mode <code>Production</code>.]]></key>
|
||||
<key alias="deleteByIdFailed">Failed to delete template with ID %0%</key>
|
||||
<key alias="edittemplate">Edit template</key>
|
||||
<key alias="insertSections">Sections</key>
|
||||
|
||||
@@ -1444,6 +1444,7 @@ Echter, Runway biedt een gemakkelijke basis om je snel op weg te helpen. Als je
|
||||
<key alias="tabRules">Rich Text Editor</key>
|
||||
</area>
|
||||
<area alias="template">
|
||||
<key alias="runtimeModeProduction"><![CDATA[Inhoud kan niet worden bewerkt in de runtime-modus <code>Production</code>.]]></key>
|
||||
<key alias="deleteByIdFailed">Kan sjabloon met ID %0% niet verwijderen</key>
|
||||
<key alias="edittemplate">Sjabloon aanpassen</key>
|
||||
<key alias="insertSections">Secties</key>
|
||||
|
||||
@@ -2,6 +2,7 @@ using Umbraco.Cms.Core.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Packaging;
|
||||
using Umbraco.Cms.Infrastructure.Persistence;
|
||||
using Umbraco.Cms.Infrastructure.Persistence.Mappers;
|
||||
using Umbraco.Cms.Infrastructure.Runtime;
|
||||
|
||||
namespace Umbraco.Extensions;
|
||||
|
||||
@@ -17,6 +18,10 @@ public static partial class UmbracoBuilderExtensions
|
||||
public static MapperCollectionBuilder? Mappers(this IUmbracoBuilder builder)
|
||||
=> builder.WithCollectionBuilder<MapperCollectionBuilder>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the NPoco mappers collection builder.
|
||||
/// </summary>
|
||||
/// <param name="builder">The builder.</param>
|
||||
public static NPocoMapperCollectionBuilder? NPocoMappers(this IUmbracoBuilder builder)
|
||||
=> builder.WithCollectionBuilder<NPocoMapperCollectionBuilder>();
|
||||
|
||||
@@ -26,4 +31,11 @@ public static partial class UmbracoBuilderExtensions
|
||||
/// <param name="builder">The builder.</param>
|
||||
public static PackageMigrationPlanCollectionBuilder? PackageMigrationPlans(this IUmbracoBuilder builder)
|
||||
=> builder.WithCollectionBuilder<PackageMigrationPlanCollectionBuilder>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the runtime mode validators collection builder.
|
||||
/// </summary>
|
||||
/// <param name="builder">The builder.</param>
|
||||
public static RuntimeModeValidatorCollectionBuilder RuntimeModeValidators(this IUmbracoBuilder builder)
|
||||
=> builder.WithCollectionBuilder<RuntimeModeValidatorCollectionBuilder>();
|
||||
}
|
||||
|
||||
@@ -86,11 +86,12 @@ public static partial class UmbracoBuilderExtensions
|
||||
|
||||
// Add runtime mode validation
|
||||
builder.Services.AddSingleton<IRuntimeModeValidationService, RuntimeModeValidationService>();
|
||||
builder.Services.AddTransient<IRuntimeModeValidator, JITOptimizerValidator>();
|
||||
builder.Services.AddTransient<IRuntimeModeValidator, UmbracoApplicationUrlValidator>();
|
||||
builder.Services.AddTransient<IRuntimeModeValidator, UseHttpsValidator>();
|
||||
builder.Services.AddTransient<IRuntimeModeValidator, RuntimeMinificationValidator>();
|
||||
builder.Services.AddTransient<IRuntimeModeValidator, ModelsBuilderModeValidator>();
|
||||
builder.RuntimeModeValidators()
|
||||
.Add<JITOptimizerValidator>()
|
||||
.Add<UmbracoApplicationUrlValidator>()
|
||||
.Add<UseHttpsValidator>()
|
||||
.Add<RuntimeMinificationValidator>()
|
||||
.Add<ModelsBuilderModeValidator>();
|
||||
|
||||
// composers
|
||||
builder
|
||||
|
||||
@@ -652,10 +652,13 @@ public class CreatedPackageSchemaRepository : ICreatedPackagesRepository
|
||||
// the media file path is different from the URL and is specifically
|
||||
// extracted using the property editor for this media file and the current media file system.
|
||||
Stream mediaStream = _mediaFileManager.GetFile(media, out var mediaFilePath);
|
||||
xmlMedia.Add(new XAttribute("mediaFilePath", mediaFilePath!));
|
||||
if (mediaFilePath is not null)
|
||||
{
|
||||
xmlMedia.Add(new XAttribute("mediaFilePath", mediaFilePath));
|
||||
|
||||
// add the stream to our outgoing stream
|
||||
mediaStreams.Add(mediaFilePath!, mediaStream);
|
||||
// add the stream to our outgoing stream
|
||||
mediaStreams.Add(mediaFilePath, mediaStream);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerable<IMedia> medias = _mediaService.GetByIds(definition.MediaUdis);
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using NPoco;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.IO;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
using Umbraco.Cms.Core.Models.Entities;
|
||||
@@ -24,17 +26,26 @@ internal class TemplateRepository : EntityRepositoryBase<int, ITemplate>, ITempl
|
||||
{
|
||||
private readonly IIOHelper _ioHelper;
|
||||
private readonly IShortStringHelper _shortStringHelper;
|
||||
private readonly IViewHelper _viewHelper;
|
||||
private readonly IFileSystem? _viewsFileSystem;
|
||||
private readonly IViewHelper _viewHelper;
|
||||
private readonly IOptionsMonitor<RuntimeSettings> _runtimeSettings;
|
||||
|
||||
public TemplateRepository(IScopeAccessor scopeAccessor, AppCaches cache, ILogger<TemplateRepository> logger,
|
||||
FileSystems fileSystems, IIOHelper ioHelper, IShortStringHelper shortStringHelper, IViewHelper viewHelper)
|
||||
public TemplateRepository(
|
||||
IScopeAccessor scopeAccessor,
|
||||
AppCaches cache,
|
||||
ILogger<TemplateRepository> logger,
|
||||
FileSystems fileSystems,
|
||||
IIOHelper ioHelper,
|
||||
IShortStringHelper shortStringHelper,
|
||||
IViewHelper viewHelper,
|
||||
IOptionsMonitor<RuntimeSettings> runtimeSettings)
|
||||
: base(scopeAccessor, cache, logger)
|
||||
{
|
||||
_ioHelper = ioHelper;
|
||||
_shortStringHelper = shortStringHelper;
|
||||
_viewsFileSystem = fileSystems.MvcViewsFileSystem;
|
||||
_viewHelper = viewHelper;
|
||||
_runtimeSettings = runtimeSettings;
|
||||
}
|
||||
|
||||
public Stream GetFileContentStream(string filepath)
|
||||
@@ -421,8 +432,12 @@ internal class TemplateRepository : EntityRepositoryBase<int, ITemplate>, ITempl
|
||||
template.Id = nodeDto.NodeId; //Set Id on entity to ensure an Id is set
|
||||
template.Path = nodeDto.Path;
|
||||
|
||||
//now do the file work
|
||||
SaveFile(template);
|
||||
// Only save file when not in production runtime mode
|
||||
if (_runtimeSettings.CurrentValue.Mode != RuntimeMode.Production)
|
||||
{
|
||||
//now do the file work
|
||||
SaveFile(template);
|
||||
}
|
||||
|
||||
template.ResetDirtyProperties();
|
||||
|
||||
@@ -476,8 +491,12 @@ internal class TemplateRepository : EntityRepositoryBase<int, ITemplate>, ITempl
|
||||
IEnumerable<IUmbracoEntity> axisDefs = GetAxisDefinitions(dto);
|
||||
template.IsMasterTemplate = axisDefs.Any(x => x.ParentId == dto.NodeId);
|
||||
|
||||
//now do the file work
|
||||
SaveFile((Template)entity, originalAlias);
|
||||
// Only save file when not in production runtime mode
|
||||
if (_runtimeSettings.CurrentValue.Mode != RuntimeMode.Production)
|
||||
{
|
||||
//now do the file work
|
||||
SaveFile((Template)entity, originalAlias);
|
||||
}
|
||||
|
||||
entity.ResetDirtyProperties();
|
||||
|
||||
|
||||
@@ -18,11 +18,11 @@ namespace Umbraco.Cms.Infrastructure;
|
||||
/// <seealso cref="Umbraco.Cms.Core.IPublishedContentQuery" />
|
||||
public class PublishedContentQuery : IPublishedContentQuery
|
||||
{
|
||||
private static readonly HashSet<string> _itemIdFieldNameHashSet = new() {ExamineFieldNames.ItemIdFieldName};
|
||||
|
||||
private readonly IExamineManager _examineManager;
|
||||
private readonly IPublishedSnapshot _publishedSnapshot;
|
||||
private readonly IVariationContextAccessor _variationContextAccessor;
|
||||
private static readonly HashSet<string> _returnedQueryFields =
|
||||
new() { ExamineFieldNames.ItemIdFieldName, ExamineFieldNames.CategoryFieldName };
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PublishedContentQuery" /> class.
|
||||
@@ -293,8 +293,8 @@ public class PublishedContentQuery : IPublishedContentQuery
|
||||
ordering = query.ManagedQuery(term, fields);
|
||||
}
|
||||
|
||||
// Only select item ID field, because results are loaded from the published snapshot based on this single value
|
||||
IOrdering? queryExecutor = ordering.SelectFields(_itemIdFieldNameHashSet);
|
||||
// Filter selected fields because results are loaded from the published snapshot based on these
|
||||
IOrdering? queryExecutor = ordering.SelectFields(_returnedQueryFields);
|
||||
|
||||
|
||||
ISearchResults? results = skip == 0 && take == 0
|
||||
@@ -328,8 +328,8 @@ public class PublishedContentQuery : IPublishedContentQuery
|
||||
|
||||
if (query is IOrdering ordering)
|
||||
{
|
||||
// Only select item ID field, because results are loaded from the published snapshot based on this single value
|
||||
query = ordering.SelectFields(_itemIdFieldNameHashSet);
|
||||
// Filter selected fields because results are loaded from the published snapshot based on these
|
||||
query = ordering.SelectFields(_returnedQueryFields);
|
||||
}
|
||||
|
||||
ISearchResults? results = skip == 0 && take == 0
|
||||
|
||||
@@ -29,11 +29,18 @@ internal class RuntimeModeValidationService : IRuntimeModeValidationService
|
||||
var validationMessages = new List<string>();
|
||||
|
||||
// Runtime mode validators are registered transient, but this service is registered as singleton
|
||||
foreach (var runtimeModeValidator in _serviceProvider.GetServices<IRuntimeModeValidator>())
|
||||
using (var scope = _serviceProvider.CreateScope())
|
||||
{
|
||||
if (runtimeModeValidator.Validate(runtimeMode, out var validationMessage) == false)
|
||||
var runtimeModeValidators = scope.ServiceProvider.GetService<RuntimeModeValidatorCollection>();
|
||||
if (runtimeModeValidators is not null)
|
||||
{
|
||||
validationMessages.Add(validationMessage);
|
||||
foreach (var runtimeModeValidator in runtimeModeValidators)
|
||||
{
|
||||
if (runtimeModeValidator.Validate(runtimeMode, out var validationMessage) == false)
|
||||
{
|
||||
validationMessages.Add(validationMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
using Umbraco.Cms.Core.Composing;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Runtime;
|
||||
|
||||
public class RuntimeModeValidatorCollection : BuilderCollectionBase<IRuntimeModeValidator>
|
||||
{
|
||||
public RuntimeModeValidatorCollection(Func<IEnumerable<IRuntimeModeValidator>> items)
|
||||
: base(items)
|
||||
{ }
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Cms.Core.Composing;
|
||||
|
||||
namespace Umbraco.Cms.Infrastructure.Runtime;
|
||||
|
||||
public class RuntimeModeValidatorCollectionBuilder : SetCollectionBuilderBase<RuntimeModeValidatorCollectionBuilder, RuntimeModeValidatorCollection, IRuntimeModeValidator>
|
||||
{
|
||||
protected override ServiceLifetime CollectionLifetime => ServiceLifetime.Transient;
|
||||
|
||||
protected override RuntimeModeValidatorCollectionBuilder This => this;
|
||||
}
|
||||
@@ -597,7 +597,7 @@ namespace Umbraco.Cms.Web.BackOffice.Controllers
|
||||
{ "assemblyVersion", _umbracoVersion.AssemblyVersion?.ToString() }
|
||||
};
|
||||
|
||||
|
||||
app.Add("runtimeMode", _runtimeSettings.Mode.ToString());
|
||||
|
||||
//the value is the hash of the version, cdf version and the configured state
|
||||
app.Add("cacheBuster", $"{version}.{_runtimeState.Level}.{_runtimeMinifier.CacheBuster}".GenerateHash());
|
||||
|
||||
@@ -20,6 +20,8 @@ using Umbraco.Extensions;
|
||||
using Umbraco.Cms.Infrastructure.Packaging;
|
||||
using System.Xml.Linq;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Umbraco.Cms.Web.Common.DependencyInjection;
|
||||
|
||||
namespace Umbraco.Cms.Web.BackOffice.Controllers;
|
||||
|
||||
@@ -47,6 +49,7 @@ public class DictionaryController : BackOfficeNotificationsController
|
||||
private readonly IHostingEnvironment _hostingEnvironment;
|
||||
private readonly PackageDataInstallation _packageDataInstallation;
|
||||
|
||||
[ActivatorUtilitiesConstructor]
|
||||
public DictionaryController(
|
||||
ILogger<DictionaryController> logger,
|
||||
ILocalizationService localizationService,
|
||||
@@ -60,8 +63,7 @@ public class DictionaryController : BackOfficeNotificationsController
|
||||
{
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
_localizationService = localizationService ?? throw new ArgumentNullException(nameof(localizationService));
|
||||
_backofficeSecurityAccessor = backofficeSecurityAccessor ??
|
||||
throw new ArgumentNullException(nameof(backofficeSecurityAccessor));
|
||||
_backofficeSecurityAccessor = backofficeSecurityAccessor ?? throw new ArgumentNullException(nameof(backofficeSecurityAccessor));
|
||||
_globalSettings = globalSettings.Value ?? throw new ArgumentNullException(nameof(globalSettings));
|
||||
_localizedTextService = localizedTextService ?? throw new ArgumentNullException(nameof(localizedTextService));
|
||||
_umbracoMapper = umbracoMapper ?? throw new ArgumentNullException(nameof(umbracoMapper));
|
||||
@@ -70,6 +72,27 @@ public class DictionaryController : BackOfficeNotificationsController
|
||||
_packageDataInstallation = packageDataInstallation ?? throw new ArgumentNullException(nameof(packageDataInstallation));
|
||||
}
|
||||
|
||||
[Obsolete("Please use ctor that also takes an IEntityXmlSerializer, IHostingEnvironment & PackageDataInstallation instead, scheduled for removal in v12")]
|
||||
public DictionaryController(
|
||||
ILogger<DictionaryController> logger,
|
||||
ILocalizationService localizationService,
|
||||
IBackOfficeSecurityAccessor backofficeSecurityAccessor,
|
||||
IOptionsSnapshot<GlobalSettings> globalSettings,
|
||||
ILocalizedTextService localizedTextService,
|
||||
IUmbracoMapper umbracoMapper)
|
||||
: this(
|
||||
logger,
|
||||
localizationService,
|
||||
backofficeSecurityAccessor,
|
||||
globalSettings,
|
||||
localizedTextService,
|
||||
umbracoMapper,
|
||||
StaticServiceProvider.Instance.GetRequiredService<IEntityXmlSerializer>(),
|
||||
StaticServiceProvider.Instance.GetRequiredService<IHostingEnvironment>(),
|
||||
StaticServiceProvider.Instance.GetRequiredService<PackageDataInstallation>())
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a data type with a given ID
|
||||
/// </summary>
|
||||
|
||||
@@ -180,10 +180,10 @@ public class ContentTypeTreeController : TreeController, ISearchableTree
|
||||
|
||||
menu.Items.Add<ActionNew>(LocalizedTextService, opensDialog: true, useLegacyIcon: false);
|
||||
|
||||
//no move action if this is a child doc type
|
||||
// No move action if this is a child doc type
|
||||
if (parent == null)
|
||||
{
|
||||
menu.Items.Add<ActionDelete>(LocalizedTextService, hasSeparator: true, opensDialog: true, useLegacyIcon: false);
|
||||
menu.Items.Add<ActionMove>(LocalizedTextService, hasSeparator: true, opensDialog: true, useLegacyIcon: false);
|
||||
}
|
||||
|
||||
menu.Items.Add<ActionCopy>(LocalizedTextService, opensDialog: true, useLegacyIcon: false);
|
||||
|
||||
@@ -1,362 +1,367 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
function partialViewMacrosEditController($scope, $routeParams, codefileResource, assetsService, notificationsService, editorState, navigationService, appState, macroService, angularHelper, $timeout, contentEditingHelper, localizationService, templateHelper, macroResource, editorService) {
|
||||
function partialViewMacrosEditController($scope, $routeParams, codefileResource, assetsService, notificationsService, editorState, navigationService, appState, macroService, angularHelper, $timeout, contentEditingHelper, localizationService, templateHelper, macroResource, editorService) {
|
||||
|
||||
var vm = this;
|
||||
var vm = this;
|
||||
|
||||
vm.header = {};
|
||||
vm.header.editorfor = "visuallyHiddenTexts_newPartialViewMacro";
|
||||
vm.header.setPageTitle = true;
|
||||
vm.page = {};
|
||||
vm.page.loading = true;
|
||||
vm.partialViewMacroFile = {};
|
||||
vm.runtimeModeProduction = Umbraco.Sys.ServerVariables.application.runtimeMode == 'Production';
|
||||
|
||||
//menu
|
||||
vm.page.menu = {};
|
||||
vm.page.menu.currentSection = appState.getSectionState("currentSection");
|
||||
vm.page.menu.currentNode = null;
|
||||
vm.header = {};
|
||||
vm.header.editorfor = "visuallyHiddenTexts_newPartialViewMacro";
|
||||
vm.header.setPageTitle = true;
|
||||
vm.page = {};
|
||||
vm.page.loading = true;
|
||||
vm.partialViewMacroFile = {};
|
||||
|
||||
// insert buttons
|
||||
vm.page.insertDefaultButton = {
|
||||
labelKey: "general_insert",
|
||||
addEllipsis: "true",
|
||||
handler: function() {
|
||||
vm.openInsertOverlay();
|
||||
}
|
||||
};
|
||||
vm.page.insertSubButtons = [
|
||||
{
|
||||
labelKey: "template_insertPageField",
|
||||
addEllipsis: "true",
|
||||
handler: function () {
|
||||
vm.openPageFieldOverlay();
|
||||
}
|
||||
},
|
||||
{
|
||||
labelKey: "template_insertMacro",
|
||||
addEllipsis: "true",
|
||||
handler: function () {
|
||||
vm.openMacroOverlay()
|
||||
}
|
||||
},
|
||||
{
|
||||
labelKey: "template_insertDictionaryItem",
|
||||
addEllipsis: "true",
|
||||
handler: function () {
|
||||
vm.openDictionaryItemOverlay();
|
||||
}
|
||||
}
|
||||
];
|
||||
//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;
|
||||
// insert buttons
|
||||
vm.page.insertDefaultButton = {
|
||||
labelKey: "general_insert",
|
||||
addEllipsis: "true",
|
||||
handler: function () {
|
||||
vm.openInsertOverlay();
|
||||
}
|
||||
};
|
||||
vm.page.insertSubButtons = [
|
||||
{
|
||||
labelKey: "template_insertPageField",
|
||||
addEllipsis: "true",
|
||||
handler: function () {
|
||||
vm.openPageFieldOverlay();
|
||||
}
|
||||
},
|
||||
{
|
||||
labelKey: "template_insertMacro",
|
||||
addEllipsis: "true",
|
||||
handler: function () {
|
||||
vm.openMacroOverlay()
|
||||
}
|
||||
},
|
||||
{
|
||||
labelKey: "template_insertDictionaryItem",
|
||||
addEllipsis: "true",
|
||||
handler: function () {
|
||||
vm.openDictionaryItemOverlay();
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
/* Functions bound to view model */
|
||||
// bind functions to view model
|
||||
vm.save = save;
|
||||
vm.openPageFieldOverlay = openPageFieldOverlay;
|
||||
vm.openDictionaryItemOverlay = openDictionaryItemOverlay;
|
||||
vm.openQueryBuilderOverlay = openQueryBuilderOverlay;
|
||||
vm.openMacroOverlay = openMacroOverlay;
|
||||
vm.openInsertOverlay = openInsertOverlay;
|
||||
|
||||
function save() {
|
||||
/* Functions bound to view model */
|
||||
|
||||
vm.page.saveButtonState = "busy";
|
||||
vm.partialViewMacro.content = vm.editor.getValue();
|
||||
function save() {
|
||||
|
||||
contentEditingHelper.contentEditorPerformSave({
|
||||
saveMethod: codefileResource.save,
|
||||
scope: $scope,
|
||||
content: vm.partialViewMacro,
|
||||
rebindCallback: function (orignal, saved) {}
|
||||
}).then(function (saved) {
|
||||
// create macro if needed
|
||||
if($routeParams.create && $routeParams.nomacro !== "true") {
|
||||
macroResource.createPartialViewMacroWithFile(saved.virtualPath, saved.name).then(function (created) {
|
||||
navigationService.syncTree({
|
||||
tree: "macros",
|
||||
path: '-1,new',
|
||||
forceReload: true,
|
||||
activate: false
|
||||
});
|
||||
completeSave(saved);
|
||||
}, Utilities.noop);
|
||||
|
||||
|
||||
} else {
|
||||
completeSave(saved);
|
||||
}
|
||||
|
||||
}, function (err) {
|
||||
|
||||
vm.page.saveButtonState = "error";
|
||||
|
||||
localizationService.localize("speechBubbles_validationFailedHeader").then(function (headerValue) {
|
||||
localizationService.localize("speechBubbles_validationFailedMessage").then(function(msgValue) {
|
||||
notificationsService.error(headerValue, msgValue);
|
||||
});
|
||||
});
|
||||
vm.page.saveButtonState = "busy";
|
||||
vm.partialViewMacro.content = vm.editor.getValue();
|
||||
|
||||
contentEditingHelper.contentEditorPerformSave({
|
||||
saveMethod: codefileResource.save,
|
||||
scope: $scope,
|
||||
content: vm.partialViewMacro,
|
||||
rebindCallback: function (orignal, saved) { }
|
||||
}).then(function (saved) {
|
||||
// create macro if needed
|
||||
if ($routeParams.create && $routeParams.nomacro !== "true") {
|
||||
macroResource.createPartialViewMacroWithFile(saved.virtualPath, saved.name).then(function (created) {
|
||||
navigationService.syncTree({
|
||||
tree: "macros",
|
||||
path: '-1,new',
|
||||
forceReload: true,
|
||||
activate: false
|
||||
});
|
||||
completeSave(saved);
|
||||
}, Utilities.noop);
|
||||
|
||||
|
||||
} else {
|
||||
completeSave(saved);
|
||||
}
|
||||
|
||||
function completeSave(saved) {
|
||||
}, function (err) {
|
||||
|
||||
localizationService.localize("speechBubbles_partialViewSavedHeader").then(function (headerValue) {
|
||||
localizationService.localize("speechBubbles_partialViewSavedText").then(function (msgValue) {
|
||||
notificationsService.success(headerValue, msgValue);
|
||||
});
|
||||
});
|
||||
vm.page.saveButtonState = "error";
|
||||
|
||||
//check if the name changed, if so we need to redirect
|
||||
if (vm.partialViewMacro.id !== saved.id) {
|
||||
contentEditingHelper.redirectToRenamedContent(saved.id);
|
||||
}
|
||||
else {
|
||||
vm.page.saveButtonState = "success";
|
||||
vm.partialViewMacro = saved;
|
||||
localizationService.localize("speechBubbles_validationFailedHeader").then(function (headerValue) {
|
||||
localizationService.localize("speechBubbles_validationFailedMessage").then(function (msgValue) {
|
||||
notificationsService.error(headerValue, msgValue);
|
||||
});
|
||||
});
|
||||
|
||||
//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 openInsertOverlay() {
|
||||
var insertOverlay = {
|
||||
allowedTypes: {
|
||||
macro: true,
|
||||
dictionary: true,
|
||||
umbracoField: 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;
|
||||
}
|
||||
editorService.close();
|
||||
},
|
||||
close: function(oldModel) {
|
||||
// close the dialog
|
||||
editorService.close();
|
||||
// focus editor
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
editorService.insertCodeSnippet(insertOverlay);
|
||||
}
|
||||
|
||||
function openMacroOverlay() {
|
||||
var macroPicker = {
|
||||
dialogData: {},
|
||||
submit: function (model) {
|
||||
var macroObject = macroService.collectValueData(model.selectedMacro, model.macroParams, "Mvc");
|
||||
insert(macroObject.syntax);
|
||||
editorService.close();
|
||||
},
|
||||
close: function() {
|
||||
editorService.close();
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
editorService.macroPicker(macroPicker);
|
||||
}
|
||||
|
||||
|
||||
function openPageFieldOverlay() {
|
||||
var insertFieldEditor = {
|
||||
submit: function (model) {
|
||||
insert(model.umbracoField);
|
||||
editorService.close();
|
||||
},
|
||||
close: function () {
|
||||
editorService.close();
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
editorService.insertField(insertFieldEditor);
|
||||
}
|
||||
|
||||
|
||||
function openDictionaryItemOverlay() {
|
||||
|
||||
var labelKeys = [
|
||||
"template_insertDictionaryItem",
|
||||
"emptyStates_emptyDictionaryTree"
|
||||
];
|
||||
|
||||
localizationService.localizeMany(labelKeys).then(function(values){
|
||||
var title = values[0];
|
||||
var emptyStateMessage = values[1];
|
||||
|
||||
var dictionaryPicker = {
|
||||
section: "translation",
|
||||
treeAlias: "dictionary",
|
||||
entityType: "dictionary",
|
||||
multiPicker: false,
|
||||
title: title,
|
||||
emptyStateMessage: emptyStateMessage,
|
||||
select: function(node){
|
||||
var code = templateHelper.getInsertDictionarySnippet(node.name);
|
||||
insert(code);
|
||||
editorService.close();
|
||||
},
|
||||
close: function (model) {
|
||||
// close dialog
|
||||
editorService.close();
|
||||
// focus editor
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
|
||||
editorService.treePicker(dictionaryPicker);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function openQueryBuilderOverlay() {
|
||||
var queryBuilder = {
|
||||
submit: function (model) {
|
||||
var code = templateHelper.getQuerySnippet(model.result.queryExpression);
|
||||
insert(code);
|
||||
editorService.close();
|
||||
},
|
||||
close: function (model) {
|
||||
// close dialog
|
||||
editorService.close();
|
||||
// focus editor
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
editorService.queryBuilder(queryBuilder);
|
||||
}
|
||||
|
||||
/* Local functions */
|
||||
|
||||
function init() {
|
||||
//we need to load this somewhere, for now its here.
|
||||
assetsService.loadCss("lib/ace-razor-mode/theme/razor_chrome.css", $scope);
|
||||
|
||||
if ($routeParams.create) {
|
||||
|
||||
var snippet = "Empty";
|
||||
|
||||
if($routeParams.snippet) {
|
||||
snippet = $routeParams.snippet;
|
||||
}
|
||||
|
||||
codefileResource.getScaffold("partialViewMacros", $routeParams.id, snippet).then(function (partialViewMacro) {
|
||||
if ($routeParams.name) {
|
||||
partialViewMacro.name = $routeParams.name;
|
||||
}
|
||||
ready(partialViewMacro, false);
|
||||
});
|
||||
|
||||
} else {
|
||||
codefileResource.getByPath('partialViewMacros', $routeParams.id).then(function (partialViewMacro) {
|
||||
ready(partialViewMacro, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function ready(partialViewMacro, syncTree) {
|
||||
|
||||
vm.page.loading = false;
|
||||
vm.partialViewMacro = partialViewMacro;
|
||||
|
||||
//sync state
|
||||
editorState.set(vm.partialViewMacro);
|
||||
|
||||
if (syncTree) {
|
||||
navigationService.syncTree({ tree: "partialViewMacros", path: vm.partialViewMacro.path, 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);
|
||||
vm.editor.on("change", changeAceEditor);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function insert(str) {
|
||||
vm.editor.focus();
|
||||
vm.editor.moveCursorToPosition(vm.currentPosition);
|
||||
vm.editor.insert(str);
|
||||
|
||||
// set form state to $dirty
|
||||
setFormState("dirty");
|
||||
}
|
||||
|
||||
function persistCurrentLocation() {
|
||||
vm.currentPosition = vm.editor.getCursorPosition();
|
||||
}
|
||||
|
||||
function changeAceEditor() {
|
||||
setFormState("dirty");
|
||||
}
|
||||
|
||||
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);
|
||||
function completeSave(saved) {
|
||||
|
||||
localizationService.localize("speechBubbles_partialViewSavedHeader").then(function (headerValue) {
|
||||
localizationService.localize("speechBubbles_partialViewSavedText").then(function (msgValue) {
|
||||
notificationsService.success(headerValue, msgValue);
|
||||
});
|
||||
});
|
||||
|
||||
//check if the name changed, if so we need to redirect
|
||||
if (vm.partialViewMacro.id !== saved.id) {
|
||||
contentEditingHelper.redirectToRenamedContent(saved.id);
|
||||
}
|
||||
else {
|
||||
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 openInsertOverlay() {
|
||||
var insertOverlay = {
|
||||
allowedTypes: {
|
||||
macro: true,
|
||||
dictionary: true,
|
||||
umbracoField: 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;
|
||||
}
|
||||
editorService.close();
|
||||
},
|
||||
close: function (oldModel) {
|
||||
// close the dialog
|
||||
editorService.close();
|
||||
// focus editor
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
editorService.insertCodeSnippet(insertOverlay);
|
||||
}
|
||||
|
||||
function openMacroOverlay() {
|
||||
var macroPicker = {
|
||||
dialogData: {},
|
||||
submit: function (model) {
|
||||
var macroObject = macroService.collectValueData(model.selectedMacro, model.macroParams, "Mvc");
|
||||
insert(macroObject.syntax);
|
||||
editorService.close();
|
||||
},
|
||||
close: function () {
|
||||
editorService.close();
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
editorService.macroPicker(macroPicker);
|
||||
}
|
||||
|
||||
|
||||
function openPageFieldOverlay() {
|
||||
var insertFieldEditor = {
|
||||
submit: function (model) {
|
||||
insert(model.umbracoField);
|
||||
editorService.close();
|
||||
},
|
||||
close: function () {
|
||||
editorService.close();
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
editorService.insertField(insertFieldEditor);
|
||||
}
|
||||
|
||||
|
||||
function openDictionaryItemOverlay() {
|
||||
|
||||
var labelKeys = [
|
||||
"template_insertDictionaryItem",
|
||||
"emptyStates_emptyDictionaryTree"
|
||||
];
|
||||
|
||||
localizationService.localizeMany(labelKeys).then(function (values) {
|
||||
var title = values[0];
|
||||
var emptyStateMessage = values[1];
|
||||
|
||||
var dictionaryPicker = {
|
||||
section: "translation",
|
||||
treeAlias: "dictionary",
|
||||
entityType: "dictionary",
|
||||
multiPicker: false,
|
||||
title: title,
|
||||
emptyStateMessage: emptyStateMessage,
|
||||
select: function (node) {
|
||||
var code = templateHelper.getInsertDictionarySnippet(node.name);
|
||||
insert(code);
|
||||
editorService.close();
|
||||
},
|
||||
close: function (model) {
|
||||
// close dialog
|
||||
editorService.close();
|
||||
// focus editor
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
|
||||
editorService.treePicker(dictionaryPicker);
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function openQueryBuilderOverlay() {
|
||||
var queryBuilder = {
|
||||
submit: function (model) {
|
||||
var code = templateHelper.getQuerySnippet(model.result.queryExpression);
|
||||
insert(code);
|
||||
editorService.close();
|
||||
},
|
||||
close: function (model) {
|
||||
// close dialog
|
||||
editorService.close();
|
||||
// focus editor
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
editorService.queryBuilder(queryBuilder);
|
||||
}
|
||||
|
||||
/* Local functions */
|
||||
|
||||
function init() {
|
||||
//we need to load this somewhere, for now its here.
|
||||
assetsService.loadCss("lib/ace-razor-mode/theme/razor_chrome.css", $scope);
|
||||
|
||||
if ($routeParams.create) {
|
||||
|
||||
var snippet = "Empty";
|
||||
|
||||
if ($routeParams.snippet) {
|
||||
snippet = $routeParams.snippet;
|
||||
}
|
||||
|
||||
codefileResource.getScaffold("partialViewMacros", $routeParams.id, snippet).then(function (partialViewMacro) {
|
||||
if ($routeParams.name) {
|
||||
partialViewMacro.name = $routeParams.name;
|
||||
}
|
||||
ready(partialViewMacro, false);
|
||||
});
|
||||
|
||||
} else {
|
||||
codefileResource.getByPath('partialViewMacros', $routeParams.id).then(function (partialViewMacro) {
|
||||
ready(partialViewMacro, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function ready(partialViewMacro, syncTree) {
|
||||
|
||||
vm.page.loading = false;
|
||||
vm.partialViewMacro = partialViewMacro;
|
||||
|
||||
//sync state
|
||||
editorState.set(vm.partialViewMacro);
|
||||
|
||||
if (syncTree) {
|
||||
navigationService.syncTree({ tree: "partialViewMacros", path: vm.partialViewMacro.path, 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;
|
||||
|
||||
// Set read-only when using runtime mode Production
|
||||
_editor.setReadOnly(vm.runtimeModeProduction);
|
||||
|
||||
// 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);
|
||||
vm.editor.on("change", changeAceEditor);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function insert(str) {
|
||||
vm.editor.focus();
|
||||
vm.editor.moveCursorToPosition(vm.currentPosition);
|
||||
vm.editor.insert(str);
|
||||
|
||||
// set form state to $dirty
|
||||
setFormState("dirty");
|
||||
}
|
||||
|
||||
function persistCurrentLocation() {
|
||||
vm.currentPosition = vm.editor.getCursorPosition();
|
||||
}
|
||||
|
||||
function changeAceEditor() {
|
||||
setFormState("dirty");
|
||||
}
|
||||
|
||||
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);
|
||||
})();
|
||||
|
||||
@@ -1,81 +1,81 @@
|
||||
<div data-element="editor-partial-view-macros" ng-controller="Umbraco.Editors.PartialViewMacros.EditController as vm">
|
||||
|
||||
<umb-load-indicator ng-if="vm.page.loading"></umb-load-indicator>
|
||||
<umb-load-indicator ng-if="vm.page.loading"></umb-load-indicator>
|
||||
|
||||
<form name="contentForm"
|
||||
ng-submit="vm.save()"
|
||||
novalidate
|
||||
val-form-manager>
|
||||
<form name="contentForm"
|
||||
ng-submit="vm.save()"
|
||||
novalidate
|
||||
val-form-manager>
|
||||
|
||||
<umb-editor-view ng-if="!vm.page.loading">
|
||||
<umb-editor-view ng-if="!vm.page.loading">
|
||||
|
||||
<umb-editor-header
|
||||
name="vm.partialViewMacro.name"
|
||||
hide-alias="true"
|
||||
description="vm.partialViewMacro.virtualPath"
|
||||
description-locked="true"
|
||||
hide-icon="true"
|
||||
editorfor="vm.header.editorfor"
|
||||
setpagetitle="vm.header.setPageTitle">
|
||||
</umb-editor-header>
|
||||
<umb-editor-header name="vm.partialViewMacro.name"
|
||||
name-locked="vm.runtimeModeProduction"
|
||||
hide-alias="true"
|
||||
description="vm.partialViewMacro.virtualPath"
|
||||
description-locked="true"
|
||||
hide-icon="true"
|
||||
editorfor="vm.header.editorfor"
|
||||
setpagetitle="vm.header.setPageTitle">
|
||||
</umb-editor-header>
|
||||
|
||||
<umb-editor-container>
|
||||
<umb-box>
|
||||
<umb-box-content>
|
||||
<umb-editor-container>
|
||||
<umb-box>
|
||||
<umb-box-content>
|
||||
<div class="umb-alert umb-alert--info mb3" ng-if="vm.runtimeModeProduction">
|
||||
<localize key="template_runtimeModeProduction">Content is not editable when using runtime mode <code>Production</code>.</localize>
|
||||
</div>
|
||||
|
||||
<div class="flex" style="margin-bottom: 30px;">
|
||||
<div class="flex mb3" ng-if="!vm.runtimeModeProduction">
|
||||
|
||||
<div class="flex" style="margin-left: auto;">
|
||||
<div class="flex" style="margin-left: auto;">
|
||||
|
||||
<umb-button-group
|
||||
style="margin-right: 5px;"
|
||||
default-button="vm.page.insertDefaultButton"
|
||||
sub-buttons="vm.page.insertSubButtons"
|
||||
size="xs"
|
||||
icon="icon-add">
|
||||
</umb-button-group>
|
||||
<umb-button-group style="margin-right: 5px;"
|
||||
default-button="vm.page.insertDefaultButton"
|
||||
sub-buttons="vm.page.insertSubButtons"
|
||||
size="xs"
|
||||
icon="icon-add">
|
||||
</umb-button-group>
|
||||
|
||||
<umb-button
|
||||
type="button"
|
||||
size="xs"
|
||||
action="vm.openQueryBuilderOverlay()"
|
||||
icon="icon-wand"
|
||||
label-key="template_queryBuilder"
|
||||
add-ellipsis="true">
|
||||
</umb-button>
|
||||
<umb-button type="button"
|
||||
size="xs"
|
||||
action="vm.openQueryBuilderOverlay()"
|
||||
icon="icon-wand"
|
||||
label-key="template_queryBuilder"
|
||||
add-ellipsis="true">
|
||||
</umb-button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
auto-scale="85"
|
||||
umb-ace-editor="vm.aceOption"
|
||||
model="vm.partialViewMacro.content">
|
||||
</div>
|
||||
<div auto-scale="90"
|
||||
umb-ace-editor="vm.aceOption"
|
||||
model="vm.partialViewMacro.content">
|
||||
</div>
|
||||
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
</umb-editor-container>
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
</umb-editor-container>
|
||||
|
||||
<umb-editor-footer>
|
||||
<umb-editor-footer>
|
||||
|
||||
<umb-editor-footer-content-right>
|
||||
<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-button type="submit"
|
||||
button-style="success"
|
||||
state="vm.page.saveButtonState"
|
||||
disabled="vm.runtimeModeProduction"
|
||||
shortcut="ctrl+s"
|
||||
label="Save"
|
||||
label-key="buttons_save">
|
||||
</umb-button>
|
||||
|
||||
</umb-editor-footer-content-right>
|
||||
</umb-editor-footer-content-right>
|
||||
|
||||
</umb-editor-footer>
|
||||
</umb-editor-footer>
|
||||
|
||||
</umb-editor-view>
|
||||
</form>
|
||||
</umb-editor-view>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,433 +1,438 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
"use strict";
|
||||
|
||||
function PartialViewsEditController($scope, $routeParams, codefileResource, assetsService, notificationsService, editorState, navigationService, appState, macroService, angularHelper, $timeout, contentEditingHelper, localizationService, templateHelper, editorService) {
|
||||
function PartialViewsEditController($scope, $routeParams, codefileResource, assetsService, notificationsService, editorState, navigationService, appState, macroService, angularHelper, $timeout, contentEditingHelper, localizationService, templateHelper, editorService) {
|
||||
|
||||
var vm = this;
|
||||
var infiniteMode = $scope.model && $scope.model.infiniteMode;
|
||||
var id = infiniteMode ? $scope.model.id : $routeParams.id;
|
||||
var create = infiniteMode ? $scope.model.create : $routeParams.create;
|
||||
var snippet = infiniteMode ? $scope.model.snippet : $routeParams.snippet;
|
||||
var vm = this;
|
||||
var infiniteMode = $scope.model && $scope.model.infiniteMode;
|
||||
var id = infiniteMode ? $scope.model.id : $routeParams.id;
|
||||
var create = infiniteMode ? $scope.model.create : $routeParams.create;
|
||||
var snippet = infiniteMode ? $scope.model.snippet : $routeParams.snippet;
|
||||
|
||||
function close() {
|
||||
if ($scope.model.close) {
|
||||
$scope.model.close($scope.model);
|
||||
}
|
||||
function close() {
|
||||
if ($scope.model.close) {
|
||||
$scope.model.close($scope.model);
|
||||
}
|
||||
}
|
||||
|
||||
vm.close = close;
|
||||
|
||||
vm.runtimeModeProduction = Umbraco.Sys.ServerVariables.application.runtimeMode == 'Production';
|
||||
|
||||
vm.header = {};
|
||||
vm.header.editorfor = "visuallyHiddenTexts_newPartialView";
|
||||
vm.header.setPageTitle = true;
|
||||
|
||||
vm.page = {};
|
||||
vm.page.loading = true;
|
||||
vm.partialView = {};
|
||||
|
||||
//menu
|
||||
vm.page.menu = {};
|
||||
vm.page.menu.currentSection = appState.getSectionState("currentSection");
|
||||
vm.page.menu.currentNode = null;
|
||||
|
||||
// insert buttons
|
||||
vm.page.insertDefaultButton = {
|
||||
labelKey: "general_insert",
|
||||
addEllipsis: "true",
|
||||
handler: function () {
|
||||
vm.openInsertOverlay();
|
||||
}
|
||||
};
|
||||
vm.page.insertSubButtons = [
|
||||
{
|
||||
labelKey: "template_insertPageField",
|
||||
addEllipsis: "true",
|
||||
handler: function () {
|
||||
vm.openPageFieldOverlay();
|
||||
}
|
||||
},
|
||||
{
|
||||
labelKey: "template_insertMacro",
|
||||
addEllipsis: "true",
|
||||
handler: function () {
|
||||
vm.openMacroOverlay()
|
||||
}
|
||||
},
|
||||
{
|
||||
labelKey: "template_insertDictionaryItem",
|
||||
addEllipsis: "true",
|
||||
handler: function () {
|
||||
vm.openDictionaryItemOverlay();
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
vm.close = close;
|
||||
//Used to toggle the keyboard shortcut modal
|
||||
//From a custom keybinding in ace editor - that conflicts with our own to show the dialog
|
||||
vm.showKeyboardShortcut = false;
|
||||
|
||||
vm.header = {};
|
||||
vm.header.editorfor = "visuallyHiddenTexts_newPartialView";
|
||||
vm.header.setPageTitle = true;
|
||||
//Keyboard shortcuts for help dialog
|
||||
vm.page.keyboardShortcutsOverview = [];
|
||||
|
||||
vm.page = {};
|
||||
vm.page.loading = true;
|
||||
vm.partialView = {};
|
||||
templateHelper.getGeneralShortcuts().then(function (data) {
|
||||
vm.page.keyboardShortcutsOverview.push(data);
|
||||
});
|
||||
templateHelper.getEditorShortcuts().then(function (data) {
|
||||
vm.page.keyboardShortcutsOverview.push(data);
|
||||
});
|
||||
templateHelper.getPartialViewEditorShortcuts().then(function (data) {
|
||||
vm.page.keyboardShortcutsOverview.push(data);
|
||||
});
|
||||
|
||||
//menu
|
||||
vm.page.menu = {};
|
||||
vm.page.menu.currentSection = appState.getSectionState("currentSection");
|
||||
vm.page.menu.currentNode = null;
|
||||
|
||||
// insert buttons
|
||||
vm.page.insertDefaultButton = {
|
||||
labelKey: "general_insert",
|
||||
addEllipsis: "true",
|
||||
handler: function() {
|
||||
vm.openInsertOverlay();
|
||||
}
|
||||
};
|
||||
vm.page.insertSubButtons = [
|
||||
{
|
||||
labelKey: "template_insertPageField",
|
||||
addEllipsis: "true",
|
||||
handler: function () {
|
||||
vm.openPageFieldOverlay();
|
||||
}
|
||||
},
|
||||
{
|
||||
labelKey: "template_insertMacro",
|
||||
addEllipsis: "true",
|
||||
handler: function () {
|
||||
vm.openMacroOverlay()
|
||||
}
|
||||
},
|
||||
{
|
||||
labelKey: "template_insertDictionaryItem",
|
||||
addEllipsis: "true",
|
||||
handler: function () {
|
||||
vm.openDictionaryItemOverlay();
|
||||
}
|
||||
}
|
||||
];
|
||||
// bind functions to view model
|
||||
vm.save = save;
|
||||
vm.openPageFieldOverlay = openPageFieldOverlay;
|
||||
vm.openDictionaryItemOverlay = openDictionaryItemOverlay;
|
||||
vm.openQueryBuilderOverlay = openQueryBuilderOverlay;
|
||||
vm.openMacroOverlay = openMacroOverlay;
|
||||
vm.openInsertOverlay = openInsertOverlay;
|
||||
|
||||
//Used to toggle the keyboard shortcut modal
|
||||
//From a custom keybinding in ace editor - that conflicts with our own to show the dialog
|
||||
vm.showKeyboardShortcut = false;
|
||||
/* Functions bound to view model */
|
||||
|
||||
//Keyboard shortcuts for help dialog
|
||||
vm.page.keyboardShortcutsOverview = [];
|
||||
function save() {
|
||||
|
||||
templateHelper.getGeneralShortcuts().then(function(data){
|
||||
vm.page.keyboardShortcutsOverview.push(data);
|
||||
});
|
||||
templateHelper.getEditorShortcuts().then(function(data){
|
||||
vm.page.keyboardShortcutsOverview.push(data);
|
||||
});
|
||||
templateHelper.getPartialViewEditorShortcuts().then(function(data){
|
||||
vm.page.keyboardShortcutsOverview.push(data);
|
||||
vm.page.saveButtonState = "busy";
|
||||
vm.partialView.content = vm.editor.getValue();
|
||||
|
||||
contentEditingHelper.contentEditorPerformSave({
|
||||
saveMethod: codefileResource.save,
|
||||
scope: $scope,
|
||||
content: vm.partialView,
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
// 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({
|
||||
saveMethod: codefileResource.save,
|
||||
scope: $scope,
|
||||
content: vm.partialView,
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
//check if the name changed, if so we need to redirect
|
||||
if (vm.partialView.id !== saved.id) {
|
||||
contentEditingHelper.redirectToRenamedContent(saved.id);
|
||||
}
|
||||
else {
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
//check if the name changed, if so we need to redirect
|
||||
if (vm.partialView.id !== saved.id) {
|
||||
contentEditingHelper.redirectToRenamedContent(saved.id);
|
||||
}
|
||||
else {
|
||||
vm.page.saveButtonState = "success";
|
||||
vm.partialView = saved;
|
||||
|
||||
function openInsertOverlay() {
|
||||
var insertOverlay = {
|
||||
allowedTypes: {
|
||||
macro: true,
|
||||
dictionary: true,
|
||||
umbracoField: true
|
||||
},
|
||||
submit: function(model) {
|
||||
//sync state
|
||||
editorState.set(vm.partialView);
|
||||
|
||||
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;
|
||||
}
|
||||
editorService.close();
|
||||
},
|
||||
close: function() {
|
||||
// close the dialog
|
||||
editorService.close();
|
||||
// focus editor
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
editorService.insertCodeSnippet(insertOverlay);
|
||||
// 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";
|
||||
|
||||
function openMacroOverlay() {
|
||||
var macroPicker = {
|
||||
dialogData: {},
|
||||
submit: function (model) {
|
||||
var macroObject = macroService.collectValueData(model.selectedMacro, model.macroParams, "Mvc");
|
||||
insert(macroObject.syntax);
|
||||
editorService.close();
|
||||
},
|
||||
close: function() {
|
||||
editorService.close();
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
editorService.macroPicker(macroPicker);
|
||||
}
|
||||
localizationService.localize("speechBubbles_validationFailedHeader").then(function (headerValue) {
|
||||
localizationService.localize("speechBubbles_validationFailedMessage").then(function (msgValue) {
|
||||
notificationsService.error(headerValue, msgValue);
|
||||
});
|
||||
});
|
||||
|
||||
function openPageFieldOverlay() {
|
||||
var insertFieldEditor = {
|
||||
submit: function (model) {
|
||||
insert(model.umbracoField);
|
||||
editorService.close();
|
||||
},
|
||||
close: function () {
|
||||
editorService.close();
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
editorService.insertField(insertFieldEditor);
|
||||
}
|
||||
|
||||
|
||||
function openDictionaryItemOverlay() {
|
||||
|
||||
var labelKeys = [
|
||||
"template_insertDictionaryItem",
|
||||
"emptyStates_emptyDictionaryTree"
|
||||
];
|
||||
|
||||
localizationService.localizeMany(labelKeys).then(function(values){
|
||||
var title = values[0];
|
||||
var emptyStateMessage = values[1];
|
||||
|
||||
var dictionaryItem = {
|
||||
section: "translation",
|
||||
treeAlias: "dictionary",
|
||||
entityType: "dictionary",
|
||||
multiPicker: false,
|
||||
title: title,
|
||||
emptyStateMessage: emptyStateMessage,
|
||||
select: function(node){
|
||||
var code = templateHelper.getInsertDictionarySnippet(node.name);
|
||||
insert(code);
|
||||
editorService.close();
|
||||
},
|
||||
close: function (model) {
|
||||
// close dialog
|
||||
editorService.close();
|
||||
// focus editor
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
editorService.treePicker(dictionaryItem);
|
||||
});
|
||||
}
|
||||
|
||||
function openQueryBuilderOverlay() {
|
||||
var queryBuilder = {
|
||||
title: "Query for content",
|
||||
submit: function (model) {
|
||||
var code = templateHelper.getQuerySnippet(model.result.queryExpression);
|
||||
insert(code);
|
||||
editorService.close();
|
||||
},
|
||||
close: function () {
|
||||
// close dialog
|
||||
editorService.close();
|
||||
// focus editor
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
editorService.queryBuilder(queryBuilder);
|
||||
}
|
||||
|
||||
/* Local functions */
|
||||
|
||||
function init() {
|
||||
//we need to load this somewhere, for now its here.
|
||||
assetsService.loadCss("lib/ace-razor-mode/theme/razor_chrome.css", $scope);
|
||||
|
||||
if (create) {
|
||||
|
||||
if (!snippet) {
|
||||
snippet = "Empty";
|
||||
}
|
||||
|
||||
codefileResource.getScaffold("partialViews", id, snippet).then(function (partialView) {
|
||||
ready(partialView, false);
|
||||
});
|
||||
|
||||
} else {
|
||||
codefileResource.getByPath('partialViews', id).then(function (partialView) {
|
||||
ready(partialView, true);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function ready(partialView, syncTree) {
|
||||
|
||||
vm.page.loading = false;
|
||||
vm.partialView = partialView;
|
||||
|
||||
//sync state
|
||||
editorState.set(vm.partialView);
|
||||
|
||||
if (!infiniteMode && syncTree) {
|
||||
navigationService.syncTree({ tree: "partialViews", path: vm.partialView.path, 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;
|
||||
|
||||
//Update the auto-complete method to use ctrl+alt+space
|
||||
_editor.commands.bindKey("ctrl-alt-space", "startAutocomplete");
|
||||
|
||||
//Unassigns the keybinding (That was previously auto-complete)
|
||||
//As conflicts with our own tree search shortcut
|
||||
_editor.commands.bindKey("ctrl-space", null);
|
||||
|
||||
// Assign new keybinding
|
||||
_editor.commands.addCommands([
|
||||
//Disable (alt+shift+K)
|
||||
//Conflicts with our own show shortcuts dialog - this overrides it
|
||||
{
|
||||
name: 'unSelectOrFindPrevious',
|
||||
bindKey: 'Alt-Shift-K',
|
||||
exec: function () {
|
||||
//Toggle the show keyboard shortcuts overlay
|
||||
$scope.$apply(function () {
|
||||
vm.showKeyboardShortcut = !vm.showKeyboardShortcut;
|
||||
});
|
||||
},
|
||||
readOnly: true
|
||||
},
|
||||
{
|
||||
name: 'insertUmbracoValue',
|
||||
bindKey: 'Alt-Shift-V',
|
||||
exec: function () {
|
||||
$scope.$apply(function () {
|
||||
openPageFieldOverlay();
|
||||
});
|
||||
},
|
||||
readOnly: true
|
||||
},
|
||||
{
|
||||
name: 'insertDictionary',
|
||||
bindKey: 'Alt-Shift-D',
|
||||
exec: function () {
|
||||
$scope.$apply(function () {
|
||||
openDictionaryItemOverlay();
|
||||
});
|
||||
},
|
||||
readOnly: true
|
||||
},
|
||||
{
|
||||
name: 'insertUmbracoMacro',
|
||||
bindKey: 'Alt-Shift-M',
|
||||
exec: function () {
|
||||
$scope.$apply(function () {
|
||||
openMacroOverlay();
|
||||
});
|
||||
},
|
||||
readOnly: true
|
||||
},
|
||||
{
|
||||
name: 'insertQuery',
|
||||
bindKey: 'Alt-Shift-Q',
|
||||
exec: function () {
|
||||
$scope.$apply(function () {
|
||||
openQueryBuilderOverlay();
|
||||
});
|
||||
},
|
||||
readOnly: true
|
||||
}
|
||||
|
||||
]);
|
||||
|
||||
// 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(!create) {
|
||||
$timeout(function(){
|
||||
vm.editor.navigateFileEnd();
|
||||
vm.editor.focus();
|
||||
persistCurrentLocation();
|
||||
});
|
||||
}
|
||||
|
||||
//change on blur, focus
|
||||
vm.editor.on("blur", persistCurrentLocation);
|
||||
vm.editor.on("focus", persistCurrentLocation);
|
||||
vm.editor.on("change", changeAceEditor);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function insert(str) {
|
||||
vm.editor.focus();
|
||||
vm.editor.moveCursorToPosition(vm.currentPosition);
|
||||
vm.editor.insert(str);
|
||||
|
||||
// set form state to $dirty
|
||||
setFormState("dirty");
|
||||
}
|
||||
|
||||
function persistCurrentLocation() {
|
||||
vm.currentPosition = vm.editor.getCursorPosition();
|
||||
}
|
||||
|
||||
function changeAceEditor() {
|
||||
setFormState("dirty");
|
||||
}
|
||||
|
||||
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);
|
||||
function openInsertOverlay() {
|
||||
var insertOverlay = {
|
||||
allowedTypes: {
|
||||
macro: true,
|
||||
dictionary: true,
|
||||
umbracoField: 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;
|
||||
}
|
||||
editorService.close();
|
||||
},
|
||||
close: function () {
|
||||
// close the dialog
|
||||
editorService.close();
|
||||
// focus editor
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
editorService.insertCodeSnippet(insertOverlay);
|
||||
}
|
||||
|
||||
|
||||
function openMacroOverlay() {
|
||||
var macroPicker = {
|
||||
dialogData: {},
|
||||
submit: function (model) {
|
||||
var macroObject = macroService.collectValueData(model.selectedMacro, model.macroParams, "Mvc");
|
||||
insert(macroObject.syntax);
|
||||
editorService.close();
|
||||
},
|
||||
close: function () {
|
||||
editorService.close();
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
editorService.macroPicker(macroPicker);
|
||||
}
|
||||
|
||||
function openPageFieldOverlay() {
|
||||
var insertFieldEditor = {
|
||||
submit: function (model) {
|
||||
insert(model.umbracoField);
|
||||
editorService.close();
|
||||
},
|
||||
close: function () {
|
||||
editorService.close();
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
editorService.insertField(insertFieldEditor);
|
||||
}
|
||||
|
||||
|
||||
function openDictionaryItemOverlay() {
|
||||
|
||||
var labelKeys = [
|
||||
"template_insertDictionaryItem",
|
||||
"emptyStates_emptyDictionaryTree"
|
||||
];
|
||||
|
||||
localizationService.localizeMany(labelKeys).then(function (values) {
|
||||
var title = values[0];
|
||||
var emptyStateMessage = values[1];
|
||||
|
||||
var dictionaryItem = {
|
||||
section: "translation",
|
||||
treeAlias: "dictionary",
|
||||
entityType: "dictionary",
|
||||
multiPicker: false,
|
||||
title: title,
|
||||
emptyStateMessage: emptyStateMessage,
|
||||
select: function (node) {
|
||||
var code = templateHelper.getInsertDictionarySnippet(node.name);
|
||||
insert(code);
|
||||
editorService.close();
|
||||
},
|
||||
close: function (model) {
|
||||
// close dialog
|
||||
editorService.close();
|
||||
// focus editor
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
editorService.treePicker(dictionaryItem);
|
||||
});
|
||||
}
|
||||
|
||||
function openQueryBuilderOverlay() {
|
||||
var queryBuilder = {
|
||||
title: "Query for content",
|
||||
submit: function (model) {
|
||||
var code = templateHelper.getQuerySnippet(model.result.queryExpression);
|
||||
insert(code);
|
||||
editorService.close();
|
||||
},
|
||||
close: function () {
|
||||
// close dialog
|
||||
editorService.close();
|
||||
// focus editor
|
||||
vm.editor.focus();
|
||||
}
|
||||
};
|
||||
editorService.queryBuilder(queryBuilder);
|
||||
}
|
||||
|
||||
/* Local functions */
|
||||
|
||||
function init() {
|
||||
//we need to load this somewhere, for now its here.
|
||||
assetsService.loadCss("lib/ace-razor-mode/theme/razor_chrome.css", $scope);
|
||||
|
||||
if (create) {
|
||||
|
||||
if (!snippet) {
|
||||
snippet = "Empty";
|
||||
}
|
||||
|
||||
codefileResource.getScaffold("partialViews", id, snippet).then(function (partialView) {
|
||||
ready(partialView, false);
|
||||
});
|
||||
|
||||
} else {
|
||||
codefileResource.getByPath('partialViews', id).then(function (partialView) {
|
||||
ready(partialView, true);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function ready(partialView, syncTree) {
|
||||
|
||||
vm.page.loading = false;
|
||||
vm.partialView = partialView;
|
||||
|
||||
//sync state
|
||||
editorState.set(vm.partialView);
|
||||
|
||||
if (!infiniteMode && syncTree) {
|
||||
navigationService.syncTree({ tree: "partialViews", path: vm.partialView.path, 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;
|
||||
|
||||
// Set read-only when using runtime mode Production
|
||||
_editor.setReadOnly(vm.runtimeModeProduction);
|
||||
|
||||
//Update the auto-complete method to use ctrl+alt+space
|
||||
_editor.commands.bindKey("ctrl-alt-space", "startAutocomplete");
|
||||
|
||||
//Unassigns the keybinding (That was previously auto-complete)
|
||||
//As conflicts with our own tree search shortcut
|
||||
_editor.commands.bindKey("ctrl-space", null);
|
||||
|
||||
// Assign new keybinding
|
||||
_editor.commands.addCommands([
|
||||
//Disable (alt+shift+K)
|
||||
//Conflicts with our own show shortcuts dialog - this overrides it
|
||||
{
|
||||
name: 'unSelectOrFindPrevious',
|
||||
bindKey: 'Alt-Shift-K',
|
||||
exec: function () {
|
||||
//Toggle the show keyboard shortcuts overlay
|
||||
$scope.$apply(function () {
|
||||
vm.showKeyboardShortcut = !vm.showKeyboardShortcut;
|
||||
});
|
||||
},
|
||||
readOnly: true
|
||||
},
|
||||
{
|
||||
name: 'insertUmbracoValue',
|
||||
bindKey: 'Alt-Shift-V',
|
||||
exec: function () {
|
||||
$scope.$apply(function () {
|
||||
openPageFieldOverlay();
|
||||
});
|
||||
},
|
||||
readOnly: true
|
||||
},
|
||||
{
|
||||
name: 'insertDictionary',
|
||||
bindKey: 'Alt-Shift-D',
|
||||
exec: function () {
|
||||
$scope.$apply(function () {
|
||||
openDictionaryItemOverlay();
|
||||
});
|
||||
},
|
||||
readOnly: true
|
||||
},
|
||||
{
|
||||
name: 'insertUmbracoMacro',
|
||||
bindKey: 'Alt-Shift-M',
|
||||
exec: function () {
|
||||
$scope.$apply(function () {
|
||||
openMacroOverlay();
|
||||
});
|
||||
},
|
||||
readOnly: true
|
||||
},
|
||||
{
|
||||
name: 'insertQuery',
|
||||
bindKey: 'Alt-Shift-Q',
|
||||
exec: function () {
|
||||
$scope.$apply(function () {
|
||||
openQueryBuilderOverlay();
|
||||
});
|
||||
},
|
||||
readOnly: true
|
||||
}
|
||||
|
||||
]);
|
||||
|
||||
// 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 (!create) {
|
||||
$timeout(function () {
|
||||
vm.editor.navigateFileEnd();
|
||||
vm.editor.focus();
|
||||
persistCurrentLocation();
|
||||
});
|
||||
}
|
||||
|
||||
//change on blur, focus
|
||||
vm.editor.on("blur", persistCurrentLocation);
|
||||
vm.editor.on("focus", persistCurrentLocation);
|
||||
vm.editor.on("change", changeAceEditor);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function insert(str) {
|
||||
vm.editor.focus();
|
||||
vm.editor.moveCursorToPosition(vm.currentPosition);
|
||||
vm.editor.insert(str);
|
||||
|
||||
// set form state to $dirty
|
||||
setFormState("dirty");
|
||||
}
|
||||
|
||||
function persistCurrentLocation() {
|
||||
vm.currentPosition = vm.editor.getCursorPosition();
|
||||
}
|
||||
|
||||
function changeAceEditor() {
|
||||
setFormState("dirty");
|
||||
}
|
||||
|
||||
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);
|
||||
})();
|
||||
|
||||
@@ -1,97 +1,98 @@
|
||||
<div data-element="editor-partial-views" ng-controller="Umbraco.Editors.PartialViews.EditController as vm">
|
||||
|
||||
<umb-load-indicator ng-if="vm.page.loading"></umb-load-indicator>
|
||||
<umb-load-indicator ng-if="vm.page.loading"></umb-load-indicator>
|
||||
|
||||
<form name="contentForm"
|
||||
ng-submit="vm.save()"
|
||||
novalidate
|
||||
val-form-manager>
|
||||
<form name="contentForm"
|
||||
ng-submit="vm.save()"
|
||||
novalidate
|
||||
val-form-manager>
|
||||
|
||||
<umb-editor-view ng-if="!vm.page.loading">
|
||||
<umb-editor-view ng-if="!vm.page.loading">
|
||||
|
||||
<umb-editor-header
|
||||
name="vm.partialView.name"
|
||||
hide-alias="true"
|
||||
description="vm.partialView.virtualPath"
|
||||
description-locked="true"
|
||||
hide-icon="true"
|
||||
editorfor="vm.header.editorfor"
|
||||
setpagetitle="vm.header.setPageTitle">
|
||||
</umb-editor-header>
|
||||
<umb-editor-header name="vm.partialView.name"
|
||||
name-locked="vm.runtimeModeProduction"
|
||||
hide-alias="true"
|
||||
description="vm.partialView.virtualPath"
|
||||
description-locked="true"
|
||||
hide-icon="true"
|
||||
editorfor="vm.header.editorfor"
|
||||
setpagetitle="vm.header.setPageTitle">
|
||||
</umb-editor-header>
|
||||
|
||||
<umb-editor-container>
|
||||
<umb-editor-container>
|
||||
|
||||
<umb-box>
|
||||
<umb-box-content>
|
||||
<umb-box>
|
||||
<umb-box-content>
|
||||
<div class="umb-alert umb-alert--info mb3" ng-if="vm.runtimeModeProduction">
|
||||
<localize key="template_runtimeModeProduction">Content is not editable when using runtime mode <code>Production</code>.</localize>
|
||||
</div>
|
||||
|
||||
<div class="flex" style="margin-bottom: 30px;">
|
||||
<div class="flex mb3" ng-if="!vm.runtimeModeProduction">
|
||||
|
||||
<div class="flex" style="margin-left: auto;">
|
||||
<div class="flex" style="margin-left: auto;">
|
||||
|
||||
<umb-button-group
|
||||
style="margin-right: 5px;"
|
||||
default-button="vm.page.insertDefaultButton"
|
||||
sub-buttons="vm.page.insertSubButtons"
|
||||
size="xs"
|
||||
icon="icon-add">
|
||||
</umb-button-group>
|
||||
<umb-button-group style="margin-right: 5px;"
|
||||
default-button="vm.page.insertDefaultButton"
|
||||
sub-buttons="vm.page.insertSubButtons"
|
||||
size="xs"
|
||||
icon="icon-add">
|
||||
</umb-button-group>
|
||||
|
||||
<umb-button
|
||||
type="button"
|
||||
size="xs"
|
||||
action="vm.openQueryBuilderOverlay()"
|
||||
icon="icon-wand"
|
||||
label-key="template_queryBuilder"
|
||||
add-ellipsis="true">
|
||||
</umb-button>
|
||||
<umb-button type="button"
|
||||
size="xs"
|
||||
action="vm.openQueryBuilderOverlay()"
|
||||
icon="icon-wand"
|
||||
label-key="template_queryBuilder"
|
||||
add-ellipsis="true">
|
||||
</umb-button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
auto-scale="85"
|
||||
umb-ace-editor="vm.aceOption"
|
||||
model="vm.partialView.content">
|
||||
</div>
|
||||
<div auto-scale="90"
|
||||
umb-ace-editor="vm.aceOption"
|
||||
model="vm.partialView.content">
|
||||
</div>
|
||||
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
|
||||
</umb-editor-container>
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
|
||||
<umb-editor-footer>
|
||||
</umb-editor-container>
|
||||
|
||||
<umb-editor-footer-content-left>
|
||||
<umb-keyboard-shortcuts-overview
|
||||
model="vm.page.keyboardShortcutsOverview"
|
||||
show-overlay="vm.showKeyboardShortcut"
|
||||
on-close="vm.showKeyboardShortcut = false;">
|
||||
</umb-keyboard-shortcuts-overview>
|
||||
</umb-editor-footer-content-left>
|
||||
<umb-editor-footer>
|
||||
|
||||
<umb-editor-footer-content-right>
|
||||
<umb-editor-footer-content-left>
|
||||
<umb-keyboard-shortcuts-overview ng-if="!vm.runtimeModeProduction"
|
||||
model="vm.page.keyboardShortcutsOverview"
|
||||
show-overlay="vm.showKeyboardShortcut"
|
||||
on-close="vm.showKeyboardShortcut = false;">
|
||||
</umb-keyboard-shortcuts-overview>
|
||||
</umb-editor-footer-content-left>
|
||||
|
||||
<umb-button ng-if="model.infiniteMode"
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="vm.close()">
|
||||
</umb-button>
|
||||
|
||||
<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-content-right>
|
||||
|
||||
</umb-editor-footer>
|
||||
<umb-button ng-if="model.infiniteMode"
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="vm.close()">
|
||||
</umb-button>
|
||||
|
||||
</umb-editor-view>
|
||||
</form>
|
||||
<umb-button type="submit"
|
||||
button-style="success"
|
||||
state="vm.page.saveButtonState"
|
||||
disabled="vm.runtimeModeProduction"
|
||||
shortcut="ctrl+s"
|
||||
label="Save"
|
||||
label-key="buttons_save">
|
||||
</umb-button>
|
||||
</umb-editor-footer-content-right>
|
||||
|
||||
</umb-editor-footer>
|
||||
|
||||
</umb-editor-view>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,144 +1,142 @@
|
||||
<div data-element="editor-templates" ng-controller="Umbraco.Editors.Templates.EditController as vm">
|
||||
|
||||
<umb-load-indicator ng-if="vm.page.loading"></umb-load-indicator>
|
||||
<umb-load-indicator ng-if="vm.page.loading"></umb-load-indicator>
|
||||
|
||||
<form name="contentForm"
|
||||
ng-submit="vm.save()"
|
||||
novalidate
|
||||
val-form-manager>
|
||||
<form name="contentForm"
|
||||
ng-submit="vm.save()"
|
||||
novalidate
|
||||
val-form-manager>
|
||||
|
||||
<umb-editor-view ng-if="!vm.page.loading">
|
||||
<umb-editor-view ng-if="!vm.page.loading">
|
||||
|
||||
<umb-editor-header
|
||||
name="vm.template.name"
|
||||
alias="vm.template.alias"
|
||||
key="vm.template.key"
|
||||
description="vm.template.virtualPath"
|
||||
description-locked="true"
|
||||
hide-icon="false"
|
||||
editorfor="vm.header.editorfor"
|
||||
setpagetitle="vm.header.setPageTitle">
|
||||
</umb-editor-header>
|
||||
<umb-editor-header name="vm.template.name"
|
||||
alias="vm.template.alias"
|
||||
alias-locked="vm.runtimeModeProduction"
|
||||
key="vm.template.key"
|
||||
description="vm.template.virtualPath"
|
||||
description-locked="true"
|
||||
hide-icon="false"
|
||||
editorfor="vm.header.editorfor"
|
||||
setpagetitle="vm.header.setPageTitle">
|
||||
</umb-editor-header>
|
||||
|
||||
<umb-editor-container>
|
||||
<umb-box>
|
||||
<umb-box-content>
|
||||
<umb-editor-container>
|
||||
<umb-box>
|
||||
|
||||
<div class="flex" style="margin-bottom: 30px;">
|
||||
<umb-box-content>
|
||||
<div class="umb-alert umb-alert--info mb3" ng-if="vm.runtimeModeProduction">
|
||||
<localize key="template_runtimeModeProduction">Content is not editable when using runtime mode <code>Production</code>.</localize>
|
||||
</div>
|
||||
|
||||
<div class="flex">
|
||||
<div class="flex mb3" ng-if="!vm.runtimeModeProduction">
|
||||
|
||||
<div ng-class="{'btn-group': vm.template.masterTemplateAlias}" style="margin-right: 10px;">
|
||||
<div class="flex">
|
||||
|
||||
<button type="button"
|
||||
data-element="button-masterTemplate"
|
||||
class="btn umb-button__button umb-button--xs umb-outline"
|
||||
style="font-size: 14px;"
|
||||
ng-click="vm.openMasterTemplateOverlay()">
|
||||
<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>
|
||||
<div ng-class="{'btn-group': vm.template.masterTemplateAlias}" style="margin-right: 10px;">
|
||||
|
||||
<button type="button"
|
||||
class="btn umb-button__button umb-button--xs dropdown-toggle umb-button-group__toggle flex-inline items-center"
|
||||
style="font-size: 14px; height: 100%;"
|
||||
localize="title"
|
||||
title="@general_remove"
|
||||
ng-if="vm.template.masterTemplateAlias"
|
||||
ng-click="vm.removeMasterTemplate()">
|
||||
<umb-icon icon="icon-wrong" class="icon"></umb-icon>
|
||||
</button>
|
||||
<button type="button"
|
||||
data-element="button-masterTemplate"
|
||||
class="btn umb-button__button umb-button--xs umb-outline"
|
||||
style="font-size: 14px;"
|
||||
ng-click="vm.openMasterTemplateOverlay()">
|
||||
<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>
|
||||
|
||||
</div>
|
||||
<button type="button"
|
||||
class="btn umb-button__button umb-button--xs dropdown-toggle umb-button-group__toggle flex-inline items-center"
|
||||
style="font-size: 14px; height: 100%;"
|
||||
localize="title"
|
||||
title="@general_remove"
|
||||
ng-if="vm.template.masterTemplateAlias"
|
||||
ng-click="vm.removeMasterTemplate()">
|
||||
<umb-icon icon="icon-wrong" class="icon"></umb-icon>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="flex" style="margin-left: auto;">
|
||||
</div>
|
||||
|
||||
<umb-button-group
|
||||
style="margin-right: 5px;"
|
||||
default-button="vm.page.insertDefaultButton"
|
||||
sub-buttons="vm.page.insertSubButtons"
|
||||
size="xs">
|
||||
</umb-button-group>
|
||||
<div class="flex" style="margin-left: auto;">
|
||||
|
||||
<umb-button
|
||||
style="margin-right: 5px;"
|
||||
alias="queryBuilder"
|
||||
type="button"
|
||||
size="xs"
|
||||
action="vm.openQueryBuilderOverlay()"
|
||||
icon="icon-wand"
|
||||
label-key="template_queryBuilder"
|
||||
add-ellipsis="true">
|
||||
</umb-button>
|
||||
<umb-button-group style="margin-right: 5px;"
|
||||
default-button="vm.page.insertDefaultButton"
|
||||
sub-buttons="vm.page.insertSubButtons"
|
||||
size="xs">
|
||||
</umb-button-group>
|
||||
|
||||
<umb-button
|
||||
alias="sections"
|
||||
type="button"
|
||||
size="xs"
|
||||
action="vm.openSectionsOverlay()"
|
||||
icon="icon-indent"
|
||||
label-key="template_insertSections"
|
||||
add-ellipsis="true">
|
||||
</umb-button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div
|
||||
data-element="code-editor"
|
||||
auto-scale="85"
|
||||
umb-ace-editor="vm.aceOption"
|
||||
model="vm.template.content">
|
||||
</div>
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
|
||||
</umb-editor-container>
|
||||
|
||||
<umb-editor-footer>
|
||||
|
||||
<umb-editor-footer-content-left>
|
||||
|
||||
<umb-keyboard-shortcuts-overview
|
||||
model="vm.page.keyboardShortcutsOverview"
|
||||
show-overlay="vm.showKeyboardShortcut"
|
||||
on-close="vm.closeShortcuts()">
|
||||
</umb-keyboard-shortcuts-overview>
|
||||
|
||||
</umb-editor-footer-content-left>
|
||||
|
||||
<umb-editor-footer-content-right>
|
||||
|
||||
<umb-button
|
||||
ng-if="model.infiniteMode"
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="vm.close()">
|
||||
<umb-button style="margin-right: 5px;"
|
||||
alias="queryBuilder"
|
||||
type="button"
|
||||
size="xs"
|
||||
action="vm.openQueryBuilderOverlay()"
|
||||
icon="icon-wand"
|
||||
label-key="template_queryBuilder"
|
||||
add-ellipsis="true">
|
||||
</umb-button>
|
||||
|
||||
<umb-button
|
||||
alias="save"
|
||||
type="submit"
|
||||
button-style="success"
|
||||
state="vm.page.saveButtonState"
|
||||
shortcut="ctrl+s"
|
||||
label="Save"
|
||||
label-key="buttons_save">
|
||||
<umb-button alias="sections"
|
||||
type="button"
|
||||
size="xs"
|
||||
action="vm.openSectionsOverlay()"
|
||||
icon="icon-indent"
|
||||
label-key="template_insertSections"
|
||||
add-ellipsis="true">
|
||||
</umb-button>
|
||||
|
||||
</umb-editor-footer-content-right>
|
||||
</div>
|
||||
|
||||
</umb-editor-footer>
|
||||
</div>
|
||||
|
||||
</umb-editor-view>
|
||||
</form>
|
||||
<div data-element="code-editor"
|
||||
auto-scale="90"
|
||||
umb-ace-editor="vm.aceOption"
|
||||
model="vm.template.content">
|
||||
</div>
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
|
||||
</umb-editor-container>
|
||||
|
||||
<umb-editor-footer>
|
||||
|
||||
<umb-editor-footer-content-left>
|
||||
|
||||
<umb-keyboard-shortcuts-overview ng-if="!vm.runtimeModeProduction"
|
||||
model="vm.page.keyboardShortcutsOverview"
|
||||
show-overlay="vm.showKeyboardShortcut"
|
||||
on-close="vm.closeShortcuts()">
|
||||
</umb-keyboard-shortcuts-overview>
|
||||
|
||||
</umb-editor-footer-content-left>
|
||||
|
||||
<umb-editor-footer-content-right>
|
||||
|
||||
<umb-button ng-if="model.infiniteMode"
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="vm.close()">
|
||||
</umb-button>
|
||||
|
||||
<umb-button alias="save"
|
||||
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,4 +1,4 @@
|
||||
(function() {
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
describe("templates editor controller",
|
||||
@@ -26,6 +26,7 @@
|
||||
getCursorPosition: function() {},
|
||||
getValue: function() {},
|
||||
setValue: function() {},
|
||||
setReadOnly: function () { },
|
||||
focus: function() {},
|
||||
clearSelection: function() {},
|
||||
navigateFileStart: function() {},
|
||||
|
||||
@@ -5,10 +5,12 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
using Umbraco.Cms.Core.Cache;
|
||||
using Umbraco.Cms.Core.Configuration.Models;
|
||||
using Umbraco.Cms.Core.IO;
|
||||
using Umbraco.Cms.Core.Mapping;
|
||||
using Umbraco.Cms.Core.Models;
|
||||
@@ -77,6 +79,9 @@ public class ContentTypeRepositoryTest : UmbracoIntegrationTest
|
||||
var provider = ScopeProvider;
|
||||
using (var scope = provider.CreateScope())
|
||||
{
|
||||
var runtimeSettingsMock = new Mock<IOptionsMonitor<RuntimeSettings>>();
|
||||
runtimeSettingsMock.Setup(x => x.CurrentValue).Returns(new RuntimeSettings());
|
||||
|
||||
var templateRepo = new TemplateRepository(
|
||||
(IScopeAccessor)provider,
|
||||
AppCaches.Disabled,
|
||||
@@ -84,7 +89,8 @@ public class ContentTypeRepositoryTest : UmbracoIntegrationTest
|
||||
FileSystems,
|
||||
IOHelper,
|
||||
ShortStringHelper,
|
||||
Mock.Of<IViewHelper>());
|
||||
Mock.Of<IViewHelper>(),
|
||||
runtimeSettingsMock.Object);
|
||||
var repository = ContentTypeRepository;
|
||||
Template[] templates =
|
||||
{
|
||||
|
||||
@@ -111,7 +111,10 @@ public class DocumentRepositoryTest : UmbracoIntegrationTest
|
||||
{
|
||||
appCaches ??= AppCaches;
|
||||
|
||||
templateRepository = new TemplateRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger<TemplateRepository>(), FileSystems, IOHelper, ShortStringHelper, Mock.Of<IViewHelper>());
|
||||
var runtimeSettingsMock = new Mock<IOptionsMonitor<RuntimeSettings>>();
|
||||
runtimeSettingsMock.Setup(x => x.CurrentValue).Returns(new RuntimeSettings());
|
||||
|
||||
templateRepository = new TemplateRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger<TemplateRepository>(), FileSystems, IOHelper, ShortStringHelper, Mock.Of<IViewHelper>(), runtimeSettingsMock.Object);
|
||||
var tagRepository = new TagRepository(scopeAccessor, appCaches, LoggerFactory.CreateLogger<TagRepository>());
|
||||
var commonRepository =
|
||||
new ContentTypeCommonRepository(scopeAccessor, templateRepository, appCaches, ShortStringHelper);
|
||||
|
||||
@@ -7,6 +7,7 @@ using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Cms.Core;
|
||||
@@ -56,10 +57,13 @@ public class TemplateRepositoryTest : UmbracoIntegrationTest
|
||||
private IHostingEnvironment HostingEnvironment => GetRequiredService<IHostingEnvironment>();
|
||||
|
||||
private FileSystems FileSystems => GetRequiredService<FileSystems>();
|
||||
|
||||
private IViewHelper ViewHelper => GetRequiredService<IViewHelper>();
|
||||
|
||||
private IOptionsMonitor<RuntimeSettings> RuntimeSettings => GetRequiredService<IOptionsMonitor<RuntimeSettings>>();
|
||||
|
||||
private ITemplateRepository CreateRepository(IScopeProvider provider) =>
|
||||
new TemplateRepository((IScopeAccessor)provider, AppCaches.Disabled, LoggerFactory.CreateLogger<TemplateRepository>(), FileSystems, IOHelper, ShortStringHelper, ViewHelper);
|
||||
new TemplateRepository((IScopeAccessor)provider, AppCaches.Disabled, LoggerFactory.CreateLogger<TemplateRepository>(), FileSystems, IOHelper, ShortStringHelper, ViewHelper, RuntimeSettings);
|
||||
|
||||
[Test]
|
||||
public void Can_Instantiate_Repository()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json",
|
||||
"version": "10.1.0-alpha.1",
|
||||
"version": "10.2.0",
|
||||
"assemblyVersion": {
|
||||
"precision": "Build" // optional. Use when you want a more precise assembly version than the default major.minor.
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user