Merge branch 'v8/dev' into temp-bellefixes
This commit is contained in:
@@ -0,0 +1,35 @@
|
||||
# Contributing to Umbraco CMS
|
||||
|
||||
When you’re considering creating a pull request for Umbraco CMS, we will categorize them in two different sizes, small and large.
|
||||
|
||||
The process for both sizes is very similar, as [explained in the contribution document](CONTRIBUTING.md#how-do-i-begin).
|
||||
|
||||
## Small PRs
|
||||
Bug fixes and small improvements - can be recognized by seeing a small number of changes and possibly a small number of new files.
|
||||
|
||||
We’re usually able to handle small PRs pretty quickly. A community volunteer will do the initial review and flag it for Umbraco HQ as “community tested”. If everything looks good, it will be merged pretty quickly [as per the described process](REVIEW_PROCESS.md).
|
||||
|
||||
### Up for grabs
|
||||
|
||||
Umbraco HQ will regularly mark newly created issues on the issue tracker with the `Up for grabs` tag. This means that the proposed changes are wanted in Umbraco but the HQ does not have the time to make them at this time. We encourage anyone to pick them up and help out.
|
||||
|
||||
If you do start working on something, make sure leave a small comment on the issue saying something like: "I'm working on this". That way other people stumbling upon the issue know they don't need to pick it up, someone already has.
|
||||
|
||||
## Large PRs
|
||||
New features and large refactorings - can be recognized by seeing a large number of changes, plenty of new files, updates to package manager files (NuGet’s packages.config, NPM’s packages.json, etc.).
|
||||
|
||||
We would love to follow the same process for larger PRs but this is not always possible due to time limitations and priorities that need to be aligned. We don’t want to put up any barriers, but this document should set the correct expectations.
|
||||
|
||||
Please make sure to describe your idea in an issue, it helps to put in mockup screenshots or videos.
|
||||
|
||||
If the change makes sense for HQ to include in Umbraco CMS we will leave you some feedback on how we’d like to see it being implemented.
|
||||
|
||||
If a larger pull request is encouraged by Umbraco HQ, the process will be similar to what is described in the [small PRs process](#small-prs) above, we strive to feedback within 14 days. Finalizing and merging the PR might take longer though as it will likely need to be picked up by the development team to make sure everything is in order. We’ll keep you posted on the progress.
|
||||
|
||||
It is highly recommended that you speak to the HQ before making large, complex changes.
|
||||
|
||||
### Pull request or package?
|
||||
|
||||
If it doesn’t fit in CMS right now, we will likely encourage you to make it into a package instead. A package is a great way to check out popularity of a feature, learn how people use it, validate good usability and to fix bugs.
|
||||
|
||||
Eventually, a package could "graduate" to be included in the CMS.
|
||||
@@ -0,0 +1,25 @@
|
||||
# Review process
|
||||
|
||||
You're an awesome person and have sent us your contribution in the form of a pull request! It's now time to relax for a bit and wait for our response.
|
||||
|
||||
In order to set some expectations, here's what happens next.
|
||||
|
||||
## Review process
|
||||
|
||||
You will get an initial reply within 48 hours (workdays) to acknowledge that we’ve seen your PR and we’ll pick it up as soon as we can.
|
||||
|
||||
You will get feedback within at most 14 days after opening the PR. You’ll most likely get feedback sooner though. Then there are a few possible outcomes:
|
||||
|
||||
- Your proposed change is awesome! We merge it in and it will be included in the next minor release of Umbraco
|
||||
- If the change is a high priority bug fix, we will cherry-pick it into the next patch release as well so that we can release it as soon as possible
|
||||
- Your proposed change is awesome but needs a bit more work, we’ll give you feedback on the changes we’d like to see
|
||||
- Your proposed change is awesome but.. not something we’re looking to include at this point. We’ll close your PR and the related issue (we’ll be nice about it!)
|
||||
|
||||
## Are you still available?
|
||||
|
||||
We understand you have other things to do and can't just drop everything to help us out.
|
||||
So if we’re asking for your help to improve the PR we’ll wait for two weeks to give you a fair chance to make changes. We’ll ask for an update if we don’t hear back from you after that time.
|
||||
|
||||
If we don’t hear back from you for 4 weeks, we’ll close the PR so that it doesn’t just hang around forever. You’re very welcome to re-open it once you have some more time to spend on it.
|
||||
|
||||
There will be times that we really like your proposed changes and we’ll finish the final improvements we’d like to see ourselves. You still get the credits and your commits will live on in the git repository.
|
||||
@@ -1,11 +1,11 @@
|
||||
|
||||
888
|
||||
888
|
||||
888 888 88888b.d88b. 88888b. 888d888 8888b. .d8888b .d88b.
|
||||
888 888 888 "888 "88b 888 "88b 888P" "88b d88P" d88""88b
|
||||
888 888 888 888 888 888 888 888 .d888888 888 888 888
|
||||
Y88b 888 888 888 888 888 d88P 888 888 888 Y88b. Y88..88P
|
||||
"Y88888 888 888 888 88888P" 888 "Y888888 "Y8888P "Y88P"
|
||||
888
|
||||
888
|
||||
888 888 88888b.d88b. 88888b. 888d888 8888b. .d8888b .d88b.
|
||||
888 888 888 "888 "88b 888 "88b 888P" "88b d88P" d88""88b
|
||||
888 888 888 888 888 888 888 888 .d888888 888 888 888
|
||||
Y88 88Y 888 888 888 888 d88P 888 888 888 Y88b. Y88..88P
|
||||
"Y888P" 888 888 888 88888P" 888 "Y888888 "Y8888P "Y88P"
|
||||
|
||||
------------------------------------------------------------------
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
|
||||
_ _ __ __ ____ _____ _____ ____
|
||||
| | | | \/ | _ \| __ \ /\ / ____/ __ \
|
||||
| | | | \ / | |_) | |__) | / \ | | | | | |
|
||||
| | | | |\/| | _ <| _ / / /\ \| | | | | |
|
||||
| |__| | | | | |_) | | \ \ / ____ | |___| |__| |
|
||||
\____/|_| |_|____/|_| \_/_/ \_\_____\____/
|
||||
888
|
||||
888
|
||||
888 888 88888b.d88b. 88888b. 888d888 8888b. .d8888b .d88b.
|
||||
888 888 888 "888 "88b 888 "88b 888P" "88b d88P" d88""88b
|
||||
888 888 888 888 888 888 888 888 .d888888 888 888 888
|
||||
Y88 88Y 888 888 888 888 d88P 888 888 888 Y88b. Y88..88P
|
||||
"Y888P" 888 888 888 88888P" 888 "Y888888 "Y8888P "Y88P"
|
||||
|
||||
----------------------------------------------------
|
||||
------------------------------------------------------------------
|
||||
|
||||
Don't forget to build!
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ namespace Umbraco.Core.Composing.CompositionExtensions
|
||||
var pluginLangFolders = appPlugins.Exists == false
|
||||
? Enumerable.Empty<LocalizedTextServiceSupplementaryFileSource>()
|
||||
: appPlugins.GetDirectories()
|
||||
.SelectMany(x => x.GetDirectories("Lang"))
|
||||
.SelectMany(x => x.GetDirectories("Lang", SearchOption.AllDirectories))
|
||||
.SelectMany(x => x.GetFiles("*.xml", SearchOption.TopDirectoryOnly))
|
||||
.Select(x => new LocalizedTextServiceSupplementaryFileSource(x, false));
|
||||
|
||||
|
||||
@@ -96,6 +96,11 @@ namespace Umbraco.Core
|
||||
/// </summary>
|
||||
public const string MediaPicker = "Umbraco.MediaPicker";
|
||||
|
||||
/// <summary>
|
||||
/// Multiple Media Picker.
|
||||
/// </summary>
|
||||
public const string MultipleMediaPicker = "Umbraco.MultipleMediaPicker";
|
||||
|
||||
/// <summary>
|
||||
/// Member Picker.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
@@ -15,7 +16,7 @@ namespace Umbraco.Core
|
||||
/// <returns></returns>
|
||||
public static string ToIsoString(this DateTime dt)
|
||||
{
|
||||
return dt.ToString("yyyy-MM-dd HH:mm:ss");
|
||||
return dt.ToString("yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
public static DateTime TruncateTo(this DateTime dt, DateTruncate truncateTo)
|
||||
|
||||
+36
-8
@@ -1,5 +1,7 @@
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using NPoco;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Migrations.Expressions.Common;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
|
||||
@@ -27,31 +29,57 @@ namespace Umbraco.Core.Migrations.Expressions.Delete.KeysAndIndexes
|
||||
{
|
||||
_context.BuildingExpression = false;
|
||||
|
||||
//get a list of all constraints - this will include all PK, FK and unique constraints
|
||||
var tableConstraints = _context.SqlContext.SqlSyntax.GetConstraintsPerTable(_context.Database).DistinctBy(x => x.Item2).ToList();
|
||||
|
||||
//get a list of defined indexes - this will include all indexes, unique indexes and unique constraint indexes
|
||||
var indexes = _context.SqlContext.SqlSyntax.GetDefinedIndexesDefinitions(_context.Database).DistinctBy(x => x.IndexName).ToList();
|
||||
|
||||
var uniqueConstraintNames = tableConstraints.Where(x => !x.Item2.InvariantStartsWith("PK_") && !x.Item2.InvariantStartsWith("FK_")).Select(x => x.Item2);
|
||||
var indexNames = indexes.Select(x => x.IndexName).ToList();
|
||||
|
||||
// drop keys
|
||||
if (DeleteLocal || DeleteForeign)
|
||||
{
|
||||
// table, constraint
|
||||
var tableKeys = _context.SqlContext.SqlSyntax.GetConstraintsPerTable(_context.Database).DistinctBy(x => x.Item2).ToList();
|
||||
|
||||
if (DeleteForeign)
|
||||
{
|
||||
foreach (var key in tableKeys.Where(x => x.Item1 == TableName && x.Item2.StartsWith("FK_")))
|
||||
//In some cases not all FK's are prefixed with "FK" :/ mostly with old upgraded databases so we need to check if it's either:
|
||||
// * starts with FK OR
|
||||
// * doesn't start with PK_ and doesn't exist in the list of indexes
|
||||
|
||||
foreach (var key in tableConstraints.Where(x => x.Item1 == TableName
|
||||
&& (x.Item2.InvariantStartsWith("FK_") || (!x.Item2.InvariantStartsWith("PK_") && !indexNames.InvariantContains(x.Item2)))))
|
||||
{
|
||||
Delete.ForeignKey(key.Item2).OnTable(key.Item1).Do();
|
||||
}
|
||||
|
||||
}
|
||||
if (DeleteLocal)
|
||||
{
|
||||
foreach (var key in tableKeys.Where(x => x.Item1 == TableName && x.Item2.StartsWith("PK_")))
|
||||
foreach (var key in tableConstraints.Where(x => x.Item1 == TableName && x.Item2.InvariantStartsWith("PK_")))
|
||||
Delete.PrimaryKey(key.Item2).FromTable(key.Item1).Do();
|
||||
|
||||
// note: we do *not* delete the DEFAULT constraints
|
||||
// note: we do *not* delete the DEFAULT constraints and if we wanted to we'd have to deal with that in interesting ways
|
||||
// since SQL server has a specific way to handle that, see SqlServerSyntaxProvider.GetDefaultConstraintsPerColumn
|
||||
}
|
||||
}
|
||||
|
||||
// drop indexes
|
||||
if (DeleteLocal)
|
||||
{
|
||||
var indexes = _context.SqlContext.SqlSyntax.GetDefinedIndexesDefinitions(_context.Database).DistinctBy(x => x.IndexName).ToList();
|
||||
{
|
||||
foreach (var index in indexes.Where(x => x.TableName == TableName))
|
||||
Delete.Index(index.IndexName).OnTable(index.TableName).Do();
|
||||
{
|
||||
//if this is a unique constraint we need to drop the constraint, else drop the index
|
||||
//to figure this out, the index must be tagged as unique and it must exist in the tableConstraints
|
||||
|
||||
if (index.IsUnique && uniqueConstraintNames.InvariantContains(index.IndexName))
|
||||
Delete.UniqueConstraint(index.IndexName).FromTable(index.TableName).Do();
|
||||
else
|
||||
Delete.Index(index.IndexName).OnTable(index.TableName).Do();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
|
||||
{
|
||||
class MarkdownEditorPreValueMigrator : DefaultPreValueMigrator //PreValueMigratorBase
|
||||
{
|
||||
public override bool CanMigrate(string editorAlias)
|
||||
=> editorAlias == Constants.PropertyEditors.Aliases.MarkdownEditor;
|
||||
|
||||
protected override object GetPreValueValue(PreValueDto preValue)
|
||||
{
|
||||
if (preValue.Alias == "preview")
|
||||
return preValue.Value == "1";
|
||||
|
||||
return base.GetPreValueValue(preValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,8 @@ public class PreValueMigratorComposer : ICoreComposer
|
||||
.Append<DecimalPreValueMigrator>()
|
||||
.Append<ListViewPreValueMigrator>()
|
||||
.Append<DropDownFlexiblePreValueMigrator>()
|
||||
.Append<ValueListPreValueMigrator>();
|
||||
.Append<ValueListPreValueMigrator>()
|
||||
.Append<MarkdownEditorPreValueMigrator>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,21 +15,17 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
|
||||
{
|
||||
//special trick to add the column without constraints and return the sql to add them later
|
||||
AddColumn<MacroDto>("macroType", out var sqls1);
|
||||
//now we need to update the new column with some values because this column doesn't allow NULL values
|
||||
Update.Table(Constants.DatabaseSchema.Tables.Macro).Set(new { macroType = (int)MacroTypes.Unknown}).AllRows().Do();
|
||||
//now apply constraints (NOT NULL) to new table
|
||||
foreach (var sql in sqls1) Execute.Sql(sql).Do();
|
||||
|
||||
//special trick to add the column without constraints and return the sql to add them later
|
||||
AddColumn<MacroDto>("macroSource", out var sqls2);
|
||||
|
||||
//populate the new macroSource column with legacy data
|
||||
Execute.Sql($"UPDATE {Constants.DatabaseSchema.Tables.Macro} SET macroSource = macroXSLT, macroType = {(int)MacroTypes.Unknown} WHERE macroXSLT IS NOT NULL").Do();
|
||||
Execute.Sql($"UPDATE {Constants.DatabaseSchema.Tables.Macro} SET macroSource = macroScriptAssembly, macroType = {(int)MacroTypes.Unknown} WHERE macroScriptAssembly IS NOT NULL").Do();
|
||||
Execute.Sql($"UPDATE {Constants.DatabaseSchema.Tables.Macro} SET macroSource = macroScriptType, macroType = {(int)MacroTypes.Unknown} WHERE macroScriptType IS NOT NULL").Do();
|
||||
Execute.Sql($"UPDATE {Constants.DatabaseSchema.Tables.Macro} SET macroSource = macroPython, macroType = {(int)MacroTypes.PartialView} WHERE macroPython IS NOT NULL").Do();
|
||||
//populate the new columns with legacy data
|
||||
Execute.Sql($"UPDATE {Constants.DatabaseSchema.Tables.Macro} SET macroSource = '', macroType = {(int)MacroTypes.Unknown}").Do();
|
||||
Execute.Sql($"UPDATE {Constants.DatabaseSchema.Tables.Macro} SET macroSource = macroXSLT, macroType = {(int)MacroTypes.Unknown} WHERE macroXSLT != '' AND macroXSLT IS NOT NULL").Do();
|
||||
Execute.Sql($"UPDATE {Constants.DatabaseSchema.Tables.Macro} SET macroSource = macroScriptAssembly, macroType = {(int)MacroTypes.Unknown} WHERE macroScriptAssembly != '' AND macroScriptAssembly IS NOT NULL").Do();
|
||||
Execute.Sql($"UPDATE {Constants.DatabaseSchema.Tables.Macro} SET macroSource = macroScriptType, macroType = {(int)MacroTypes.Unknown} WHERE macroScriptType != '' AND macroScriptType IS NOT NULL").Do();
|
||||
Execute.Sql($"UPDATE {Constants.DatabaseSchema.Tables.Macro} SET macroSource = macroPython, macroType = {(int)MacroTypes.PartialView} WHERE macroPython != '' AND macroPython IS NOT NULL").Do();
|
||||
|
||||
//now apply constraints (NOT NULL) to new table
|
||||
foreach (var sql in sqls1) Execute.Sql(sql).Do();
|
||||
foreach (var sql in sqls2) Execute.Sql(sql).Do();
|
||||
|
||||
//now remove these old columns
|
||||
|
||||
+2
-2
@@ -50,10 +50,10 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
|
||||
var obj = JsonConvert.DeserializeObject<JObject>(value);
|
||||
var allControls = obj.SelectTokens("$.sections..rows..areas..controls");
|
||||
|
||||
foreach (var control in allControls.SelectMany(c => c))
|
||||
foreach (var control in allControls.SelectMany(c => c).OfType<JObject>())
|
||||
{
|
||||
var controlValue = control["value"];
|
||||
if (controlValue.Type == JTokenType.String)
|
||||
if (controlValue?.Type == JTokenType.String)
|
||||
{
|
||||
control["value"] = UpdateMediaUrls(mediaLinkPattern, controlValue.Value<string>());
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using System.Xml.Linq;
|
||||
using System.Xml.XPath;
|
||||
@@ -575,12 +574,11 @@ namespace Umbraco.Core.Packaging
|
||||
contentType.Thumbnail = infoElement.Element("Thumbnail").Value;
|
||||
contentType.Description = infoElement.Element("Description").Value;
|
||||
|
||||
//NOTE AllowAtRoot is a new property in the package xml so we need to verify it exists before using it.
|
||||
//NOTE AllowAtRoot, IsListView, IsElement and Variations are new properties in the package xml so we need to verify it exists before using it.
|
||||
var allowAtRoot = infoElement.Element("AllowAtRoot");
|
||||
if (allowAtRoot != null)
|
||||
contentType.AllowedAsRoot = allowAtRoot.Value.InvariantEquals("true");
|
||||
|
||||
//NOTE IsListView is a new property in the package xml so we need to verify it exists before using it.
|
||||
var isListView = infoElement.Element("IsListView");
|
||||
if (isListView != null)
|
||||
contentType.IsContainer = isListView.Value.InvariantEquals("true");
|
||||
@@ -589,6 +587,10 @@ namespace Umbraco.Core.Packaging
|
||||
if (isElement != null)
|
||||
contentType.IsElement = isElement.Value.InvariantEquals("true");
|
||||
|
||||
var variationsElement = infoElement.Element("Variations");
|
||||
if (variationsElement != null)
|
||||
contentType.Variations = (ContentVariation)Enum.Parse(typeof(ContentVariation), variationsElement.Value);
|
||||
|
||||
//Name of the master corresponds to the parent and we need to ensure that the Parent Id is set
|
||||
var masterElement = infoElement.Element("Master");
|
||||
if (masterElement != null)
|
||||
@@ -614,7 +616,7 @@ namespace Umbraco.Core.Packaging
|
||||
var compositionContentType = importedContentTypes.ContainsKey(compositionAlias)
|
||||
? importedContentTypes[compositionAlias]
|
||||
: _contentTypeService.Get(compositionAlias);
|
||||
var added = contentType.AddContentType(compositionContentType);
|
||||
contentType.AddContentType(compositionContentType);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -748,9 +750,14 @@ namespace Umbraco.Core.Packaging
|
||||
{
|
||||
Name = property.Element("Name").Value,
|
||||
Description = (string)property.Element("Description"),
|
||||
Mandatory = property.Element("Mandatory") != null ? property.Element("Mandatory").Value.ToLowerInvariant().Equals("true") : false,
|
||||
Mandatory = property.Element("Mandatory") != null
|
||||
? property.Element("Mandatory").Value.ToLowerInvariant().Equals("true")
|
||||
: false,
|
||||
ValidationRegExp = (string)property.Element("Validation"),
|
||||
SortOrder = sortOrder
|
||||
SortOrder = sortOrder,
|
||||
Variations = property.Element("Variations") != null
|
||||
? (ContentVariation)Enum.Parse(typeof(ContentVariation), property.Element("Variations").Value)
|
||||
: ContentVariation.Nothing
|
||||
};
|
||||
|
||||
var tab = (string)property.Element("Tab");
|
||||
|
||||
@@ -174,7 +174,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
totalRecords = page.TotalItems;
|
||||
|
||||
var items = page.Items.Select(
|
||||
dto => new AuditItem(dto.Id, Enum<AuditType>.ParseOrNull(dto.Header) ?? AuditType.Custom, dto.UserId ?? Constants.Security.UnknownUserId, dto.EntityType, dto.Comment, dto.Parameters)).ToList();
|
||||
dto => new AuditItem(dto.NodeId, Enum<AuditType>.ParseOrNull(dto.Header) ?? AuditType.Custom, dto.UserId ?? Constants.Security.UnknownUserId, dto.EntityType, dto.Comment, dto.Parameters)).ToList();
|
||||
|
||||
// map the DateStamp
|
||||
for (var i = 0; i < items.Count; i++)
|
||||
|
||||
@@ -404,7 +404,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
if (isMedia)
|
||||
{
|
||||
sql
|
||||
.InnerJoin<MediaVersionDto>().On<ContentVersionDto, MediaVersionDto>((left, right) => left.Id == right.Id);
|
||||
.LeftJoin<MediaVersionDto>().On<ContentVersionDto, MediaVersionDto>((left, right) => left.Id == right.Id);
|
||||
}
|
||||
|
||||
//Any LeftJoin statements need to come last
|
||||
|
||||
@@ -757,11 +757,11 @@ namespace Umbraco.Core.Services.Implement
|
||||
{
|
||||
var publishedState = content.PublishedState;
|
||||
if (publishedState != PublishedState.Published && publishedState != PublishedState.Unpublished)
|
||||
throw new InvalidOperationException("Cannot save (un)publishing content, use the dedicated SavePublished method.");
|
||||
throw new InvalidOperationException($"Cannot save (un)publishing content with name: {content.Name} - and state: {content.PublishedState}, use the dedicated SavePublished method.");
|
||||
|
||||
if (content.Name != null && content.Name.Length > 255)
|
||||
{
|
||||
throw new InvalidOperationException("Name cannot be more than 255 characters in length.");
|
||||
throw new InvalidOperationException($"Content with the name {content.Name} cannot be more than 255 characters in length.");
|
||||
}
|
||||
|
||||
var evtMsgs = EventMessagesFactory.Get();
|
||||
|
||||
@@ -437,7 +437,8 @@ namespace Umbraco.Core.Services.Implement
|
||||
new XElement("Description", contentType.Description),
|
||||
new XElement("AllowAtRoot", contentType.AllowedAsRoot.ToString()),
|
||||
new XElement("IsListView", contentType.IsContainer.ToString()),
|
||||
new XElement("IsElement", contentType.IsElement.ToString()));
|
||||
new XElement("IsElement", contentType.IsElement.ToString()),
|
||||
new XElement("Variations", contentType.Variations.ToString()));
|
||||
|
||||
var masterContentType = contentType.ContentTypeComposition.FirstOrDefault(x => x.Id == contentType.ParentId);
|
||||
if(masterContentType != null)
|
||||
@@ -487,7 +488,8 @@ namespace Umbraco.Core.Services.Implement
|
||||
new XElement("SortOrder", propertyType.SortOrder),
|
||||
new XElement("Mandatory", propertyType.Mandatory.ToString()),
|
||||
propertyType.ValidationRegExp != null ? new XElement("Validation", propertyType.ValidationRegExp) : null,
|
||||
propertyType.Description != null ? new XElement("Description", new XCData(propertyType.Description)) : null);
|
||||
propertyType.Description != null ? new XElement("Description", new XCData(propertyType.Description)) : null,
|
||||
new XElement("Variations", propertyType.Variations.ToString()));
|
||||
|
||||
genericProperties.Add(genericProperty);
|
||||
}
|
||||
|
||||
@@ -97,8 +97,7 @@ namespace Umbraco.Core.Sync
|
||||
? ":" + request.ServerVariables["SERVER_PORT"]
|
||||
: "";
|
||||
|
||||
var useSsl = globalSettings.UseHttps || port == "443";
|
||||
var ssl = useSsl ? "s" : ""; // force, whatever the first request
|
||||
var ssl = globalSettings.UseHttps ? "s" : ""; // force, whatever the first request
|
||||
var url = "http" + ssl + "://" + request.ServerVariables["SERVER_NAME"] + port + IOHelper.ResolveUrl(SystemDirectories.Umbraco);
|
||||
|
||||
return url.TrimEnd('/');
|
||||
|
||||
@@ -235,6 +235,7 @@
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\IPreValueMigrator.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\ListViewPreValueMigrator.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\MediaPickerPreValueMigrator.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\MarkdownEditorPreValueMigrator.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\NestedContentPreValueMigrator.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\PreValueMigratorCollection.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\PreValueMigratorCollectionBuilder.cs" />
|
||||
|
||||
@@ -268,7 +268,7 @@ AnotherContentFinder
|
||||
public void GetDataEditors()
|
||||
{
|
||||
var types = _typeLoader.GetDataEditors();
|
||||
Assert.AreEqual(38, types.Count());
|
||||
Assert.AreEqual(39, types.Count());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace Umbraco.Tests.Routing
|
||||
{
|
||||
base.SetUp();
|
||||
|
||||
WebFinalComponent.CreateRoutes(
|
||||
WebInitialComponent.CreateRoutes(
|
||||
new TestUmbracoContextAccessor(),
|
||||
TestObjects.GetGlobalSettings(),
|
||||
new SurfaceControllerTypeCollection(Enumerable.Empty<Type>()),
|
||||
|
||||
@@ -1239,6 +1239,11 @@
|
||||
// Perform the button's action.
|
||||
function doClick(button) {
|
||||
|
||||
// don't do anything if the editor input or button bar isn't the currently active element
|
||||
if (document.activeElement !== panels.input && !panels.buttonBar.contains(document.activeElement)) {
|
||||
return;
|
||||
}
|
||||
|
||||
inputBox.focus();
|
||||
|
||||
if (button.textOp) {
|
||||
|
||||
+21
-1
@@ -1,7 +1,7 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function MediaNodeInfoDirective($timeout, $location, eventsService, userService, dateHelper, editorService) {
|
||||
function MediaNodeInfoDirective($timeout, $location, eventsService, userService, dateHelper, editorService, mediaHelper) {
|
||||
|
||||
function link(scope, element, attrs, ctrl) {
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
|
||||
// make sure dates are formatted to the user's locale
|
||||
formatDatesToLocal();
|
||||
|
||||
// set media file extension initially
|
||||
setMediaExtension();
|
||||
}
|
||||
|
||||
function formatDatesToLocal() {
|
||||
@@ -49,6 +52,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
function setMediaExtension() {
|
||||
scope.node.extension = mediaHelper.getFileExtension(scope.nodeUrl);
|
||||
}
|
||||
|
||||
scope.openMediaType = function (mediaType) {
|
||||
var editor = {
|
||||
id: mediaType.id,
|
||||
@@ -62,6 +69,16 @@
|
||||
editorService.mediaTypeEditor(editor);
|
||||
};
|
||||
|
||||
scope.openSVG = function () {
|
||||
var popup = window.open('', '_blank');
|
||||
var html = '<!DOCTYPE html><body><img src="' + scope.nodeUrl + '"/>' +
|
||||
'<script>history.pushState(null, null,"' + $location.$$absUrl + '");</script></body>';
|
||||
|
||||
popup.document.open();
|
||||
popup.document.write(html);
|
||||
popup.document.close();
|
||||
}
|
||||
|
||||
// watch for content updates - reload content when node is saved, published etc.
|
||||
scope.$watch('node.updateDate', function(newValue, oldValue){
|
||||
if(!newValue) { return; }
|
||||
@@ -72,6 +89,9 @@
|
||||
|
||||
// Update the create and update dates
|
||||
formatDatesToLocal();
|
||||
|
||||
//Update the media file format
|
||||
setMediaExtension();
|
||||
});
|
||||
|
||||
//ensure to unregister from all events!
|
||||
|
||||
+14
-13
@@ -1,13 +1,13 @@
|
||||
/**
|
||||
@ngdoc directive
|
||||
@name umbraco.directives.directive:umbFlatpickr
|
||||
@name umbraco.directives.directive:umbDateTimePicker
|
||||
@restrict E
|
||||
@scope
|
||||
|
||||
@description
|
||||
<b>Added in Umbraco version 8.0</b>
|
||||
This directive is a wrapper of the flatpickr library. Use it to render a date time picker.
|
||||
For extra details about options and events take a look here: https://flatpickr.js.org/
|
||||
For extra details about options and events take a look here: https://flatpickr.js.org
|
||||
|
||||
Use this directive to render a date time picker
|
||||
|
||||
@@ -15,11 +15,11 @@ Use this directive to render a date time picker
|
||||
<pre>
|
||||
<div ng-controller="My.Controller as vm">
|
||||
|
||||
<umb-flatpickr
|
||||
<umb-date-time-picker
|
||||
ng-model="vm.date"
|
||||
options="vm.config"
|
||||
on-change="vm.datePickerChange(selectedDates, dateStr, instance)">
|
||||
</umb-flatpickr>
|
||||
</umb-date-time-picker>
|
||||
|
||||
</div>
|
||||
</pre>
|
||||
@@ -70,12 +70,12 @@ Use this directive to render a date time picker
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
var umbFlatpickr = {
|
||||
var umbDateTimePicker = {
|
||||
template: '<ng-transclude>' +
|
||||
'<input type="text" ng-if="!$ctrl.options.inline" ng-model="$ctrl.ngModel" placeholder="Select Date.."></input>' +
|
||||
'<div ng-if="$ctrl.options.inline"></div>' +
|
||||
'</ng-transclude>',
|
||||
controller: umbFlatpickrCtrl,
|
||||
controller: umbDateTimePickerCtrl,
|
||||
transclude: true,
|
||||
bindings: {
|
||||
ngModel: '<',
|
||||
@@ -92,9 +92,9 @@ Use this directive to render a date time picker
|
||||
}
|
||||
};
|
||||
|
||||
function umbFlatpickrCtrl($element, $timeout, $scope, assetsService, userService) {
|
||||
function umbDateTimePickerCtrl($element, $timeout, $scope, assetsService, userService) {
|
||||
|
||||
var ctrl = this;
|
||||
var loaded = false;
|
||||
var userLocale = null;
|
||||
|
||||
ctrl.$onInit = function() {
|
||||
@@ -102,14 +102,14 @@ Use this directive to render a date time picker
|
||||
// load css file for the date picker
|
||||
assetsService.loadCss('lib/flatpickr/flatpickr.css', $scope).then(function () {
|
||||
userService.getCurrentUser().then(function (user) {
|
||||
|
||||
// init date picker
|
||||
userLocale = user.locale;
|
||||
if (userLocale.indexOf('-') > -1) {
|
||||
userLocale = userLocale.split('-')[0];
|
||||
}
|
||||
loaded = true;
|
||||
grabElementAndRunFlatpickr();
|
||||
|
||||
grabElementAndRunFlatpickr();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -234,7 +234,8 @@ Use this directive to render a date time picker
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
angular.module('umbraco.directives').component('umbFlatpickr', umbFlatpickr);
|
||||
|
||||
|
||||
// umbFlatpickr (umb-flatpickr) is deprecated, but we keep it for backwards compatibility
|
||||
angular.module('umbraco.directives').component('umbFlatpickr', umbDateTimePicker);
|
||||
angular.module('umbraco.directives').component('umbDateTimePicker', umbDateTimePicker);
|
||||
})();
|
||||
+3
@@ -17,6 +17,7 @@
|
||||
scope.sortableOptionsGroup = {};
|
||||
scope.sortableOptionsProperty = {};
|
||||
scope.sortingButtonKey = "general_reorder";
|
||||
scope.compositionsButtonState = "init";
|
||||
|
||||
function activate() {
|
||||
|
||||
@@ -343,6 +344,7 @@
|
||||
})), function(f) {
|
||||
return f !== null && f !== undefined;
|
||||
});
|
||||
scope.compositionsButtonState = "busy";
|
||||
$q.all([
|
||||
//get available composite types
|
||||
availableContentTypeResource(scope.model.id, [], propAliasesExisting).then(function (result) {
|
||||
@@ -363,6 +365,7 @@
|
||||
scope.isCompositionsDialogLoading = false;
|
||||
//resolves when both other promises are done, now show it
|
||||
editorService.open(scope.compositionsDialogModel);
|
||||
scope.compositionsButtonState = "init";
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
@ngdoc directive
|
||||
@name umbraco.directives.directive:umbLoader
|
||||
@restrict E
|
||||
|
||||
@description
|
||||
Use this directive to generate a loading indicator.
|
||||
|
||||
<h3>Markup example</h3>
|
||||
<pre>
|
||||
<div ng-controller="My.Controller as vm">
|
||||
|
||||
<umb-loader
|
||||
ng-if="vm.loading">
|
||||
</umb-loader>
|
||||
|
||||
<div class="content" ng-if="!vm.loading">
|
||||
<p>{{content}}</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</pre>
|
||||
|
||||
<h3>Controller example</h3>
|
||||
<pre>
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function Controller(myService) {
|
||||
|
||||
var vm = this;
|
||||
|
||||
vm.content = "";
|
||||
vm.loading = true;
|
||||
|
||||
myService.getContent().then(function(content){
|
||||
vm.content = content;
|
||||
vm.loading = false;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("My.Controller", Controller);
|
||||
})();
|
||||
</pre>
|
||||
|
||||
@param {string=} position The loader position ("top", "bottom").
|
||||
|
||||
**/
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
function UmbLoaderDirective() {
|
||||
|
||||
function link(scope, el, attr, ctrl) {
|
||||
|
||||
}
|
||||
|
||||
var directive = {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'views/components/umb-loader.html',
|
||||
scope: {
|
||||
position: "@?"
|
||||
},
|
||||
link: link
|
||||
};
|
||||
|
||||
return directive;
|
||||
}
|
||||
|
||||
angular.module('umbraco.directives').directive('umbLoader', UmbLoaderDirective);
|
||||
|
||||
})();
|
||||
+1
-1
@@ -39,7 +39,7 @@ Use this directive to generate a loading indicator.
|
||||
});
|
||||
|
||||
}
|
||||
½
|
||||
|
||||
angular.module("umbraco").controller("My.Controller", Controller);
|
||||
})();
|
||||
</pre>
|
||||
|
||||
+156
-151
@@ -1,167 +1,172 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
'use strict';
|
||||
|
||||
function ChangePasswordController($scope) {
|
||||
function ChangePasswordController($scope) {
|
||||
|
||||
function resetModel(isNew) {
|
||||
//the model config will contain an object, if it does not we'll create defaults
|
||||
//NOTE: We will not support doing the password regex on the client side because the regex on the server side
|
||||
//based on the membership provider cannot always be ported to js from .net directly.
|
||||
/*
|
||||
{
|
||||
hasPassword: true/false,
|
||||
requiresQuestionAnswer: true/false,
|
||||
enableReset: true/false,
|
||||
enablePasswordRetrieval: true/false,
|
||||
minPasswordLength: 10
|
||||
}
|
||||
*/
|
||||
var vm = this;
|
||||
|
||||
$scope.showReset = false;
|
||||
vm.$onInit = onInit;
|
||||
vm.$onDestroy = onDestroy;
|
||||
vm.doChange = doChange;
|
||||
vm.cancelChange = cancelChange;
|
||||
vm.showOldPass = showOldPass;
|
||||
vm.showCancelBtn = showCancelBtn;
|
||||
|
||||
//set defaults if they are not available
|
||||
if ($scope.config.disableToggle === undefined) {
|
||||
$scope.config.disableToggle = false;
|
||||
}
|
||||
if ($scope.config.hasPassword === undefined) {
|
||||
$scope.config.hasPassword = false;
|
||||
}
|
||||
if ($scope.config.enablePasswordRetrieval === undefined) {
|
||||
$scope.config.enablePasswordRetrieval = true;
|
||||
}
|
||||
if ($scope.config.requiresQuestionAnswer === undefined) {
|
||||
$scope.config.requiresQuestionAnswer = false;
|
||||
}
|
||||
//don't enable reset if it is new - that doesn't make sense
|
||||
if (isNew === "true") {
|
||||
$scope.config.enableReset = false;
|
||||
}
|
||||
else if ($scope.config.enableReset === undefined) {
|
||||
$scope.config.enableReset = true;
|
||||
}
|
||||
|
||||
if ($scope.config.minPasswordLength === undefined) {
|
||||
$scope.config.minPasswordLength = 0;
|
||||
}
|
||||
|
||||
//set the model defaults
|
||||
if (!angular.isObject($scope.passwordValues)) {
|
||||
//if it's not an object then just create a new one
|
||||
$scope.passwordValues = {
|
||||
newPassword: null,
|
||||
oldPassword: null,
|
||||
reset: null,
|
||||
answer: null
|
||||
};
|
||||
}
|
||||
else {
|
||||
//just reset the values
|
||||
var unsubscribe = [];
|
||||
|
||||
function resetModel(isNew) {
|
||||
//the model config will contain an object, if it does not we'll create defaults
|
||||
//NOTE: We will not support doing the password regex on the client side because the regex on the server side
|
||||
//based on the membership provider cannot always be ported to js from .net directly.
|
||||
/*
|
||||
{
|
||||
hasPassword: true/false,
|
||||
requiresQuestionAnswer: true/false,
|
||||
enableReset: true/false,
|
||||
enablePasswordRetrieval: true/false,
|
||||
minPasswordLength: 10
|
||||
}
|
||||
*/
|
||||
|
||||
vm.showReset = false;
|
||||
|
||||
//set defaults if they are not available
|
||||
if (vm.config.disableToggle === undefined) {
|
||||
vm.config.disableToggle = false;
|
||||
}
|
||||
if (vm.config.hasPassword === undefined) {
|
||||
vm.config.hasPassword = false;
|
||||
}
|
||||
if (vm.config.enablePasswordRetrieval === undefined) {
|
||||
vm.config.enablePasswordRetrieval = true;
|
||||
}
|
||||
if (vm.config.requiresQuestionAnswer === undefined) {
|
||||
vm.config.requiresQuestionAnswer = false;
|
||||
}
|
||||
//don't enable reset if it is new - that doesn't make sense
|
||||
if (isNew === "true") {
|
||||
vm.config.enableReset = false;
|
||||
}
|
||||
else if (vm.config.enableReset === undefined) {
|
||||
vm.config.enableReset = true;
|
||||
}
|
||||
|
||||
if (vm.config.minPasswordLength === undefined) {
|
||||
vm.config.minPasswordLength = 0;
|
||||
}
|
||||
|
||||
//set the model defaults
|
||||
if (!angular.isObject(vm.passwordValues)) {
|
||||
//if it's not an object then just create a new one
|
||||
vm.passwordValues = {
|
||||
newPassword: null,
|
||||
oldPassword: null,
|
||||
reset: null,
|
||||
answer: null
|
||||
};
|
||||
}
|
||||
else {
|
||||
//just reset the values
|
||||
|
||||
if (!isNew) {
|
||||
//if it is new, then leave the generated pass displayed
|
||||
vm.passwordValues.newPassword = null;
|
||||
vm.passwordValues.oldPassword = null;
|
||||
}
|
||||
vm.passwordValues.reset = null;
|
||||
vm.passwordValues.answer = null;
|
||||
}
|
||||
|
||||
//the value to compare to match passwords
|
||||
if (!isNew) {
|
||||
vm.passwordValues.confirm = "";
|
||||
}
|
||||
else if (vm.passwordValues.newPassword && vm.passwordValues.newPassword.length > 0) {
|
||||
//if it is new and a new password has been set, then set the confirm password too
|
||||
vm.passwordValues.confirm = vm.passwordValues.newPassword;
|
||||
}
|
||||
|
||||
if (!isNew) {
|
||||
//if it is new, then leave the generated pass displayed
|
||||
$scope.passwordValues.newPassword = null;
|
||||
$scope.passwordValues.oldPassword = null;
|
||||
}
|
||||
$scope.passwordValues.reset = null;
|
||||
$scope.passwordValues.answer = null;
|
||||
}
|
||||
|
||||
//the value to compare to match passwords
|
||||
if (!isNew) {
|
||||
$scope.passwordValues.confirm = "";
|
||||
}
|
||||
else if ($scope.passwordValues.newPassword && $scope.passwordValues.newPassword.length > 0) {
|
||||
//if it is new and a new password has been set, then set the confirm password too
|
||||
$scope.passwordValues.confirm = $scope.passwordValues.newPassword;
|
||||
}
|
||||
//when the scope is destroyed we need to unsubscribe
|
||||
function onDestroy() {
|
||||
for (var u in unsubscribe) {
|
||||
unsubscribe[u]();
|
||||
}
|
||||
}
|
||||
|
||||
function onInit() {
|
||||
//listen for the saved event, when that occurs we'll
|
||||
//change to changing = false;
|
||||
unsubscribe.push($scope.$on("formSubmitted", function () {
|
||||
if (vm.config.disableToggle === false) {
|
||||
vm.changing = false;
|
||||
}
|
||||
}));
|
||||
|
||||
unsubscribe.push($scope.$on("formSubmitting", function () {
|
||||
//if there was a previously generated password displaying, clear it
|
||||
if (vm.changing && vm.passwordValues) {
|
||||
vm.passwordValues.generatedPassword = null;
|
||||
}
|
||||
else if (!vm.changing) {
|
||||
//we are not changing, so the model needs to be null
|
||||
vm.passwordValues = null;
|
||||
}
|
||||
}));
|
||||
|
||||
resetModel(vm.isNew);
|
||||
|
||||
//if there is no password saved for this entity , it must be new so we do not allow toggling of the change password, it is always there
|
||||
//with validators turned on.
|
||||
vm.changing = vm.config.disableToggle === true || !vm.config.hasPassword;
|
||||
|
||||
//we're not currently changing so set the model to null
|
||||
if (!vm.changing) {
|
||||
vm.passwordValues = null;
|
||||
}
|
||||
}
|
||||
|
||||
function doChange() {
|
||||
resetModel();
|
||||
vm.changing = true;
|
||||
//if there was a previously generated password displaying, clear it
|
||||
vm.passwordValues.generatedPassword = null;
|
||||
vm.passwordValues.confirm = null;
|
||||
};
|
||||
|
||||
function cancelChange() {
|
||||
vm.changing = false;
|
||||
//set model to null
|
||||
vm.passwordValues = null;
|
||||
};
|
||||
|
||||
function showOldPass() {
|
||||
return vm.config.hasPassword &&
|
||||
!vm.config.allowManuallyChangingPassword &&
|
||||
!vm.config.enablePasswordRetrieval && !vm.showReset;
|
||||
};
|
||||
|
||||
// TODO: I don't think we need this or the cancel button, this can be up to the editor rendering this component
|
||||
function showCancelBtn() {
|
||||
return vm.config.disableToggle !== true && vm.config.hasPassword;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
resetModel($scope.isNew);
|
||||
|
||||
//if there is no password saved for this entity , it must be new so we do not allow toggling of the change password, it is always there
|
||||
//with validators turned on.
|
||||
$scope.changing = $scope.config.disableToggle === true || !$scope.config.hasPassword;
|
||||
|
||||
//we're not currently changing so set the model to null
|
||||
if (!$scope.changing) {
|
||||
$scope.passwordValues = null;
|
||||
}
|
||||
|
||||
$scope.doChange = function () {
|
||||
resetModel();
|
||||
$scope.changing = true;
|
||||
//if there was a previously generated password displaying, clear it
|
||||
$scope.passwordValues.generatedPassword = null;
|
||||
$scope.passwordValues.confirm = null;
|
||||
var component = {
|
||||
templateUrl: 'views/components/users/change-password.html',
|
||||
controller: ChangePasswordController,
|
||||
controllerAs: 'vm',
|
||||
bindings: {
|
||||
isNew: "<",
|
||||
passwordValues: "=", //TODO: Do we need bi-directional vals?
|
||||
config: "=" //TODO: Do we need bi-directional vals?
|
||||
//TODO: Do we need callbacks?
|
||||
}
|
||||
};
|
||||
|
||||
$scope.cancelChange = function () {
|
||||
$scope.changing = false;
|
||||
//set model to null
|
||||
$scope.passwordValues = null;
|
||||
};
|
||||
|
||||
var unsubscribe = [];
|
||||
|
||||
//listen for the saved event, when that occurs we'll
|
||||
//change to changing = false;
|
||||
unsubscribe.push($scope.$on("formSubmitted", function () {
|
||||
if ($scope.config.disableToggle === false) {
|
||||
$scope.changing = false;
|
||||
}
|
||||
}));
|
||||
unsubscribe.push($scope.$on("formSubmitting", function () {
|
||||
//if there was a previously generated password displaying, clear it
|
||||
if ($scope.changing && $scope.passwordValues) {
|
||||
$scope.passwordValues.generatedPassword = null;
|
||||
}
|
||||
else if (!$scope.changing) {
|
||||
//we are not changing, so the model needs to be null
|
||||
$scope.passwordValues = null;
|
||||
}
|
||||
}));
|
||||
|
||||
//when the scope is destroyed we need to unsubscribe
|
||||
$scope.$on('$destroy', function () {
|
||||
for (var u in unsubscribe) {
|
||||
unsubscribe[u]();
|
||||
}
|
||||
});
|
||||
|
||||
$scope.showOldPass = function () {
|
||||
return $scope.config.hasPassword &&
|
||||
!$scope.config.allowManuallyChangingPassword &&
|
||||
!$scope.config.enablePasswordRetrieval && !$scope.showReset;
|
||||
};
|
||||
|
||||
// TODO: I don't think we need this or the cancel button, this can be up to the editor rendering this directive
|
||||
$scope.showCancelBtn = function () {
|
||||
return $scope.config.disableToggle !== true && $scope.config.hasPassword;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
function ChangePasswordDirective() {
|
||||
|
||||
var directive = {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'views/components/users/change-password.html',
|
||||
controller: 'Umbraco.Editors.Users.ChangePasswordDirectiveController',
|
||||
scope: {
|
||||
isNew: "=?",
|
||||
passwordValues: "=",
|
||||
config: "="
|
||||
}
|
||||
};
|
||||
|
||||
return directive;
|
||||
|
||||
}
|
||||
|
||||
angular.module('umbraco.directives').controller('Umbraco.Editors.Users.ChangePasswordDirectiveController', ChangePasswordController);
|
||||
angular.module('umbraco.directives').directive('changePassword', ChangePasswordDirective);
|
||||
angular.module('umbraco.directives').component('changePassword', component);
|
||||
|
||||
|
||||
})();
|
||||
|
||||
@@ -104,21 +104,26 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
*
|
||||
* @param {Int} id Id of node to return the public url to
|
||||
* @param {string} type Object type name
|
||||
* @param {string} culture Culture
|
||||
* @returns {Promise} resourcePromise object containing the url.
|
||||
*
|
||||
*/
|
||||
getUrl: function (id, type) {
|
||||
getUrl: function (id, type, culture) {
|
||||
|
||||
if (id === -1 || id === "-1") {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (!culture) {
|
||||
culture = "";
|
||||
}
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"entityApiBaseUrl",
|
||||
"GetUrl",
|
||||
[{ id: id }, {type: type }])),
|
||||
[{ id: id }, {type: type }, {culture: culture }])),
|
||||
'Failed to retrieve url for id:' + id);
|
||||
},
|
||||
|
||||
|
||||
@@ -491,7 +491,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt
|
||||
var savedVariants = [];
|
||||
if (origContent.variants) {
|
||||
isContent = true;
|
||||
//it's contnet so assign the variants as they exist
|
||||
//it's content so assign the variants as they exist
|
||||
origVariants = origContent.variants;
|
||||
savedVariants = savedContent.variants;
|
||||
}
|
||||
@@ -517,7 +517,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt
|
||||
|
||||
//special case for content, don't sync this variant if it wasn't tagged
|
||||
//for saving in the first place
|
||||
if (!origVariant.save) {
|
||||
if (isContent && !origVariant.save) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@
|
||||
@import "components/umb-editor-navigation-item.less";
|
||||
@import "components/umb-editor-sub-views.less";
|
||||
@import "components/editor/subheader/umb-editor-sub-header.less";
|
||||
@import "components/umb-flatpickr.less";
|
||||
@import "components/umb-date-time-picker.less";
|
||||
@import "components/umb-grid-selector.less";
|
||||
@import "components/umb-child-selector.less";
|
||||
@import "components/umb-group-builder.less";
|
||||
@@ -124,6 +124,7 @@
|
||||
@import "components/umb-form-check.less";
|
||||
@import "components/umb-locked-field.less";
|
||||
@import "components/umb-tabs.less";
|
||||
@import "components/umb-loader.less";
|
||||
@import "components/umb-load-indicator.less";
|
||||
@import "components/umb-breadcrumbs.less";
|
||||
@import "components/umb-media-grid.less";
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
.umb-tour__loader {
|
||||
background: @white;
|
||||
z-index: @zindexTourModal;
|
||||
.umb-loader-wrapper.umb-tour__loader {
|
||||
margin: 0;
|
||||
position: fixed;
|
||||
height: 5px;
|
||||
z-index: @zindexTourModal;
|
||||
|
||||
.umb-loader {
|
||||
background-color: @white;
|
||||
height: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-tour__pulse {
|
||||
|
||||
@@ -376,14 +376,3 @@ a.umb-variant-switcher__toggle {
|
||||
margin-right: auto;
|
||||
padding-right: 10px;
|
||||
}
|
||||
|
||||
/* Confirm */
|
||||
.umb-editor-confirm {
|
||||
background-color: @white;
|
||||
padding: 20px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
z-index: 10;
|
||||
box-shadow: 0 -3px 12px 0px rgba(0,0,0,0.16);
|
||||
}
|
||||
|
||||
@@ -39,17 +39,10 @@
|
||||
|
||||
// Loading Animation
|
||||
// ------------------------
|
||||
.l {
|
||||
.umb-tree-item__loader {
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: -1px;
|
||||
|
||||
div {
|
||||
.umb-loader;
|
||||
}
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.umb-tree-item__label {
|
||||
|
||||
@@ -33,12 +33,6 @@
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
//loader defaults
|
||||
.umb-loader {
|
||||
height: 10px;
|
||||
margin: 10px 10px 10px 10px;
|
||||
}
|
||||
|
||||
.search-subtitle {
|
||||
color: @gray-7;
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
.flatpickr-calendar.flatpickr-calendar {
|
||||
.flatpickr-calendar {
|
||||
border-radius: @baseBorderRadius;
|
||||
box-shadow: 0 5px 10px 0 rgba(0,0,0,0.16);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
// Loading Animation
|
||||
// ------------------------
|
||||
|
||||
.umb-loader {
|
||||
background-color: @blue;
|
||||
margin-top: 0;
|
||||
margin-left: -100%;
|
||||
animation-name: bounce_loadingProgressG;
|
||||
animation-duration: 1s;
|
||||
animation-iteration-count: infinite;
|
||||
animation-timing-function: linear;
|
||||
width: 100%;
|
||||
height: 2px;
|
||||
}
|
||||
|
||||
@keyframes bounce_loadingProgressG {
|
||||
0% {
|
||||
margin-left: -100%;
|
||||
}
|
||||
|
||||
100% {
|
||||
margin-left: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-loader-wrapper {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
margin: 10px 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.umb-loader-wrapper.-top {
|
||||
top: 0;
|
||||
bottom: auto;
|
||||
}
|
||||
|
||||
.umb-loader-wrapper.-bottom {
|
||||
top: auto;
|
||||
bottom: 0;
|
||||
}
|
||||
@@ -295,7 +295,11 @@ input.umb-table__input {
|
||||
.umb-table__row-expand {
|
||||
font-size: 12px;
|
||||
text-decoration: none;
|
||||
color: @black;
|
||||
color: @gray-4;
|
||||
|
||||
&:hover {
|
||||
color: @black;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-table__row-expand--hidden {
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
@import "../../lib/bootstrap/less/thumbnails.less";
|
||||
@import "../../lib/bootstrap/less/media.less";
|
||||
|
||||
// Umbraco Components
|
||||
@import "components/umb-loader.less";
|
||||
|
||||
|
||||
[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak {
|
||||
display: none !important;
|
||||
@@ -165,45 +168,17 @@ input.ng-dirty.ng-invalid{border-color: #b94a48; color: #b94a48;}
|
||||
opacity:1;
|
||||
}
|
||||
|
||||
.umb-installer-loader {
|
||||
margin: 0;
|
||||
width: 0;
|
||||
z-index: 777;
|
||||
|
||||
.umb-loader{
|
||||
background-color: @white;
|
||||
margin-top:0;
|
||||
margin-left:-100%;
|
||||
animation-name:bounce_loadingProgressG;
|
||||
animation-duration:1s;
|
||||
animation-iteration-count:infinite;
|
||||
animation-timing-function:linear;
|
||||
width:100%;
|
||||
height: 5px;
|
||||
}
|
||||
|
||||
@keyframes bounce_loadingProgressG{
|
||||
0%{
|
||||
margin-left:-100%;
|
||||
}
|
||||
100%{
|
||||
margin-left:100%;
|
||||
.umb-loader {
|
||||
background-color: @white;
|
||||
height: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
//loader defaults
|
||||
.umb-loader-container, .umb-loader-done{
|
||||
height: 3px;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
overflow: hidden;
|
||||
width: 0%;
|
||||
z-index: 777;
|
||||
}
|
||||
|
||||
.umb-loader-done{
|
||||
right: 0%;
|
||||
background: @white;
|
||||
}
|
||||
|
||||
|
||||
.permissions-report {
|
||||
overflow:auto;
|
||||
height:320px;
|
||||
|
||||
@@ -486,42 +486,6 @@ table thead a {
|
||||
color:@green;
|
||||
}
|
||||
|
||||
// Loading Animation
|
||||
// ------------------------
|
||||
|
||||
.umb-loader{
|
||||
background-color: @blue;
|
||||
margin-top:0;
|
||||
margin-left:-100%;
|
||||
animation-name:bounce_loadingProgressG;
|
||||
animation-duration:1s;
|
||||
animation-iteration-count:infinite;
|
||||
animation-timing-function:linear;
|
||||
width:100%;
|
||||
height:2px;
|
||||
}
|
||||
|
||||
@keyframes bounce_loadingProgressG{
|
||||
0%{
|
||||
margin-left:-100%;
|
||||
}
|
||||
100%{
|
||||
margin-left:100%;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-loader-wrapper {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
left: 0;
|
||||
margin: 10px 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.umb-loader-wrapper.-bottom {
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
// Helpers
|
||||
|
||||
.strong {
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
// --------------------------------------------------
|
||||
.umb-property-editor {
|
||||
width: 100%;
|
||||
position:relative;
|
||||
}
|
||||
|
||||
.umb-property-editor-tiny {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*/
|
||||
function MainController($scope, $location, appState, treeService, notificationsService,
|
||||
userService, historyService, updateChecker, navigationService, eventsService,
|
||||
tmhDynamicLocale, localStorageService, editorService, overlayService) {
|
||||
tmhDynamicLocale, localStorageService, editorService, overlayService, assetsService, tinyMceAssets) {
|
||||
|
||||
//the null is important because we do an explicit bool check on this in the view
|
||||
$scope.authenticated = null;
|
||||
@@ -21,7 +21,13 @@ function MainController($scope, $location, appState, treeService, notificationsS
|
||||
$scope.search = {};
|
||||
$scope.login = {};
|
||||
$scope.tabbingActive = false;
|
||||
|
||||
|
||||
// Load TinyMCE assets ahead of time in the background for the user
|
||||
// To help with first load of the RTE
|
||||
tinyMceAssets.forEach(function (tinyJsAsset) {
|
||||
assetsService.loadJs(tinyJsAsset, $scope);
|
||||
});
|
||||
|
||||
// There are a number of ways to detect when a focus state should be shown when using the tab key and this seems to be the simplest solution.
|
||||
// For more information about this approach, see https://hackernoon.com/removing-that-ugly-focus-ring-and-keeping-it-too-6c8727fefcd2
|
||||
function handleFirstTab(evt) {
|
||||
|
||||
+21
-5
@@ -1,7 +1,7 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function CompositionsController($scope, $location, $filter) {
|
||||
function CompositionsController($scope, $location, $filter, overlayService) {
|
||||
|
||||
var vm = this;
|
||||
var oldModel = null;
|
||||
@@ -56,19 +56,35 @@
|
||||
if ($scope.model && $scope.model.submit) {
|
||||
|
||||
// check if any compositions has been removed
|
||||
vm.compositionRemoved = false;
|
||||
var compositionRemoved = false;
|
||||
for (var i = 0; oldModel.compositeContentTypes.length > i; i++) {
|
||||
var oldComposition = oldModel.compositeContentTypes[i];
|
||||
if (_.contains($scope.model.compositeContentTypes, oldComposition) === false) {
|
||||
vm.compositionRemoved = true;
|
||||
compositionRemoved = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* submit the form if there havne't been removed any composition
|
||||
or the confirm checkbox has been checked */
|
||||
if (!vm.compositionRemoved || vm.allowSubmit) {
|
||||
$scope.model.submit($scope.model);
|
||||
if (compositionRemoved) {
|
||||
vm.allowSubmit = false;
|
||||
const dialog = {
|
||||
view: "views/common/infiniteeditors/compositions/overlays/confirmremove.html",
|
||||
submitButtonLabelKey: "general_ok",
|
||||
closeButtonLabelKey: "general_cancel",
|
||||
submit: function (model) {
|
||||
$scope.model.submit($scope.model);
|
||||
overlayService.close();
|
||||
},
|
||||
close: function () {
|
||||
overlayService.close();
|
||||
}
|
||||
};
|
||||
overlayService.open(dialog);
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.model.submit($scope.model);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-10
@@ -92,16 +92,6 @@
|
||||
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
|
||||
<div ng-if="vm.compositionRemoved" class="umb-editor-confirm">
|
||||
<h5 class="red"><i class="icon-alert"></i>Warning</h5>
|
||||
<p>Removing a composition will delete all the associated property data. Once you save the document type there's no way back, are you sure?</p>
|
||||
<label class="checkbox no-indent">
|
||||
<input type="checkbox" ng-model="vm.allowSubmit" />
|
||||
<strong>I know what I'm doing</strong>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
</umb-editor-container>
|
||||
|
||||
<umb-editor-footer>
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
<div>
|
||||
|
||||
<h5 class="red"><i class="icon-alert"></i>Warning</h5>
|
||||
<p>Removing a composition will delete all the associated property data. Once you save the document type there's no way back, are you sure?</p>
|
||||
|
||||
</div>
|
||||
+1
-1
@@ -93,7 +93,7 @@ angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
|
||||
});
|
||||
|
||||
}
|
||||
} else if ($scope.model.target.url.length) {
|
||||
} else if ($scope.model.target.url && $scope.model.target.url.length) {
|
||||
// a url but no id/udi indicates an external link - trim the url to remove the anchor/qs
|
||||
// only do the substring if there's a # or a ?
|
||||
var indexOfAnchor = $scope.model.target.url.search(/(#|\?)/);
|
||||
|
||||
+2
-2
@@ -109,10 +109,10 @@
|
||||
<input type="number" ng-switch-when="int" style="width:90px; margin-bottom: 0;" ng-model="filter.constraintValue" ng-change="vm.changeConstraintValue()" />
|
||||
|
||||
<span ng-switch-when="datetime">
|
||||
<umb-flatpickr
|
||||
<umb-date-time-picker
|
||||
options="vm.datePickerConfig"
|
||||
on-change="vm.datePickerChange(dateStr, filter)">
|
||||
</umb-flatpickr>
|
||||
</umb-date-time-picker>
|
||||
</span>
|
||||
|
||||
</span>
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
</p>
|
||||
|
||||
<div class="control-group" ng-class="{error: vm.setPasswordForm.password.$invalid}">
|
||||
<label>
|
||||
<label for="umb-password">
|
||||
<localize key="user_newPassword">New password</localize>
|
||||
<small style="font-size: 13px;">{{vm.invitedUserPasswordModel.passwordPolicyText}}</small>
|
||||
</label>
|
||||
<input type="password" ng-model="vm.invitedUserPasswordModel.password" name="password" class="-full-width-input" umb-auto-focus required val-server-field="value" ng-minlength="{{vm.invitedUserPasswordModel.passwordPolicies.minPasswordLength}}" />
|
||||
<input type="password" ng-model="vm.invitedUserPasswordModel.password" name="password" id="umb-password" class="-full-width-input" umb-auto-focus required val-server-field="value" ng-minlength="{{vm.invitedUserPasswordModel.passwordPolicies.minPasswordLength}}" />
|
||||
<span ng-messages="inviteUserPasswordForm.password.$error" show-validation-on-submit >
|
||||
<span class="help-inline" ng-message="required"><localize key="user_passwordIsBlank">Your new password cannot be blank!</localize></span>
|
||||
<span class="help-inline" ng-message="minlength">Minimum {{vm.invitedUserPasswordModel.passwordPolicies.minPasswordLength}} characters</span>
|
||||
@@ -31,8 +31,8 @@
|
||||
</div>
|
||||
|
||||
<div class="control-group" ng-class="{error: vm.setPasswordForm.confirmPassword.$invalid}">
|
||||
<label><localize key="user_confirmNewPassword">Confirm new password</localize></label>
|
||||
<input type="password" ng-model="vm.invitedUserPasswordModel.confirmPassword" name="confirmPassword" class="-full-width-input" required val-compare="password" />
|
||||
<label for="umb-confirmPassword"><localize key="user_confirmNewPassword">Confirm new password</localize></label>
|
||||
<input type="password" ng-model="vm.invitedUserPasswordModel.confirmPassword" name="confirmPassword" id="umb-confirmPassword" class="-full-width-input" required val-compare="password" />
|
||||
<span ng-messages="inviteUserPasswordForm.confirmPassword.$error" show-validation-on-submit >
|
||||
<span class="help-inline" ng-message="required"><localize key="general_required">Required</localize></span>
|
||||
<span class="help-inline" ng-message="valCompare"><localize key="user_passwordMismatch">The confirmed password doesn't match the new password!</localize></span>
|
||||
@@ -152,13 +152,13 @@
|
||||
<p ng-message="auth" class="text-error" role="alert">{{vm.errorMsg}}</p>
|
||||
</div>
|
||||
<div class="control-group" ng-class="{error: vm.loginForm.username.$invalid}">
|
||||
<label>{{vm.labels.usernameLabel}}</label>
|
||||
<input type="text" ng-model="vm.login" name="username" class="-full-width-input" placeholder="{{vm.labels.usernamePlaceholder}}" focus-when="{{vm.view === 'login'}}" />
|
||||
<label for="umb-username">{{vm.labels.usernameLabel}}</label>
|
||||
<input type="text" ng-model="vm.login" name="username" id="umb-username" class="-full-width-input" placeholder="{{vm.labels.usernamePlaceholder}}" focus-when="{{vm.view === 'login'}}" />
|
||||
</div>
|
||||
|
||||
<div class="control-group" ng-class="{error: vm.loginForm.password.$invalid}">
|
||||
<label><localize key="general_password">Password</localize></label>
|
||||
<input type="password" ng-model="vm.password" name="password" class="-full-width-input" localize="placeholder" placeholder="@placeholders_password" />
|
||||
<label for="umb-password"><localize key="general_password">Password</localize></label>
|
||||
<input type="password" ng-model="vm.password" name="password" id="umb-password" class="-full-width-input" localize="placeholder" placeholder="@placeholders_password" />
|
||||
<div class="password-toggle">
|
||||
<a href="#" prevent-default ng-click="vm.togglePassword()">
|
||||
<span class="password-text show"><localize key="login_showPassword">Show password</localize></span>
|
||||
@@ -189,8 +189,8 @@
|
||||
|
||||
<form method="POST" name="vm.requestPasswordResetForm" ng-submit="vm.requestPasswordResetSubmit(email)">
|
||||
<div class="control-group" ng-class="{error: requestPasswordResetForm.email.$invalid}">
|
||||
<label><localize key="general_email">Email</localize></label>
|
||||
<input type="email" val-email ng-model="email" name="email" class="-full-width-input" localize="placeholder" placeholder="@placeholders_email" focus-when="{{vm.view === 'request-password-reset'}}" />
|
||||
<label for="umb-email"><localize key="general_email">Email</localize></label>
|
||||
<input type="email" val-email ng-model="email" name="email" id="umb-email" class="-full-width-input" localize="placeholder" placeholder="@placeholders_email" focus-when="{{vm.view === 'request-password-reset'}}" />
|
||||
</div>
|
||||
|
||||
<div class="control-group" ng-show="requestPasswordResetForm.$invalid">
|
||||
@@ -220,13 +220,13 @@
|
||||
<form method="POST" name="vm.setPasswordForm" ng-submit="vm.setPasswordSubmit(vm.password, vm.confirmPassword)">
|
||||
|
||||
<div ng-hide="vm.resetComplete" class="control-group" ng-class="{error: vm.setPasswordForm.password.$invalid}">
|
||||
<label><localize key="user_newPassword">New password</localize></label>
|
||||
<input type="password" ng-model="vm.password" name="password" class="-full-width-input" localize="placeholder" placeholder="@placeholders_password" focus-when="{{vm.view === 'set-password'}}" />
|
||||
<label for="umb-password"><localize key="user_newPassword">New password</localize></label>
|
||||
<input type="password" ng-model="vm.password" name="password" id="umb-password" class="-full-width-input" localize="placeholder" placeholder="@placeholders_password" focus-when="{{vm.view === 'set-password'}}" />
|
||||
</div>
|
||||
|
||||
<div ng-hide="vm.resetComplete" class="control-group" ng-class="{error: vm.setPasswordForm.confirmPassword.$invalid}">
|
||||
<label><localize key="user_confirmNewPassword">Confirm new password</localize></label>
|
||||
<input type="password" ng-model="vm.confirmPassword" name="confirmPassword" class="-full-width-input" localize="placeholder" placeholder="@placeholders_confirmPassword" />
|
||||
<label for="umb-confirmPassword"><localize key="user_confirmNewPassword">Confirm new password</localize></label>
|
||||
<input type="password" ng-model="vm.confirmPassword" name="confirmPassword" id="umb-confirmPassword" class="-full-width-input" localize="placeholder" placeholder="@placeholders_confirmPassword" />
|
||||
</div>
|
||||
|
||||
<div ng-hide="vm.resetComplete" class="control-group" ng-show="vm.setPasswordForm.$invalid">
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<div class="umb-tour">
|
||||
|
||||
<div class="umb-loader umb-tour__loader" ng-if="loadingStep"></div>
|
||||
<umb-loader class="umb-tour__loader" ng-if="loadingStep"></umb-loader>
|
||||
|
||||
<div class="umb-tour__pulse"></div>
|
||||
|
||||
<div class="umb-tour__popover shadow-depth-2" ng-class="{'umb-tour__popover--l': model.currentStep.type === 'intro' || model.currentStepIndex === model.steps.length}">
|
||||
|
||||
@@ -12,9 +12,10 @@
|
||||
|
||||
<ul ng-if="nodeUrl" class="nav nav-stacked" style="margin-bottom: 0;">
|
||||
<li>
|
||||
<a href="{{nodeUrl}}" target="_blank">
|
||||
<i class="icon icon-out"></i>
|
||||
<span>{{nodeFileName}}</span>
|
||||
<a ng-attr-href="{{node.extension !== 'svg' ? nodeUrl : undefined}}" ng-click="node.extension === 'svg' && openSVG()" target="_blank">
|
||||
<i class="icon icon-out"></i>
|
||||
<span>{{nodeFileName}}</span>
|
||||
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
|
||||
<!-- NOTE: These are the 'option' elipses -->
|
||||
<button data-element="tree-item-options" class="umb-options btn-reset sr-only sr-only--focusable sr-only--hoverable" ng-click="options(node, $event)" ng-if="::node.menuUrl"><i></i><i></i><i></i></button>
|
||||
<div ng-show="node.loading" class="l"><div></div></div>
|
||||
|
||||
<umb-loader ng-show="node.loading" position="bottom" class="umb-tree-item__loader"></umb-loader>
|
||||
</div>
|
||||
|
||||
<ul ng-class="{collapsed: !node.expanded}">
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
icon="icon-merge"
|
||||
action="openCompositionsDialog()"
|
||||
size="xs"
|
||||
add-ellipsis="true">
|
||||
add-ellipsis="true"
|
||||
state="compositionsButtonState">
|
||||
</umb-button>
|
||||
|
||||
<umb-button
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<div class="umb-loader-wrapper" ng-class="{ '-top': position === 'top', '-bottom': position === 'bottom' }">
|
||||
<div class="umb-loader"></div>
|
||||
</div>
|
||||
@@ -60,7 +60,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Items -->
|
||||
<div class="umb-table-row"
|
||||
<div class="umb-table-row cursor-pointer"
|
||||
ng-repeat="child in miniListView.children"
|
||||
ng-click="selectNode(child)"
|
||||
ng-class="{'-selected':child.selected, 'not-allowed':!child.allowed}">
|
||||
|
||||
@@ -1,68 +1,69 @@
|
||||
<div>
|
||||
<div class="alert alert-success text-center" ng-hide="!passwordValues.generatedPassword">
|
||||
<div class="alert alert-success text-center" ng-hide="!vm.passwordValues.generatedPassword">
|
||||
<small>Password has been reset to:</small>
|
||||
<br />
|
||||
<strong>{{passwordValues.generatedPassword}}</strong>
|
||||
<strong>{{vm.passwordValues.generatedPassword}}</strong>
|
||||
</div>
|
||||
<div ng-switch="changing">
|
||||
<div ng-switch="vm.changing">
|
||||
<div ng-switch-when="false">
|
||||
<a href="" ng-click="doChange()" class="btn btn-small">
|
||||
<a href="" ng-click="vm.doChange()" class="btn btn-small">
|
||||
<localize key="general_changePassword">Change password</localize>
|
||||
</a>
|
||||
</div>
|
||||
<div ng-switch-when="true">
|
||||
<ng-form name="passwordForm">
|
||||
<umb-control-group alias="resetPassword" label="@user_resetPassword" ng-show="config.enableReset">
|
||||
<input type="checkbox" ng-model="passwordValues.reset"
|
||||
|
||||
<ng-form name="vm.passwordForm">
|
||||
<umb-control-group alias="resetPassword" label="@user_resetPassword" ng-show="vm.config.enableReset">
|
||||
<input type="checkbox" ng-model="vm.passwordValues.reset"
|
||||
id="Checkbox1"
|
||||
name="resetPassword"
|
||||
val-server-field="resetPassword"
|
||||
no-dirty-check
|
||||
ng-change="showReset = !showReset" />
|
||||
<span ng-messages="passwordForm.resetPassword.$error" show-validation-on-submit >
|
||||
<span class="help-inline" ng-message="valServerField">{{passwordForm.resetPassword.errorMsg}}</span>
|
||||
ng-change="vm.showReset = !vm.showReset" />
|
||||
<span ng-messages="vm.passwordForm.resetPassword.$error" show-validation-on-submit>
|
||||
<span class="help-inline" ng-message="valServerField">{{vm.passwordForm.resetPassword.errorMsg}}</span>
|
||||
</span>
|
||||
|
||||
</umb-control-group>
|
||||
|
||||
</umb-control-group>
|
||||
|
||||
<!-- we need to show the old pass field when the provider cannot retrieve the password -->
|
||||
<umb-control-group alias="oldPassword" label="@user_oldPassword" ng-if="showOldPass()" required="true">
|
||||
<input type="password" name="oldPassword" ng-model="passwordValues.oldPassword"
|
||||
<umb-control-group alias="oldPassword" label="@user_oldPassword" ng-if="vm.showOldPass()" required="true">
|
||||
<input type="password" name="oldPassword" ng-model="vm.passwordValues.oldPassword"
|
||||
class="input-block-level umb-textstring textstring"
|
||||
required
|
||||
val-server-field="oldPassword"
|
||||
no-dirty-check />
|
||||
<span ng-messages="passwordForm.oldPassword.$error" show-validation-on-submit >
|
||||
<span ng-messages="vm.passwordForm.oldPassword.$error" show-validation-on-submit>
|
||||
<span class="help-inline" ng-message="required">Required</span>
|
||||
<span class="help-inline" ng-message="valServerField">{{passwordForm.oldPassword.errorMsg}}</span>
|
||||
<span class="help-inline" ng-message="valServerField">{{vm.passwordForm.oldPassword.errorMsg}}</span>
|
||||
</span>
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group alias="password" label="@user_newPassword" ng-if="!showReset" required="true">
|
||||
<input type="password" name="password" ng-model="passwordValues.newPassword"
|
||||
<umb-control-group alias="password" label="@user_newPassword" ng-if="!vm.showReset" required="true">
|
||||
<input type="password" name="password" ng-model="vm.passwordValues.newPassword"
|
||||
class="input-block-level umb-textstring textstring"
|
||||
required
|
||||
val-server-field="password"
|
||||
ng-minlength="{{config.minPasswordLength}}"
|
||||
ng-minlength="{{vm.config.minPasswordLength}}"
|
||||
no-dirty-check />
|
||||
<span ng-messages="passwordForm.password.$error" show-validation-on-submit >
|
||||
<span ng-messages="vm.passwordForm.password.$error" show-validation-on-submit>
|
||||
<span class="help-inline" ng-message="required">Required</span>
|
||||
<span class="help-inline" ng-message="minlength">Minimum {{config.minPasswordLength}} characters</span>
|
||||
<span class="help-inline" ng-message="valServerField">{{passwordForm.password.errorMsg}}</span>
|
||||
<span class="help-inline" ng-message="minlength">Minimum {{vm.config.minPasswordLength}} characters</span>
|
||||
<span class="help-inline" ng-message="valServerField">{{vm.passwordForm.password.errorMsg}}</span>
|
||||
</span>
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group alias="confirmpassword" label="@user_confirmNewPassword" ng-if="!showReset" required="true">
|
||||
<input type="password" name="confirmpassword" ng-model="passwordValues.confirm"
|
||||
<umb-control-group alias="confirmpassword" label="@user_confirmNewPassword" ng-if="!vm.showReset" required="true">
|
||||
<input type="password" name="confirmpassword" ng-model="vm.passwordValues.confirm"
|
||||
class="input-block-level umb-textstring textstring"
|
||||
val-compare="password"
|
||||
no-dirty-check />
|
||||
<span ng-messages="passwordForm.confirmpassword.$error" show-validation-on-submit >
|
||||
<span ng-messages="vm.passwordForm.confirmpassword.$error" show-validation-on-submit>
|
||||
<span class="help-inline" ng-message="valCompare"><localize key="user_passwordMismatch">The confirmed password doesn't match the new password!</localize></span>
|
||||
</span>
|
||||
</umb-control-group>
|
||||
|
||||
<a href="" ng-click="cancelChange()" ng-show="showCancelBtn()" class="btn btn-small">
|
||||
<a href="" ng-click="vm.cancelChange()" ng-show="vm.showCancelBtn()" class="btn btn-small">
|
||||
<localize key="general_cancel">Cancel</localize>
|
||||
</a>
|
||||
|
||||
|
||||
@@ -51,7 +51,10 @@ function contentCreateController($scope,
|
||||
.search("create", "true")
|
||||
/* when we create a new node we want to make sure it uses the same
|
||||
language as what is selected in the tree */
|
||||
.search("cculture", mainCulture);
|
||||
.search("cculture", mainCulture)
|
||||
/* when we create a new node we must make sure that any previously
|
||||
used blueprint is reset */
|
||||
.search("blueprintId", null);
|
||||
close();
|
||||
}
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ function ContentDeleteController($scope, $timeout, contentResource, treeService,
|
||||
$location.path(location);
|
||||
}
|
||||
|
||||
navigationService.hideMenu();
|
||||
$scope.success = true;
|
||||
}, function(err) {
|
||||
|
||||
toggleDeleting(false);
|
||||
@@ -74,7 +74,11 @@ function ContentDeleteController($scope, $timeout, contentResource, treeService,
|
||||
|
||||
$scope.cancel = function() {
|
||||
toggleDeleting(false);
|
||||
navigationService.hideDialog();
|
||||
$scope.close();
|
||||
};
|
||||
|
||||
$scope.close = function () {
|
||||
navigationService.hideDialog();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -24,9 +24,7 @@
|
||||
<localize key="actions_toInTheTreeStructureBelow">to in the tree structure below</localize>
|
||||
</p>
|
||||
|
||||
<div class="umb-loader-wrapper" ng-show="busy">
|
||||
<div class="umb-loader"></div>
|
||||
</div>
|
||||
<umb-loader ng-show="busy"></umb-loader>
|
||||
|
||||
<div ng-hide="success">
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
</ul>
|
||||
<ul class="umb-actions umb-actions-child" ng-if="selectBlueprint">
|
||||
|
||||
<li class="umb-action" ng-repeat="blueprint in selectableBlueprints | orderBy:'name':false">
|
||||
<li class="umb-action" ng-repeat="blueprint in selectableBlueprints | orderBy:'name':false track by $index">
|
||||
<button class="umb-action-link umb-outline btn-reset" ng-click="createFromBlueprint(blueprint.id)">
|
||||
<i class="large icon {{docType.icon}}"></i>
|
||||
<span class="menu-label">
|
||||
|
||||
@@ -1,15 +1,25 @@
|
||||
<div class="umb-dialog umb-pane" ng-controller="Umbraco.Editors.Content.DeleteController">
|
||||
<div class="umb-dialog-body" auto-scale="90">
|
||||
|
||||
<p class="abstract">
|
||||
<localize key="defaultdialogs_confirmdelete">Are you sure you want to delete</localize> <strong>{{currentNode.name}}</strong>?
|
||||
</p>
|
||||
|
||||
<div class="umb-alert umb-alert--warning">
|
||||
<localize key="defaultdialogs_variantdeletewarning">This will delete the node and all its languages. If you only want to delete one language go and unpublish it instead.</localize>
|
||||
<div ng-show="success">
|
||||
<div class="alert alert-success">
|
||||
<strong>{{currentNode.name}}</strong>
|
||||
<localize key="actions_wasDeleted">was deleted</localize>
|
||||
</div>
|
||||
<button class="btn btn-primary" ng-click="close()">Ok</button>
|
||||
</div>
|
||||
|
||||
<umb-confirm on-confirm="performDelete" confirm-button-style="danger" on-cancel="cancel"></umb-confirm>
|
||||
<div ng-hide="success">
|
||||
<p class="abstract">
|
||||
<localize key="defaultdialogs_confirmdelete">Are you sure you want to delete</localize> <strong>{{currentNode.name}}</strong>?
|
||||
</p>
|
||||
|
||||
<div class="umb-alert umb-alert--warning">
|
||||
<localize key="defaultdialogs_variantdeletewarning">This will delete the node and all its languages. If you only want to delete one language go and unpublish it instead.</localize>
|
||||
</div>
|
||||
|
||||
<umb-confirm on-confirm="performDelete" confirm-button-style="danger" on-cancel="cancel"></umb-confirm>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
<div class="umb-dialog" ng-controller="Umbraco.Editors.Content.EmptyRecycleBinController">
|
||||
<div class="umb-dialog-body">
|
||||
<umb-pane>
|
||||
<div class="umb-loader-wrapper" ng-show="busy">
|
||||
<div class="umb-loader"></div>
|
||||
</div>
|
||||
|
||||
<umb-loader ng-show="busy"></umb-loader>
|
||||
|
||||
<p class="abstract">
|
||||
<localize key="defaultdialogs_recycleBinWarning">When items are deleted from the recycle bin, they will be gone forever</localize>.
|
||||
|
||||
@@ -24,9 +24,7 @@
|
||||
<localize key="actions_toInTheTreeStructureBelow">to in the tree structure below</localize>
|
||||
</p>
|
||||
|
||||
<div class="umb-loader-wrapper" ng-show="busy">
|
||||
<div class="umb-loader"></div>
|
||||
</div>
|
||||
<umb-loader ng-show="busy"></umb-loader>
|
||||
|
||||
<div ng-hide="success">
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
|
||||
<div class="btn-group flex" style="font-size: 15px;">
|
||||
|
||||
<umb-flatpickr ng-model="vm.variants[0].releaseDate"
|
||||
<umb-date-time-picker ng-model="vm.variants[0].releaseDate"
|
||||
options="vm.variants[0].datePickerConfig"
|
||||
on-setup="vm.datePickerSetup(vm.variants[0], 'publish', fpItem)"
|
||||
on-change="vm.datePickerChange(vm.variants[0], dateStr, 'publish')"
|
||||
@@ -32,7 +32,7 @@
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</umb-flatpickr>
|
||||
</umb-date-time-picker>
|
||||
|
||||
<a ng-show="vm.variants[0].releaseDate" ng-click="vm.clearPublishDate(vm.variants[0])" class="btn umb-button--xs dropdown-toggle umb-button-group__toggle" style="margin-left: -2px;">
|
||||
<span class="icon icon-wrong"></span>
|
||||
@@ -47,7 +47,7 @@
|
||||
</label>
|
||||
|
||||
<div class="btn-group flex" style="font-size: 15px;">
|
||||
<umb-flatpickr ng-model="vm.variants[0].expireDate"
|
||||
<umb-date-time-picker ng-model="vm.variants[0].expireDate"
|
||||
options="vm.variants[0].datePickerConfig"
|
||||
on-setup="vm.datePickerSetup(vm.variants[0], 'unpublish', fpItem)"
|
||||
on-change="vm.datePickerChange(vm.variants[0], dateStr, 'unpublish')"
|
||||
@@ -64,7 +64,7 @@
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</umb-flatpickr>
|
||||
</umb-date-time-picker>
|
||||
|
||||
<a ng-show="vm.variants[0].expireDate" ng-click="vm.clearUnpublishDate(vm.variants[0])" class="btn umb-button--xs dropdown-toggle umb-button-group__toggle" style="margin-left: -2px;">
|
||||
<span class="icon icon-wrong"></span>
|
||||
@@ -112,7 +112,7 @@
|
||||
<div style="font-size: 13px; margin-right: 5px;">Publish:<em ng-show="!variant.save"> {{variant.releaseDateFormatted}}</em></div>
|
||||
|
||||
<div class="btn-group flex" style="font-size: 14px; margin-right: 10px;" ng-if="variant.save">
|
||||
<umb-flatpickr ng-model="variant.releaseDate"
|
||||
<umb-date-time-picker ng-model="variant.releaseDate"
|
||||
options="variant.datePickerConfig"
|
||||
on-setup="vm.datePickerSetup(variant, 'publish', fpItem)"
|
||||
on-change="vm.datePickerChange(variant, dateStr, 'publish')"
|
||||
@@ -127,7 +127,7 @@
|
||||
<localize key="content_setDate">Set date</localize>
|
||||
</a>
|
||||
</div>
|
||||
</umb-flatpickr>
|
||||
</umb-date-time-picker>
|
||||
<a ng-show="variant.releaseDate" ng-click="vm.clearPublishDate(variant)" class="btn umb-button--xxs dropdown-toggle umb-button-group__toggle" style="margin-left: -2px;">
|
||||
<span class="icon icon-wrong"></span>
|
||||
</a>
|
||||
@@ -138,7 +138,7 @@
|
||||
<div style="font-size: 13px; margin-right: 5px;">Unpublish:<em ng-show="!variant.save"> {{variant.expireDateFormatted}}</em></div>
|
||||
|
||||
<div class="btn-group flex" style="font-size: 14px;" ng-if="variant.save">
|
||||
<umb-flatpickr ng-model="variant.expireDate"
|
||||
<umb-date-time-picker ng-model="variant.expireDate"
|
||||
options="variant.datePickerConfig"
|
||||
on-setup="vm.datePickerSetup(variant, 'unpublish', fpItem)"
|
||||
on-change="vm.datePickerChange(variant, dateStr, 'unpublish')"
|
||||
@@ -153,7 +153,7 @@
|
||||
<localize key="content_setDate">Set date</localize>
|
||||
</a>
|
||||
</div>
|
||||
</umb-flatpickr>
|
||||
</umb-date-time-picker>
|
||||
<a ng-show="variant.expireDate" ng-click="vm.clearUnpublishDate(variant)" class="btn umb-button--xxs dropdown-toggle umb-button-group__toggle" style="margin-left: -2px;">
|
||||
<span class="icon icon-wrong"></span>
|
||||
</a>
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
<localize key="editdatatype_selectFolder">Select the folder to move</localize> <strong>{{source.name}}</strong> <localize key="editdatatype_inTheTree">to in the tree structure below</localize>
|
||||
</p>
|
||||
|
||||
<div class="umb-loader-wrapper" ng-show="busy">
|
||||
<div class="umb-loader"></div>
|
||||
</div>
|
||||
<umb-loader ng-show="busy"></umb-loader>
|
||||
|
||||
<div ng-show="error">
|
||||
<div class="alert alert-error">
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
<localize key="contentTypeEditor_folderToCopy">Select the folder to copy</localize> <strong>{{source.name}}</strong> <localize key="contentTypeEditor_structureBelow">to in the tree structure below</localize>
|
||||
</p>
|
||||
|
||||
<div class="umb-loader-wrapper" ng-show="busy">
|
||||
<div class="umb-loader"></div>
|
||||
</div>
|
||||
<umb-loader ng-show="busy"></umb-loader>
|
||||
|
||||
<div ng-show="error">
|
||||
<div class="alert alert-error">
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
<localize key="contentTypeEditor_folderToMove">Select the folder to move</localize> <strong>{{source.name}}</strong> <localize key="contentTypeEditor_structureBelow">to in the tree structure below</localize>
|
||||
</p>
|
||||
|
||||
<div class="umb-loader-wrapper" ng-show="busy">
|
||||
<div class="umb-loader"></div>
|
||||
</div>
|
||||
<umb-loader ng-show="busy"></umb-loader>
|
||||
|
||||
<div ng-show="error">
|
||||
<div class="alert alert-error">
|
||||
|
||||
@@ -74,11 +74,11 @@
|
||||
<umb-box>
|
||||
<umb-box-header title="Time Period"></umb-box-header>
|
||||
|
||||
<umb-flatpickr class="datepicker"
|
||||
<umb-date-time-picker class="datepicker"
|
||||
ng-model="vm.period"
|
||||
options="vm.config"
|
||||
on-close="vm.dateRangeChange(selectedDates, dateStr, instance)">
|
||||
</umb-flatpickr>
|
||||
</umb-date-time-picker>
|
||||
</umb-box>
|
||||
|
||||
<div ng-show=" vm.canLoadLogs">
|
||||
|
||||
@@ -1,10 +1,21 @@
|
||||
<div class="umb-dialog umb-pane" ng-controller="Umbraco.Editors.Media.DeleteController">
|
||||
<div class="umb-dialog-body" auto-scale="90">
|
||||
|
||||
<p class="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 ng-show="success">
|
||||
<div class="alert alert-success">
|
||||
<strong>{{currentNode.name}}</strong>
|
||||
<localize key="actions_wasDeleted">was deleted</localize>
|
||||
</div>
|
||||
<button class="btn btn-primary" ng-click="close()">Ok</button>
|
||||
</div>
|
||||
|
||||
<div ng-hide="success">
|
||||
<p class="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="close"></umb-confirm>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -2,9 +2,8 @@
|
||||
<div class="umb-dialog-body">
|
||||
|
||||
<umb-pane>
|
||||
<div class="umb-loader-wrapper" ng-show="busy">
|
||||
<div class="umb-loader"></div>
|
||||
</div>
|
||||
|
||||
<umb-loader ng-show="busy"></umb-loader>
|
||||
|
||||
<p class="abstract">
|
||||
<localize key="defaultdialogs_recycleBinWarning">When items are deleted from the recycle bin, they will be gone forever</localize>.
|
||||
|
||||
@@ -50,8 +50,7 @@ function MediaDeleteController($scope, mediaResource, treeService, navigationSer
|
||||
$location.path(location);
|
||||
}
|
||||
|
||||
navigationService.hideMenu();
|
||||
|
||||
$scope.success = true;
|
||||
}, function (err) {
|
||||
|
||||
$scope.currentNode.loading = false;
|
||||
@@ -66,7 +65,7 @@ function MediaDeleteController($scope, mediaResource, treeService, navigationSer
|
||||
});
|
||||
};
|
||||
|
||||
$scope.cancel = function() {
|
||||
$scope.close = function() {
|
||||
navigationService.hideDialog();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
<localize key="contentTypeEditor_folderToCopy">Select the folder to copy</localize> <strong>{{source.name}}</strong> <localize key="contentTypeEditor_structureBelow">to in the tree structure below</localize>
|
||||
</p>
|
||||
|
||||
<div class="umb-loader-wrapper" ng-show="busy">
|
||||
<div class="umb-loader"></div>
|
||||
</div>
|
||||
<umb-loader ng-show="busy"></umb-loader>
|
||||
|
||||
<div ng-show="error">
|
||||
<div class="alert alert-error">
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
<localize key="contentTypeEditor_folderToMove">Select the folder to move</localize> <strong>{{source.name}}</strong> <localize key="contentTypeEditor_structureBelow">to in the tree structure below</localize>
|
||||
</p>
|
||||
|
||||
<div class="umb-loader-wrapper" ng-show="busy">
|
||||
<div class="umb-loader"></div>
|
||||
</div>
|
||||
<umb-loader ng-show="busy"></umb-loader>
|
||||
|
||||
<div ng-show="error">
|
||||
<div class="alert alert-error">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<ul class="umb-actions umb-actions-child">
|
||||
|
||||
<li class="umb-action" ng-repeat="docType in allowedTypes">
|
||||
<button class="umb-action-link umb-outline btn-reset" href="#member/member/edit/{{currentNode.id}}?doctype={{docType.alias}}&create=true" ng-click="hideActions()">
|
||||
<button class="umb-action-link umb-outline btn-reset" ng-click="createMemberType(docType)">
|
||||
<i class="large icon {{docType.icon}}"></i>
|
||||
<span class="menu-label">
|
||||
{{docType.name}}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* @description
|
||||
* The controller for the member creation dialog
|
||||
*/
|
||||
function memberCreateController($scope, memberTypeResource, iconHelper, navigationService) {
|
||||
function memberCreateController($scope, memberTypeResource, iconHelper, navigationService, $location) {
|
||||
|
||||
memberTypeResource.getTypes($scope.currentNode.id).then(function (data) {
|
||||
$scope.allowedTypes = iconHelper.formatContentTypeIcons(data);
|
||||
@@ -17,7 +17,8 @@ function memberCreateController($scope, memberTypeResource, iconHelper, navigati
|
||||
navigationService.hideDialog(showMenu);
|
||||
};
|
||||
|
||||
$scope.hideActions = function () {
|
||||
$scope.createMemberType = function (memberType) {
|
||||
$location.path("/member/member/edit/" + $scope.currentNode.id).search("doctype", memberType.alias).search("create", "true");
|
||||
navigationService.hideNavigation();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -298,7 +298,7 @@
|
||||
description="Here you can add custom installer / uninstaller events to perform certain tasks during installation and uninstallation.
|
||||
All actions are formed as a xml node, containing data for the action to be performed.">
|
||||
<div>
|
||||
<a ng-href="https://our.umbraco.com/documentation/Reference/Packaging/">Documentation</a>
|
||||
<a target="_blank" ng-href="https://our.umbraco.com/documentation/Reference/Packaging/">Documentation</a>
|
||||
<div>
|
||||
<textarea class="umb-property-editor" rows="10" ng-model="vm.package.actions"></textarea>
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
<div id="datepicker{{model.alias}}">
|
||||
|
||||
<umb-flatpickr
|
||||
<umb-date-time-picker
|
||||
ng-model="model.value"
|
||||
options="datePickerConfig"
|
||||
on-setup="datePickerSetup(fpItem)"
|
||||
@@ -28,7 +28,7 @@
|
||||
</span>
|
||||
</div>
|
||||
|
||||
</umb-flatpickr>
|
||||
</umb-date-time-picker>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
</a>
|
||||
|
||||
<umb-dropdown ng-if="page.createDropdownOpen" on-close="page.createDropdownOpen = false">
|
||||
<umb-dropdown-item ng-repeat="blueprint in listViewAllowedTypes[0].blueprints | orderBy:'name':false">
|
||||
<umb-dropdown-item ng-repeat="blueprint in listViewAllowedTypes[0].blueprints | orderBy:'name':false track by $index">
|
||||
<a ng-click="createFromBlueprint(entityType, listViewAllowedTypes[0].alias, blueprint.id)">
|
||||
<i class="{{::listViewAllowedTypes[0].icon}}"></i>
|
||||
{{::blueprint.name}}
|
||||
@@ -95,9 +95,8 @@
|
||||
<strong ng-show="!actionInProgress">{{ selectedItemsCount() }} <localize key="general_of">of</localize> {{ listViewResultSet.items.length }} <localize key="general_selected">selected</localize></strong>
|
||||
<strong ng-show="actionInProgress" ng-bind="bulkStatus"></strong>
|
||||
|
||||
<div class="umb-loader-wrapper -bottom" ng-show="actionInProgress">
|
||||
<div class="umb-loader"></div>
|
||||
</div>
|
||||
<umb-loader position="bottom" ng-show="actionInProgress"></umb-loader>
|
||||
|
||||
</umb-editor-sub-header-section>
|
||||
|
||||
</umb-editor-sub-header-content-left>
|
||||
|
||||
+8
-1
@@ -1,7 +1,7 @@
|
||||
//this controller simply tells the dialogs service to open a mediaPicker window
|
||||
//with a specified callback, this callback will receive an object with a selection on it
|
||||
angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerController",
|
||||
function ($scope, entityResource, mediaHelper, $timeout, userService, localizationService, editorService) {
|
||||
function ($scope, entityResource, mediaHelper, $timeout, userService, localizationService, editorService, angularHelper) {
|
||||
|
||||
var vm = {
|
||||
labels: {
|
||||
@@ -92,6 +92,10 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
|
||||
$scope.model.value = $scope.ids.join();
|
||||
};
|
||||
|
||||
function setDirty() {
|
||||
angularHelper.getCurrentForm($scope).$setDirty();
|
||||
}
|
||||
|
||||
function reloadUpdatedMediaItems(updatedMediaNodes) {
|
||||
// because the images can be edited through the media picker we need to
|
||||
// reload. We only reload the images that is already picked but has been updated.
|
||||
@@ -152,6 +156,7 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
|
||||
$scope.mediaItems.splice(index, 1);
|
||||
$scope.ids.splice(index, 1);
|
||||
sync();
|
||||
setDirty();
|
||||
};
|
||||
|
||||
$scope.editItem = function (item) {
|
||||
@@ -215,6 +220,7 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
|
||||
});
|
||||
sync();
|
||||
reloadUpdatedMediaItems(model.updatedMediaNodes);
|
||||
setDirty();
|
||||
},
|
||||
close: function (model) {
|
||||
editorService.close();
|
||||
@@ -233,6 +239,7 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
|
||||
items: "li:not(.add-wrapper)",
|
||||
cancel: ".unsortable",
|
||||
update: function (e, ui) {
|
||||
setDirty();
|
||||
var r = [];
|
||||
// TODO: Instead of doing this with a half second delay would be better to use a watch like we do in the
|
||||
// content picker. Then we don't have to worry about setting ids, render models, models, we just set one and let the
|
||||
|
||||
+1
-1
@@ -78,7 +78,7 @@ function multiUrlPickerController($scope, angularHelper, localizationService, en
|
||||
var linkPicker = {
|
||||
currentTarget: target,
|
||||
dataTypeKey: $scope.model.dataTypeKey,
|
||||
ignoreUserStartNodes : $scope.model.config.ignoreUserStartNodes,
|
||||
ignoreUserStartNodes : ($scope.model.config && $scope.model.config.ignoreUserStartNodes) ? $scope.model.config.ignoreUserStartNodes : "0",
|
||||
submit: function (model) {
|
||||
if (model.target.url || model.target.anchor) {
|
||||
// if an anchor exists, check that it is appropriately prefixed
|
||||
|
||||
+14
@@ -15,6 +15,10 @@
|
||||
});
|
||||
}
|
||||
|
||||
$scope.canAdd = function () {
|
||||
return !$scope.model.docTypes || !$scope.model.value || $scope.model.value.length < $scope.model.docTypes.length;
|
||||
}
|
||||
|
||||
$scope.remove = function (index) {
|
||||
$scope.model.value.splice(index, 1);
|
||||
}
|
||||
@@ -57,10 +61,20 @@
|
||||
|
||||
ncResources.getContentTypes().then(function (docTypes) {
|
||||
$scope.model.docTypes = docTypes;
|
||||
|
||||
// Count doctype name occurrences
|
||||
var docTypeNameOccurrences = _.countBy(docTypes, 'name');
|
||||
|
||||
// Populate document type tab dictionary
|
||||
// And append alias to name if multiple doctypes have the same name
|
||||
docTypes.forEach(function (value) {
|
||||
$scope.docTypeTabs[value.alias] = value.tabs;
|
||||
|
||||
value.displayName = value.name;
|
||||
|
||||
if (docTypeNameOccurrences[value.name] > 1) {
|
||||
value.displayName += " (" + value.alias + ")";
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
+5
-5
@@ -23,7 +23,7 @@
|
||||
</td>
|
||||
<td>
|
||||
<select id="{{model.alias}}_doctype_select"
|
||||
ng-options="dt.alias as dt.name for dt in selectableDocTypesFor(config) | orderBy: 'name'"
|
||||
ng-options="dt.alias as dt.displayName for dt in selectableDocTypesFor(config) | orderBy: 'name'"
|
||||
ng-model="config.ncAlias" required></select>
|
||||
</td>
|
||||
<td>
|
||||
@@ -35,17 +35,17 @@
|
||||
<input type="text" ng-model="config.nameTemplate" />
|
||||
</td>
|
||||
<td>
|
||||
<a class="btn btn-danger" ng-click="remove($index)">
|
||||
<button type="button" class="btn btn-danger" ng-click="remove($index)">
|
||||
<localize key="general_delete">Delete</localize>
|
||||
</a>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div>
|
||||
<a class="btn" ng-click="add()">
|
||||
<button type="button" class="btn" ng-click="add()" ng-disabled="!canAdd()">
|
||||
<localize key="general_add">Add</localize>
|
||||
</a>
|
||||
</button>
|
||||
<i class="icon icon-help-alt medium umb-nested-content__help-icon" ng-click="showHelpText = !showHelpText"></i>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
<div class="umb-pane">
|
||||
<div ng-repeat="property in tab.properties" class="umb-nested-content-property-container">
|
||||
|
||||
<umb-property property="property" ng-class="{'umb-nested-content--not-supported': property.notSupported}">
|
||||
<umb-property property="property" ng-class="{'umb-nested-content--not-supported': property.notSupported}" data-element="property-{{property.alias}}">
|
||||
<umb-property-editor model="property"></umb-property-editor>
|
||||
</umb-property>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.PropertyEditors.RTEController",
|
||||
function ($scope, $q, assetsService, $timeout, tinyMceService, angularHelper) {
|
||||
function ($scope, $q, assetsService, $timeout, tinyMceService, angularHelper, tinyMceAssets) {
|
||||
|
||||
// TODO: A lot of the code below should be shared between the grid rte and the normal rte
|
||||
|
||||
@@ -30,9 +30,9 @@ angular.module("umbraco")
|
||||
var promises = [];
|
||||
|
||||
//queue file loading
|
||||
if (typeof tinymce === "undefined") { // Don't reload tinymce if already loaded
|
||||
promises.push(assetsService.loadJs("lib/tinymce/tinymce.min.js", $scope));
|
||||
}
|
||||
tinyMceAssets.forEach(function (tinyJsAsset) {
|
||||
promises.push(assetsService.loadJs(tinyJsAsset, $scope));
|
||||
});
|
||||
|
||||
//stores a reference to the editor
|
||||
var tinyMceEditor = null;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"use strict";
|
||||
|
||||
function UserGroupsController($scope, $timeout, $location, $filter, userService, userGroupsResource,
|
||||
formHelper, localizationService, listViewHelper) {
|
||||
formHelper, localizationService, listViewHelper, overlayService) {
|
||||
|
||||
var vm = this;
|
||||
|
||||
@@ -95,18 +95,26 @@
|
||||
|
||||
if(vm.selection.length > 0) {
|
||||
|
||||
localizationService.localize("defaultdialogs_confirmdelete")
|
||||
.then(function(value) {
|
||||
|
||||
var confirmResponse = confirm(value);
|
||||
|
||||
if (confirmResponse === true) {
|
||||
userGroupsResource.deleteUserGroups(_.pluck(vm.selection, "id")).then(function (data) {
|
||||
clearSelection();
|
||||
onInit();
|
||||
}, angular.noop);
|
||||
}
|
||||
|
||||
localizationService.localizeMany(["general_delete", "defaultdialogs_confirmdelete", "general_cancel", "contentTypeEditor_yesDelete"])
|
||||
.then(function (data) {
|
||||
const overlay = {
|
||||
title: data[0],
|
||||
content: data[1] + "?",
|
||||
closeButtonLabel: data[2],
|
||||
submitButtonLabel: data[3],
|
||||
submitButtonStyle: "danger",
|
||||
close: function () {
|
||||
overlayService.close();
|
||||
},
|
||||
submit: function () {
|
||||
userGroupsResource.deleteUserGroups(_.pluck(vm.selection, "id")).then(function (data) {
|
||||
clearSelection();
|
||||
onInit();
|
||||
}, angular.noop);
|
||||
overlayService.close();
|
||||
}
|
||||
};
|
||||
overlayService.open(overlay);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
describe('RTE controller tests', function () {
|
||||
var scope, controllerFactory;
|
||||
|
||||
beforeEach(module('umbraco'));
|
||||
beforeEach(module('umbraco', function ($provide) {
|
||||
$provide.value('tinyMceAssets', []);
|
||||
}));
|
||||
|
||||
beforeEach(inject(function ($rootScope, $controller) {
|
||||
controllerFactory = $controller;
|
||||
@@ -20,4 +22,5 @@ describe('RTE controller tests', function () {
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -347,10 +347,10 @@
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<DevelopmentServerPort>8200</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:8200</IISUrl>
|
||||
<DevelopmentServerPort>8120</DevelopmentServerPort>
|
||||
<IISUrl>http://localhost:8200/</IISUrl>
|
||||
<DevelopmentServerPort>8130</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:8120</IISUrl>
|
||||
<IISUrl>http://localhost:8130</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>False</UseCustomServer>
|
||||
<CustomServerUrl>
|
||||
|
||||
@@ -19,11 +19,13 @@
|
||||
|
||||
<img src="assets/img/application/logo_white.png" id="logo" />
|
||||
|
||||
<div class="umb-loader-container" ng-style="{'width': installer.progress}">
|
||||
<div class="umb-loader" id="loader" ng-if="installer.loading"></div>
|
||||
</div>
|
||||
<umb-loader position="bottom"
|
||||
class="umb-installer-loader"
|
||||
ng-if="installer.loading"
|
||||
ng-style="{'width': installer.progress}">
|
||||
</umb-loader>
|
||||
|
||||
<div id="overlay" ng-cloak ng-animate="'fade'" ng-show="installer.done"></div>
|
||||
<div id="overlay" ng-cloak ng-animate="'fade'" ng-show="installer.done"></div>
|
||||
|
||||
<div id="installer" class="absolute-center clearfix"
|
||||
ng-cloak
|
||||
|
||||
@@ -119,6 +119,8 @@
|
||||
document.angularReady = function(app) {
|
||||
@Html.AngularValueExternalLoginInfoScript(ViewData.GetExternalSignInError())
|
||||
@Html.AngularValueResetPasswordCodeInfoScript(ViewData["PasswordResetCode"])
|
||||
@Html.AngularValueTinyMceAssets()
|
||||
|
||||
//required for the noscript trick
|
||||
document.getElementById("mainwrapper").style.display = "inherit";
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
<key alias="toInTheTreeStructureBelow">til i træstrukturen nedenfor</key>
|
||||
<key alias="wasMovedTo">blev flyttet til</key>
|
||||
<key alias="wasCopiedTo">blev kopieret til</key>
|
||||
<key alias="wasDeleted">blev slettet</key>
|
||||
<key alias="rights">Rettigheder</key>
|
||||
<key alias="rollback">Fortryd ændringer</key>
|
||||
<key alias="sendtopublish">Send til udgivelse</key>
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
<key alias="toInTheTreeStructureBelow">to in the tree structure below</key>
|
||||
<key alias="wasMovedTo">was moved to</key>
|
||||
<key alias="wasCopiedTo">was copied to</key>
|
||||
<key alias="wasDeleted">was deleted</key>
|
||||
<key alias="rights">Permissions</key>
|
||||
<key alias="rollback">Rollback</key>
|
||||
<key alias="sendtopublish">Send To Publish</key>
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
<key alias="toInTheTreeStructureBelow">to in the tree structure below</key>
|
||||
<key alias="wasMovedTo">was moved to</key>
|
||||
<key alias="wasCopiedTo">was copied to</key>
|
||||
<key alias="wasDeleted">was deleted</key>
|
||||
<key alias="rights">Permissions</key>
|
||||
<key alias="rollback">Rollback</key>
|
||||
<key alias="sendtopublish">Send To Publish</key>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
*/
|
||||
function MainController($scope, $location, appState, treeService, notificationsService,
|
||||
userService, historyService, updateChecker, navigationService, eventsService,
|
||||
tmhDynamicLocale, localStorageService, editorService, overlayService) {
|
||||
tmhDynamicLocale, localStorageService, editorService, overlayService, assetsService, tinyMceAssets) {
|
||||
|
||||
//the null is important because we do an explicit bool check on this in the view
|
||||
$scope.authenticated = null;
|
||||
@@ -21,7 +21,13 @@ function MainController($scope, $location, appState, treeService, notificationsS
|
||||
$scope.search = {};
|
||||
$scope.login = {};
|
||||
$scope.tabbingActive = false;
|
||||
|
||||
|
||||
// Load TinyMCE assets ahead of time in the background for the user
|
||||
// To help with first load of the RTE
|
||||
tinyMceAssets.forEach(function (tinyJsAsset) {
|
||||
assetsService.loadJs(tinyJsAsset, $scope);
|
||||
});
|
||||
|
||||
// There are a number of ways to detect when a focus state should be shown when using the tab key and this seems to be the simplest solution.
|
||||
// For more information about this approach, see https://hackernoon.com/removing-that-ugly-focus-ring-and-keeping-it-too-6c8727fefcd2
|
||||
function handleFirstTab(evt) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<tinymceConfig>
|
||||
<commands>
|
||||
<command alias="ace" name="Source code editor" mode="Insert" />
|
||||
@@ -8,7 +8,7 @@
|
||||
<command alias="cut" name="Cut" mode="Selection"/>
|
||||
<command alias="copy" name="Copy" mode="Selection"/>
|
||||
<command alias="paste" name="Paste" mode="All" />
|
||||
<command alias="styleselect" name="Style select" mode="Insert" />
|
||||
<command alias="styleselect" name="Style select" mode="All" />
|
||||
<command alias="bold" name="Bold" mode="Selection" />
|
||||
<command alias="italic" name="Italic" mode="Selection" />
|
||||
<command alias="underline" name="Underline" mode="Selection" />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<tinymceConfig>
|
||||
<commands>
|
||||
<command alias="ace" name="Source code editor" mode="Insert" />
|
||||
@@ -8,7 +8,7 @@
|
||||
<command alias="cut" name="Cut" mode="Selection"/>
|
||||
<command alias="copy" name="Copy" mode="Selection"/>
|
||||
<command alias="paste" name="Paste" mode="All" />
|
||||
<command alias="styleselect" name="Style select" mode="Insert" />
|
||||
<command alias="styleselect" name="Style select" mode="All" />
|
||||
<command alias="bold" name="Bold" mode="Selection" />
|
||||
<command alias="italic" name="Italic" mode="Selection" />
|
||||
<command alias="underline" name="Underline" mode="Selection" />
|
||||
|
||||
@@ -2297,7 +2297,7 @@ namespace Umbraco.Web.Editors
|
||||
}
|
||||
|
||||
var entry = Services.PublicAccessService.GetEntryForContent(content);
|
||||
if (entry == null)
|
||||
if (entry == null || entry.ProtectedNodeId != content.Id)
|
||||
{
|
||||
return Request.CreateResponse(HttpStatusCode.OK);
|
||||
}
|
||||
@@ -2379,7 +2379,7 @@ namespace Umbraco.Web.Editors
|
||||
|
||||
var entry = Services.PublicAccessService.GetEntryForContent(content);
|
||||
|
||||
if (entry == null)
|
||||
if (entry == null || entry.ProtectedNodeId != content.Id)
|
||||
{
|
||||
entry = new PublicAccessEntry(content, loginPage, errorPage, new List<PublicAccessRule>());
|
||||
|
||||
|
||||
@@ -211,17 +211,20 @@ namespace Umbraco.Web.Editors
|
||||
/// </summary>
|
||||
/// <param name="id">Int id of the entity to fetch URL for</param>
|
||||
/// <param name="type">The type of entity such as Document, Media, Member</param>
|
||||
/// <param name="culture">The culture to fetch the URL for</param>
|
||||
/// <returns>The URL or path to the item</returns>
|
||||
/// <remarks>
|
||||
/// We are not restricting this with security because there is no sensitive data
|
||||
/// </remarks>
|
||||
public HttpResponseMessage GetUrl(int id, UmbracoEntityTypes type)
|
||||
public HttpResponseMessage GetUrl(int id, UmbracoEntityTypes type, string culture = null)
|
||||
{
|
||||
culture = culture ?? ClientCulture();
|
||||
|
||||
var returnUrl = string.Empty;
|
||||
|
||||
if (type == UmbracoEntityTypes.Document)
|
||||
{
|
||||
var foundUrl = UmbracoContext.Url(id);
|
||||
var foundUrl = UmbracoContext.Url(id, culture);
|
||||
if (string.IsNullOrEmpty(foundUrl) == false && foundUrl != "#")
|
||||
{
|
||||
returnUrl = foundUrl;
|
||||
|
||||
@@ -13,6 +13,7 @@ using Umbraco.Web.Models;
|
||||
namespace Umbraco.Web
|
||||
{
|
||||
using Core.Configuration;
|
||||
using Umbraco.Web.JavaScript;
|
||||
|
||||
/// <summary>
|
||||
/// HtmlHelper extensions for the back office
|
||||
@@ -118,6 +119,21 @@ namespace Umbraco.Web
|
||||
sb.AppendLine(JsonConvert.SerializeObject(resetCodeModel));
|
||||
sb.AppendLine(@"});");
|
||||
|
||||
return html.Raw(sb.ToString());
|
||||
}
|
||||
|
||||
public static IHtmlString AngularValueTinyMceAssets(this HtmlHelper html)
|
||||
{
|
||||
var ctx = new HttpContextWrapper(HttpContext.Current);
|
||||
var files = JsInitialization.OptimizeTinyMceScriptFiles(ctx);
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
||||
sb.AppendLine(@"app.value(""tinyMceAssets"",");
|
||||
sb.AppendLine(JsonConvert.SerializeObject(files));
|
||||
sb.AppendLine(@");");
|
||||
|
||||
|
||||
return html.Raw(sb.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,10 +19,26 @@ namespace Umbraco.Web
|
||||
/// Replaces text line breaks with HTML line breaks
|
||||
/// </summary>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <returns>The text with text line breaks replaced with HTML line breaks (<br/>)</returns>
|
||||
/// <returns>The text with text line breaks replaced with HTML line breaks (<c><br /></c>).
|
||||
[Obsolete("This method doesn't HTML encode the text. Use ReplaceLineBreaks instead.")]
|
||||
public HtmlString ReplaceLineBreaksForHtml(string text)
|
||||
{
|
||||
return new HtmlString(text.Replace("\r\n", @"<br />").Replace("\n", @"<br />").Replace("\r", @"<br />"));
|
||||
return new HtmlString(text.Replace("\r\n", @"<br />").Replace("\n", @"<br />").Replace("\r", @"<br />"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HTML encodes the text and replaces text line breaks with HTML line breaks.
|
||||
/// </summary>
|
||||
/// <param name="text">The text.</param>
|
||||
/// <returns>The HTML encoded text with text line breaks replaced with HTML line breaks (<c><br /></c>).</returns>
|
||||
public IHtmlString ReplaceLineBreaks(string text)
|
||||
{
|
||||
var value = HttpUtility.HtmlEncode(text)?
|
||||
.Replace("\r\n", "<br />")
|
||||
.Replace("\r", "<br />")
|
||||
.Replace("\n", "<br />");
|
||||
|
||||
return new HtmlString(value);
|
||||
}
|
||||
|
||||
public HtmlString StripHtmlTags(string html, params string[] tags)
|
||||
|
||||
@@ -131,6 +131,17 @@ namespace Umbraco.Web.JavaScript
|
||||
return resources.Where(x => x.Type == JTokenType.String).Select(x => x.ToString());
|
||||
}
|
||||
|
||||
internal static IEnumerable<string> GetTinyMceInitialization()
|
||||
{
|
||||
var resources = JsonConvert.DeserializeObject<JArray>(Resources.TinyMceInitialize);
|
||||
return resources.Where(x => x.Type == JTokenType.String).Select(x => x.ToString());
|
||||
}
|
||||
|
||||
internal static IEnumerable<string> OptimizeTinyMceScriptFiles(HttpContextBase httpContext)
|
||||
{
|
||||
return OptimizeScriptFiles(httpContext, GetTinyMceInitialization());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses the JsResources.Main and replaces the replacement tokens accordingly.
|
||||
/// </summary>
|
||||
|
||||
+12
@@ -146,5 +146,17 @@ namespace Umbraco.Web.JavaScript {
|
||||
return ResourceManager.GetString("ServerVariables", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to [
|
||||
/// '../lib/tinymce/tinymce.min.js',
|
||||
///]
|
||||
///.
|
||||
/// </summary>
|
||||
internal static string TinyMceInitialize {
|
||||
get {
|
||||
return ResourceManager.GetString("TinyMceInitialize", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user