Compare commits
281 Commits
release-8.1.2
...
v8/dev
| Author | SHA1 | Date | |
|---|---|---|---|
| 157c0a2479 | |||
| 3d3a836c52 | |||
| 24efa54481 | |||
| 1bf85ab1db | |||
| 1d94c4b9bb | |||
| 13e704e36c | |||
| 413b266335 | |||
| 7cb0886b35 | |||
| d0e7344e2d | |||
| 8fdc14f360 | |||
| 915b24e4e4 | |||
| a24e5bd10c | |||
| 3457018fb4 | |||
| bfc87922cb | |||
| 09def9f352 | |||
| 934e2066a0 | |||
| b254b4fcda | |||
| 4dad427a64 | |||
| 9e1424fb24 | |||
| ad978c60df | |||
| dfe96dccde | |||
| 981519eac0 | |||
| 16ab7b70cf | |||
| b2093e6dfa | |||
| 3f8dffee3f | |||
| 204a9c9d53 | |||
| 531dee1e75 | |||
| 297e054381 | |||
| e9eecb2031 | |||
| 4f289a222f | |||
| e92631c623 | |||
| 93bb75511b | |||
| 5d9e1087f4 | |||
| 0308c8096e | |||
| 02469f110f | |||
| 851a2a3de8 | |||
| 74ccc34124 | |||
| f5a445101d | |||
| 2cdeb38521 | |||
| b3834c296b | |||
| 198b74f4de | |||
| 3c7580ff7b | |||
| c0ad292ebb | |||
| 4ef55aa7d0 | |||
| 3dc0bbeff3 | |||
| b205f19f40 | |||
| 727c32843c | |||
| 78a63b20c7 | |||
| c3e99205de | |||
| 66ba6f51da | |||
| 8625c8da43 | |||
| d86db3fc11 | |||
| ac4128d89e | |||
| 11f2855442 | |||
| d09be604d9 | |||
| d8355c368f | |||
| 703092c12c | |||
| 9b212121e3 | |||
| 88145d70fc | |||
| 320cc48132 | |||
| ac6e399847 | |||
| d2649e9354 | |||
| 0aaf284f7f | |||
| a21c9420b1 | |||
| b396cc340c | |||
| 4b9ce6bb10 | |||
| 55d0ca2557 | |||
| d57ebf021c | |||
| a2899b21b6 | |||
| 1089b4b9bb | |||
| 2428af3c40 | |||
| ffd5d61f9f | |||
| 5b1f2ef95d | |||
| 08c3b6bff5 | |||
| ccc2a0e811 | |||
| 445e6d41b7 | |||
| 82e11d7e0a | |||
| 2cc5256c00 | |||
| 6f83d3c865 | |||
| 3325627fd2 | |||
| bec54a0467 | |||
| 4fc265275b | |||
| a95360036d | |||
| 6873c12f04 | |||
| 0daa80efa4 | |||
| 1f2c4e38ac | |||
| b9b4721295 | |||
| 7a7adfb61f | |||
| defcb727f9 | |||
| e4f19f7192 | |||
| 0e565ddbf8 | |||
| 438133ae1f | |||
| 7ef7b23e93 | |||
| 6e1314ae30 | |||
| 75ff3b26c1 | |||
| 505b541040 | |||
| fbc12b607d | |||
| cb7440bbbf | |||
| cd355910b3 | |||
| 5452ebaf6d | |||
| cec4376d19 | |||
| 53c52abde5 | |||
| 0d63b13bf0 | |||
| 65b2d08997 | |||
| 2b7154622e | |||
| 0baf5eab0a | |||
| 16ac2c5589 | |||
| 4743fc0e1d | |||
| f8409be506 | |||
| f1f9e1742e | |||
| 455395154a | |||
| 3087eff147 | |||
| 8e2eccb392 | |||
| a0af474c75 | |||
| 7e8364eae4 | |||
| e7a9ee8142 | |||
| 806d835a90 | |||
| 617fd9ab17 | |||
| fe6df58e66 | |||
| 6bd647f8c6 | |||
| 8d0df6cec3 | |||
| 5997e0ce8c | |||
| 8bdd694a12 | |||
| ee2068de56 | |||
| dfed93a4ab | |||
| 4e17463eb8 | |||
| df391c86f3 | |||
| 67f0a65811 | |||
| 9d77114d50 | |||
| d2be30a228 | |||
| 9ed1101f27 | |||
| f60b91110f | |||
| db6714d3b8 | |||
| 47c8de4ca1 | |||
| 802e6d7979 | |||
| 249126a2b5 | |||
| ea591c87a2 | |||
| f3fc83fae6 | |||
| d005af2b11 | |||
| 3b60815e53 | |||
| b0b05cf785 | |||
| d5d213cd44 | |||
| 2d56879d92 | |||
| 13d07c7ba3 | |||
| ece7178ef5 | |||
| ab63d2664c | |||
| f829ac4e6c | |||
| 28dd9aa081 | |||
| eb8556c792 | |||
| 84e4c78bb9 | |||
| 6123c0d475 | |||
| 12ad9dd36b | |||
| ba040674cb | |||
| 3fa77dbf3d | |||
| 9fa435dbb2 | |||
| 02c1e88da2 | |||
| 87e60ef26b | |||
| 87845ee907 | |||
| 405538544f | |||
| afca2e70bd | |||
| 31d67161ab | |||
| 66e3869b06 | |||
| 600be987a7 | |||
| fdcfc48e06 | |||
| eb46b16800 | |||
| 392445b53a | |||
| 7c93b8f157 | |||
| 2f84e76952 | |||
| 12a30d3ffd | |||
| 7e1f90fb3b | |||
| 9865596dcc | |||
| 7393d9c372 | |||
| c87a22f347 | |||
| dc44a7a3a7 | |||
| 79c4d7797c | |||
| feb5567621 | |||
| 9cab789425 | |||
| ab3202b560 | |||
| a0cd542ba3 | |||
| e10ce234db | |||
| 7f02bc7d1d | |||
| 44b6738b0d | |||
| fbb19cba0b | |||
| 84554101f2 | |||
| 8a3b2e038c | |||
| ff595df7ca | |||
| 01a895bbf7 | |||
| 296d7964ae | |||
| ed5effd190 | |||
| c6671f7f8e | |||
| 44c966bd44 | |||
| 57e58c6cf7 | |||
| 34e45abcc7 | |||
| b3497011e8 | |||
| a398881fa1 | |||
| 2cf3a7831c | |||
| 0138091a6c | |||
| 6c0fb2f849 | |||
| e495faf83c | |||
| 8721423f40 | |||
| 49b3351c72 | |||
| faef449750 | |||
| 4a24064783 | |||
| 0ab84fc443 | |||
| fca74ad8d7 | |||
| 7bc7dba86d | |||
| ca75a25802 | |||
| ece31733a9 | |||
| 28a8027179 | |||
| 4fa523db43 | |||
| 186460ac08 | |||
| a97604d6c4 | |||
| 308f929f7b | |||
| c8d7df1515 | |||
| 2c795662d2 | |||
| 8a43e3a87e | |||
| 210e43fcb0 | |||
| beb8c7ac7c | |||
| 2f8979bbc3 | |||
| a8ed7f2c17 | |||
| 1c6bf55e5d | |||
| c246044ac7 | |||
| 5126521d37 | |||
| 27223738c6 | |||
| 968463912a | |||
| 05c6b856f9 | |||
| 6fe3089207 | |||
| 06b136fdf6 | |||
| c6246b5404 | |||
| 3062f40ef5 | |||
| dcd0d38419 | |||
| c01a8f8f13 | |||
| da71a94c39 | |||
| f6413af3f4 | |||
| 2ec8281163 | |||
| 440e649d6d | |||
| 47dcd37d1d | |||
| d60fc63e78 | |||
| b0c4042e87 | |||
| da525513a3 | |||
| 2ac5e61e44 | |||
| 101a8b6c78 | |||
| f7a10e3a15 | |||
| 4e0dd728a8 | |||
| 320ccf8105 | |||
| 62f924a757 | |||
| c47a08b553 | |||
| de9241bcf5 | |||
| 7c03fe3c1f | |||
| 82eb241119 | |||
| 1073e6257c | |||
| bc3e4847fe | |||
| 1a7251909c | |||
| 61a18297d9 | |||
| bdd413f9ee | |||
| fd8ca35e63 | |||
| fdd9aee773 | |||
| d31e71a838 | |||
| 3c2a92d3b6 | |||
| cf49e6160a | |||
| ec93030e21 | |||
| 1d49c8626e | |||
| 89bb94aa1a | |||
| 03a4b75176 | |||
| 943b54dcf7 | |||
| 39bd18ec1a | |||
| e93ddff46b | |||
| 3144b51c91 | |||
| e92f68d040 | |||
| 469054e9b3 | |||
| d17022d87d | |||
| 6865629090 | |||
| a4749f201d | |||
| ad90264ef1 | |||
| 9ba7e7742a | |||
| 6473f600c7 | |||
| 6329dfa629 | |||
| 2cd0173534 | |||
| a0bcfeddcc | |||
| c4b5483d8c | |||
| 7557c584d8 |
@@ -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.
|
||||
@@ -12,7 +12,7 @@ thoroughly. Then, proceed by filling out the rest of the details in the issue
|
||||
template below. The more details you can give us, the easier it will be for us
|
||||
to determine the cause of a problem.
|
||||
|
||||
See: https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/.github/CONTRIBUTING.md
|
||||
See: https://github.com/umbraco/Umbraco-CMS/blob/v8/dev/.github/CONTRIBUTING.md
|
||||
|
||||
-->
|
||||
|
||||
|
||||
@@ -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!
|
||||
|
||||
|
||||
+2
-2
@@ -18,5 +18,5 @@ using System.Resources;
|
||||
[assembly: AssemblyVersion("8.0.0")]
|
||||
|
||||
// these are FYI and changed automatically
|
||||
[assembly: AssemblyFileVersion("8.1.2")]
|
||||
[assembly: AssemblyInformationalVersion("8.1.2")]
|
||||
[assembly: AssemblyFileVersion("8.2.0")]
|
||||
[assembly: AssemblyInformationalVersion("8.2.0")]
|
||||
|
||||
@@ -90,7 +90,7 @@ namespace Umbraco.Core.Composing.CompositionExtensions
|
||||
// register the IFileSystem supporting the IMediaFileSystem
|
||||
// THIS IS THE ONLY THING THAT NEEDS TO CHANGE, IN ORDER TO REPLACE THE UNDERLYING FILESYSTEM
|
||||
// and, SupportingFileSystem.For<IMediaFileSystem>() returns the underlying filesystem
|
||||
composition.SetMediaFileSystem(() => new PhysicalFileSystem("~/media"));
|
||||
composition.SetMediaFileSystem(() => new PhysicalFileSystem(SystemDirectories.Media));
|
||||
|
||||
return composition;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
@@ -203,6 +208,24 @@ namespace Umbraco.Core
|
||||
/// <remarks>Must be a valid <see cref="ValueTypes"/> value.</remarks>
|
||||
public const string DataValueType = "umbracoDataValueType";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Defines Umbraco's built-in property editor groups.
|
||||
/// </summary>
|
||||
public static class Groups
|
||||
{
|
||||
public const string Common = "Common";
|
||||
|
||||
public const string Lists = "Lists";
|
||||
|
||||
public const string Media = "Media";
|
||||
|
||||
public const string People = "People";
|
||||
|
||||
public const string Pickers = "Pickers";
|
||||
|
||||
public const string RichContent = "Rich Content";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -42,6 +42,12 @@ namespace Umbraco.Core.Logging.Viewer
|
||||
|
||||
bool CheckCanOpenLogs(LogTimePeriod logTimePeriod);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current Serilog minimum log level
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
string GetLogLevel();
|
||||
|
||||
/// <summary>
|
||||
/// Returns the collection of logs
|
||||
/// </summary>
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using Newtonsoft.Json;
|
||||
using Serilog;
|
||||
using Serilog.Events;
|
||||
using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Formatting = Newtonsoft.Json.Formatting;
|
||||
|
||||
namespace Umbraco.Core.Logging.Viewer
|
||||
{
|
||||
@@ -89,6 +92,16 @@ namespace Umbraco.Core.Logging.Viewer
|
||||
return errorCounter.Count;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the Serilog minimum-level value from the config file.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public string GetLogLevel()
|
||||
{
|
||||
var logLevel = Enum.GetValues(typeof(LogEventLevel)).Cast<LogEventLevel>().Where(Log.Logger.IsEnabled)?.Min() ?? null;
|
||||
return logLevel?.ToString() ?? "";
|
||||
}
|
||||
|
||||
public LogLevelCounts GetLogLevelCounts(LogTimePeriod logTimePeriod)
|
||||
{
|
||||
var counter = new CountingFilter();
|
||||
|
||||
+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>());
|
||||
}
|
||||
|
||||
@@ -114,7 +114,7 @@ namespace Umbraco.Core.Models
|
||||
/// Gets of sets the alias of the property type.
|
||||
/// </summary>
|
||||
[DataMember]
|
||||
public string Alias
|
||||
public virtual string Alias
|
||||
{
|
||||
get => _alias;
|
||||
set => SetPropertyValueAndDetectChanges(SanitizeAlias(value), ref _alias, nameof(Alias));
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -250,7 +250,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
lock (_codeIdMap)
|
||||
{
|
||||
if (_codeIdMap.TryGetValue(isoCode, out var id)) return id;
|
||||
if (isoCode.Contains('-') && _codeIdMap.TryGetValue(isoCode.Split('-').First(), out var invariantId)) return invariantId;
|
||||
}
|
||||
if (throwOnNotFound)
|
||||
throw new ArgumentException($"Code {isoCode} does not correspond to an existing language.", nameof(isoCode));
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace Umbraco.Core.PropertyEditors
|
||||
// defaults
|
||||
Type = type;
|
||||
Icon = Constants.Icons.PropertyEditor;
|
||||
Group = "common";
|
||||
Group = Constants.PropertyEditors.Groups.Common;
|
||||
|
||||
// assign properties based on the attribute, if it is found
|
||||
Attribute = GetType().GetCustomAttribute<DataEditorAttribute>(false);
|
||||
|
||||
@@ -121,7 +121,7 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// Gets or sets an optional group.
|
||||
/// </summary>
|
||||
/// <remarks>The group can be used for example to group the editors by category.</remarks>
|
||||
public string Group { get; set; } = "common";
|
||||
public string Group { get; set; } = Constants.PropertyEditors.Groups.Common;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether the value editor is deprecated.
|
||||
|
||||
@@ -5,7 +5,11 @@ namespace Umbraco.Core.PropertyEditors
|
||||
/// <summary>
|
||||
/// Represents a property editor for label properties.
|
||||
/// </summary>
|
||||
[DataEditor(Constants.PropertyEditors.Aliases.Label, "Label", "readonlyvalue", Icon = "icon-readonly")]
|
||||
[DataEditor(
|
||||
Constants.PropertyEditors.Aliases.Label,
|
||||
"Label",
|
||||
"readonlyvalue",
|
||||
Icon = "icon-readonly")]
|
||||
public class LabelPropertyEditor : DataEditor
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -12,6 +12,7 @@ using Lucene.Net.Store;
|
||||
using Umbraco.Core;
|
||||
using Version = Lucene.Net.Util.Version;
|
||||
using Umbraco.Core.Logging;
|
||||
using System.Threading;
|
||||
|
||||
namespace Umbraco.Examine
|
||||
{
|
||||
@@ -28,29 +29,27 @@ namespace Umbraco.Examine
|
||||
/// </remarks>
|
||||
internal static readonly Regex CultureIsoCodeFieldNameMatchExpression = new Regex("^([_\\w]+)_([a-z]{2}-[a-z0-9]{2,4})$", RegexOptions.Compiled);
|
||||
|
||||
private static volatile bool _isUnlocked = false;
|
||||
private static readonly object IsUnlockedLocker = new object();
|
||||
private static bool _isConfigured = false;
|
||||
private static object _configuredInit = null;
|
||||
private static object _isConfiguredLocker = new object();
|
||||
|
||||
/// <summary>
|
||||
/// Unlocks all Lucene based indexes registered with the <see cref="IExamineManager"/>
|
||||
/// Called on startup to configure each index.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Indexing rebuilding can occur on a normal boot if the indexes are empty or on a cold boot by the database server messenger. Before
|
||||
/// either of these happens, we need to configure the indexes.
|
||||
/// Configures and unlocks all Lucene based indexes registered with the <see cref="IExamineManager"/>.
|
||||
/// </remarks>
|
||||
internal static void EnsureUnlocked(this IExamineManager examineManager, IMainDom mainDom, ILogger logger)
|
||||
internal static void ConfigureIndexes(this IExamineManager examineManager, IMainDom mainDom, ILogger logger)
|
||||
{
|
||||
if (!mainDom.IsMainDom) return;
|
||||
if (_isUnlocked) return;
|
||||
|
||||
lock (IsUnlockedLocker)
|
||||
{
|
||||
//double check
|
||||
if (_isUnlocked) return;
|
||||
|
||||
_isUnlocked = true;
|
||||
examineManager.UnlockLuceneIndexes(logger);
|
||||
}
|
||||
LazyInitializer.EnsureInitialized(
|
||||
ref _configuredInit,
|
||||
ref _isConfigured,
|
||||
ref _isConfiguredLocker,
|
||||
() =>
|
||||
{
|
||||
examineManager.ConfigureLuceneIndexes(logger, !mainDom.IsMainDom);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
//TODO: We need a public method here to just match a field name against CultureIsoCodeFieldNameMatchExpression
|
||||
@@ -127,7 +126,7 @@ namespace Umbraco.Examine
|
||||
/// <remarks>
|
||||
/// This is not thread safe, use with care
|
||||
/// </remarks>
|
||||
internal static void UnlockLuceneIndexes(this IExamineManager examineManager, ILogger logger)
|
||||
internal static void ConfigureLuceneIndexes(this IExamineManager examineManager, ILogger logger, bool disableExamineIndexing)
|
||||
{
|
||||
foreach (var luceneIndexer in examineManager.Indexes.OfType<LuceneIndex>())
|
||||
{
|
||||
@@ -136,6 +135,8 @@ namespace Umbraco.Examine
|
||||
//that could end up halting shutdown for a very long time causing overlapping appdomains and many other problems.
|
||||
luceneIndexer.WaitForIndexQueueOnShutdown = false;
|
||||
|
||||
if (disableExamineIndexing) continue; //exit if not enabled, we don't need to unlock them if we're not maindom
|
||||
|
||||
//we should check if the index is locked ... it shouldn't be! We are using simple fs lock now and we are also ensuring that
|
||||
//the indexes are not operational unless MainDom is true
|
||||
var dir = luceneIndexer.GetLuceneDirectory();
|
||||
|
||||
@@ -268,7 +268,7 @@ AnotherContentFinder
|
||||
public void GetDataEditors()
|
||||
{
|
||||
var types = _typeLoader.GetDataEditors();
|
||||
Assert.AreEqual(38, types.Count());
|
||||
Assert.AreEqual(39, types.Count());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -79,39 +79,6 @@ namespace Umbraco.Tests.Persistence.Repositories
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Perform_Get_By_Invariant_Code_On_LanguageRepository()
|
||||
{
|
||||
var provider = TestObjects.GetScopeProvider(Logger);
|
||||
using (var scope = provider.CreateScope())
|
||||
{
|
||||
var repository = CreateRepository(provider);
|
||||
|
||||
var es = new CultureInfo("es");
|
||||
var esSpecific = new CultureInfo("es-ES");
|
||||
|
||||
var language = (ILanguage)new Language(es.Name)
|
||||
{
|
||||
CultureName = es.DisplayName,
|
||||
FallbackLanguageId = 1
|
||||
};
|
||||
repository.Save(language);
|
||||
|
||||
language = repository.GetByIsoCode(es.Name);
|
||||
var languageSpecific = repository.GetByIsoCode(esSpecific.Name);
|
||||
|
||||
// Assert
|
||||
Assert.That(language, Is.Not.Null);
|
||||
Assert.That(language.HasIdentity, Is.True);
|
||||
Assert.That(language.IsoCode, Is.EqualTo(es.Name));
|
||||
|
||||
Assert.That(languageSpecific, Is.Not.Null);
|
||||
Assert.That(languageSpecific.HasIdentity, Is.True);
|
||||
Assert.That(languageSpecific.Id, Is.EqualTo(language.Id));
|
||||
Assert.That(language.IsoCode, Is.EqualTo(language.IsoCode));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Get_When_Id_Doesnt_Exist_Returns_Null()
|
||||
{
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace Umbraco.Tests.Routing
|
||||
{
|
||||
base.SetUp();
|
||||
|
||||
WebFinalComponent.CreateRoutes(
|
||||
WebInitialComponent.CreateRoutes(
|
||||
new TestUmbracoContextAccessor(),
|
||||
TestObjects.GetGlobalSettings(),
|
||||
new SurfaceControllerTypeCollection(Enumerable.Empty<Type>()),
|
||||
|
||||
@@ -16,13 +16,31 @@ module.exports = {
|
||||
//processed in the js task
|
||||
js: {
|
||||
preview: { files: ["./src/preview/**/*.js"], out: "umbraco.preview.js" },
|
||||
installer: { files: ["./src/installer/**/*.js"], out: "umbraco.installer.js" },
|
||||
controllers: { files: ["./src/{views,controllers}/**/*.controller.js"], out: "umbraco.controllers.js" },
|
||||
directives: { files: ["./src/common/directives/**/*.js"], out: "umbraco.directives.js" },
|
||||
installer: { files: ["./src/installer/**/*.js"], out: "umbraco.installer.js" },
|
||||
filters: { files: ["./src/common/filters/**/*.js"], out: "umbraco.filters.js" },
|
||||
resources: { files: ["./src/common/resources/**/*.js"], out: "umbraco.resources.js" },
|
||||
services: { files: ["./src/common/services/**/*.js"], out: "umbraco.services.js" },
|
||||
security: { files: ["./src/common/interceptors/**/*.js"], out: "umbraco.interceptors.js" }
|
||||
security: { files: ["./src/common/interceptors/**/*.js"], out: "umbraco.interceptors.js" },
|
||||
|
||||
//the controllers for views
|
||||
controllers: {
|
||||
files: [
|
||||
"./src/views/**/*.controller.js",
|
||||
"./src/*.controller.js"
|
||||
], out: "umbraco.controllers.js"
|
||||
},
|
||||
|
||||
//directives/components
|
||||
// - any JS file found in common / directives or common/ components
|
||||
// - any JS file found inside views that has the suffix .directive.js or .component.js
|
||||
directives: {
|
||||
files: [
|
||||
"./src/common/directives/_module.js",
|
||||
"./src/{common/directives,common/components}/**/*.js",
|
||||
"./src/views/**/*.{directive,component}.js"
|
||||
],
|
||||
out: "umbraco.directives.js"
|
||||
},
|
||||
},
|
||||
|
||||
//selectors for copying all views into the build
|
||||
@@ -34,7 +52,7 @@ module.exports = {
|
||||
|
||||
//globs for file-watching
|
||||
globs:{
|
||||
views: "./src/views/**/*.html",
|
||||
views: ["./src/views/**/*.html", "./src/common/directives/**/*.html", "./src/common/components/**/*.html" ],
|
||||
less: "./src/less/**/*.less",
|
||||
js: "./src/*.js",
|
||||
lib: "./lib/**/*",
|
||||
|
||||
@@ -5,6 +5,9 @@ var gulp = require('gulp');
|
||||
var runSequence = require('run-sequence');
|
||||
|
||||
// Dev - build the files ready for development and start watchers
|
||||
gulp.task('dev', function(cb) {
|
||||
gulp.task('dev', function (cb) {
|
||||
|
||||
global.isProd = false;
|
||||
|
||||
runSequence(["dependencies", "js", "less", "views"], "watch", cb);
|
||||
});
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var config = require('../config');
|
||||
var gulp = require('gulp');
|
||||
var runSequence = require('run-sequence');
|
||||
|
||||
// Dev - build the files ready for development and start watchers
|
||||
gulp.task('fastdev', function(cb) {
|
||||
|
||||
global.isProd = false;
|
||||
|
||||
runSequence(["dependencies", "js", "less", "views"], "watch", cb);
|
||||
});
|
||||
@@ -9,26 +9,28 @@ var concat = require('gulp-concat');
|
||||
var wrap = require("gulp-wrap-js");
|
||||
var embedTemplates = require('gulp-angular-embed-templates');
|
||||
|
||||
module.exports = function(files, out) {
|
||||
|
||||
module.exports = function (files, out) {
|
||||
|
||||
var task = gulp.src(files);
|
||||
|
||||
if (global.isProd === true) {
|
||||
// check for js errors
|
||||
task = task.pipe(eslint());
|
||||
// outputs the lint results to the console
|
||||
task = task.pipe(eslint.format());
|
||||
}
|
||||
|
||||
|
||||
// check for js errors
|
||||
task = task.pipe(eslint());
|
||||
// outputs the lint results to the console
|
||||
task = task.pipe(eslint.format());
|
||||
|
||||
// sort files in stream by path or any custom sort comparator
|
||||
task = task.pipe(babel())
|
||||
.pipe(sort())
|
||||
.pipe(embedTemplates({ basePath: "./src/", minimize:{ loose: true } }))
|
||||
.pipe(concat(out))
|
||||
.pipe(sort());
|
||||
|
||||
if (global.isProd === true) {
|
||||
//in production, embed the templates
|
||||
task = task.pipe(embedTemplates({ basePath: "./src/", minimize: { loose: true } }))
|
||||
}
|
||||
task = task.pipe(concat(out))
|
||||
.pipe(wrap('(function(){\n%= body %\n})();'))
|
||||
.pipe(gulp.dest(config.root + config.targets.js));
|
||||
|
||||
|
||||
|
||||
|
||||
return task;
|
||||
|
||||
|
||||
};
|
||||
|
||||
@@ -17,17 +17,12 @@ module.exports = function(files, out) {
|
||||
];
|
||||
|
||||
var task = gulp.src(files)
|
||||
.pipe(less());
|
||||
|
||||
|
||||
if (global.isProd === true) {
|
||||
task = task.pipe(cleanCss());
|
||||
}
|
||||
|
||||
task = task.pipe(postcss(processors))
|
||||
.pipe(less())
|
||||
.pipe(cleanCss())
|
||||
.pipe(postcss(processors))
|
||||
.pipe(rename(out))
|
||||
.pipe(gulp.dest(config.root + config.targets.css));
|
||||
|
||||
return task;
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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) {
|
||||
|
||||
+278
-86
File diff suppressed because it is too large
Load Diff
@@ -21,6 +21,12 @@
|
||||
$scope.page.menu.currentSection = appState.getSectionState("currentSection");
|
||||
$scope.page.listViewPath = null;
|
||||
$scope.page.isNew = $scope.isNew ? true : false;
|
||||
|
||||
if (infiniteMode) {
|
||||
$scope.page.allowInfinitePublishAndClose = $scope.infiniteModel.allowPublishAndClose;
|
||||
$scope.page.allowInfiniteSaveAndClose = $scope.infiniteModel.allowSaveAndClose;
|
||||
}
|
||||
|
||||
$scope.page.buttonGroupState = "init";
|
||||
$scope.page.hideActionsMenu = infiniteMode ? true : false;
|
||||
$scope.page.hideChangeVariant = false;
|
||||
@@ -369,12 +375,17 @@
|
||||
saveMethod: args.saveMethod,
|
||||
scope: $scope,
|
||||
content: $scope.content,
|
||||
create: $scope.page.isNew,
|
||||
action: args.action,
|
||||
showNotifications: args.showNotifications,
|
||||
softRedirect: true
|
||||
}).then(function (data) {
|
||||
//success
|
||||
init();
|
||||
|
||||
//needs to be manually set for infinite editing mode
|
||||
$scope.page.isNew = false;
|
||||
|
||||
syncTreeNode($scope.content, data.path);
|
||||
|
||||
eventsService.emit("content.saved", { content: $scope.content, action: args.action });
|
||||
|
||||
+10
-2
@@ -1,7 +1,7 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function ContentNodeInfoDirective($timeout, logResource, eventsService, userService, localizationService, dateHelper, editorService, redirectUrlsResource, overlayService) {
|
||||
function ContentNodeInfoDirective($timeout, logResource, eventsService, userService, localizationService, dateHelper, editorService, redirectUrlsResource, overlayService, entityResource) {
|
||||
|
||||
function link(scope) {
|
||||
|
||||
@@ -16,8 +16,12 @@
|
||||
scope.disableTemplates = Umbraco.Sys.ServerVariables.features.disabledFeatures.disableTemplates;
|
||||
scope.allowChangeDocumentType = false;
|
||||
scope.allowChangeTemplate = false;
|
||||
scope.allTemplates = [];
|
||||
|
||||
function onInit() {
|
||||
entityResource.getAll("Template").then(function (templates) {
|
||||
scope.allTemplates = templates;
|
||||
});
|
||||
|
||||
// set currentVariant
|
||||
scope.currentVariant = _.find(scope.node.variants, (v) => v.active);
|
||||
@@ -158,8 +162,12 @@
|
||||
}
|
||||
|
||||
scope.openTemplate = function () {
|
||||
var template = _.findWhere(scope.allTemplates, {alias: scope.node.template})
|
||||
if (!template) {
|
||||
return;
|
||||
}
|
||||
var templateEditor = {
|
||||
id: scope.node.templateId,
|
||||
id: template.id,
|
||||
submit: function (model) {
|
||||
editorService.close();
|
||||
},
|
||||
|
||||
+19
-2
@@ -1,7 +1,7 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function EditorContentHeader(serverValidationManager) {
|
||||
function EditorContentHeader(serverValidationManager, localizationService, editorState) {
|
||||
|
||||
function link(scope, el, attr, ctrl) {
|
||||
|
||||
@@ -13,7 +13,24 @@
|
||||
if (!scope.serverValidationAliasField) {
|
||||
scope.serverValidationAliasField = "Alias";
|
||||
}
|
||||
|
||||
|
||||
scope.isNew = scope.content.state == "NotCreated";
|
||||
|
||||
localizationService.localizeMany([
|
||||
scope.isNew ? "placeholders_a11yCreateItem" : "placeholders_a11yEdit",
|
||||
"placeholders_a11yName"]
|
||||
).then(function (data) {
|
||||
scope.a11yMessage = data[0];
|
||||
scope.a11yName = data[1];
|
||||
if (!scope.isNew) {
|
||||
scope.a11yMessage += " " + scope.content.name;
|
||||
|
||||
} else {
|
||||
var name = editorState.current.contentTypeName;
|
||||
scope.a11yMessage += " " + name;
|
||||
scope.a11yName = name + " " + scope.a11yName;
|
||||
}
|
||||
});
|
||||
scope.vm = {};
|
||||
scope.vm.dropdownOpen = false;
|
||||
scope.vm.currentVariant = "";
|
||||
|
||||
+1
-3
@@ -16,9 +16,7 @@
|
||||
editor.moveRight = true;
|
||||
editor.level = 0;
|
||||
editor.styleIndex = 0;
|
||||
|
||||
editor.infinityMode = true;
|
||||
|
||||
|
||||
// push the new editor to the dom
|
||||
scope.editors.push(editor);
|
||||
|
||||
|
||||
+14
-6
@@ -11,6 +11,11 @@ function hexBgColor() {
|
||||
restrict: "A",
|
||||
link: function (scope, element, attr, formCtrl) {
|
||||
|
||||
function setBackgroundColor(color) {
|
||||
// note: can't use element.css(), it doesn't support hexa background colors
|
||||
angular.element(element)[0].style.backgroundColor = "#" + color;
|
||||
}
|
||||
|
||||
// Only add inline hex background color if defined and not "true".
|
||||
if (attr.hexBgInline === undefined || (attr.hexBgInline !== undefined && attr.hexBgInline === "true")) {
|
||||
|
||||
@@ -26,18 +31,21 @@ function hexBgColor() {
|
||||
// Get the orig color before changing it.
|
||||
origColor = element.css("border-color");
|
||||
}
|
||||
// Validate it - test with and without the leading hash.
|
||||
if (/^([0-9a-f]{3}|[0-9a-f]{6})$/i.test(newVal)) {
|
||||
element.css("background-color", "#" + newVal);
|
||||
// Is it a regular hex value - (#)AABBCC ?
|
||||
var match = newVal.match(/^#?([0-9a-f]{3}|[0-9a-f]{6})$/i);
|
||||
if (match && match.length) {
|
||||
setBackgroundColor(match[1]);
|
||||
return;
|
||||
}
|
||||
if (/^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(newVal)) {
|
||||
element.css("background-color", newVal);
|
||||
// Is it a hexa value - (#)AABBCCDD ?
|
||||
match = newVal.match(/^#?([0-9a-f]{4}|[0-9a-f]{8})$/i);
|
||||
if (match && match.length) {
|
||||
setBackgroundColor(match[1]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
element.css("background-color", origColor);
|
||||
setBackgroundColor(origColor);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ angular.module("umbraco.directives")
|
||||
|
||||
// TODO: A lot of the code below should be shared between the grid rte and the normal rte
|
||||
|
||||
scope.isLoading = true;
|
||||
|
||||
var promises = [];
|
||||
|
||||
//To id the html textarea we need to use the datetime ticks because we can have multiple rte's per a single property alias
|
||||
@@ -91,6 +93,10 @@ angular.module("umbraco.directives")
|
||||
//custom initialization for this editor within the grid
|
||||
editor.on('init', function (e) {
|
||||
|
||||
// Used this init event - as opposed to property init_instance_callback
|
||||
// to turn off the loader
|
||||
scope.isLoading = false;
|
||||
|
||||
//force overflow to hidden to prevent no needed scroll
|
||||
editor.getBody().style.overflow = "hidden";
|
||||
|
||||
|
||||
+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);
|
||||
})();
|
||||
+9
@@ -17,6 +17,7 @@
|
||||
scope.sortableOptionsGroup = {};
|
||||
scope.sortableOptionsProperty = {};
|
||||
scope.sortingButtonKey = "general_reorder";
|
||||
scope.compositionsButtonState = "init";
|
||||
|
||||
function activate() {
|
||||
|
||||
@@ -337,6 +338,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) {
|
||||
@@ -356,6 +358,7 @@
|
||||
]).then(function() {
|
||||
//resolves when both other promises are done, now show it
|
||||
editorService.open(scope.compositionsDialogModel);
|
||||
scope.compositionsButtonState = "init";
|
||||
});
|
||||
|
||||
};
|
||||
@@ -532,6 +535,7 @@
|
||||
// push new init tab to the scope
|
||||
addInitGroup(scope.model.groups);
|
||||
|
||||
notifyChanged();
|
||||
},
|
||||
close: function() {
|
||||
if(_.isEqual(oldPropertyModel, propertyModel) === false) {
|
||||
@@ -588,8 +592,13 @@
|
||||
|
||||
}
|
||||
|
||||
notifyChanged();
|
||||
};
|
||||
|
||||
function notifyChanged() {
|
||||
eventsService.emit("editors.groupsBuilder.changed");
|
||||
}
|
||||
|
||||
function addInitProperty(group) {
|
||||
|
||||
var addInitPropertyBool = true;
|
||||
|
||||
@@ -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>
|
||||
|
||||
+82
-120
@@ -4,7 +4,7 @@
|
||||
@restrict A
|
||||
|
||||
@description
|
||||
Use this directive make an element sticky and follow the page when scrolling.
|
||||
Use this directive make an element sticky and follow the page when scrolling. `umb-sticky-bar--active` class is applied when the element is stuck
|
||||
|
||||
<h3>Markup example</h3>
|
||||
<pre>
|
||||
@@ -12,140 +12,102 @@ Use this directive make an element sticky and follow the page when scrolling.
|
||||
|
||||
<div
|
||||
class="my-sticky-bar"
|
||||
umb-sticky-bar
|
||||
scrollable-container=".container">
|
||||
umb-sticky-bar>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</pre>
|
||||
|
||||
<h3>CSS example</h3>
|
||||
<pre>
|
||||
.my-sticky-bar {
|
||||
padding: 15px 0;
|
||||
background: #000000;
|
||||
position: relative;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.my-sticky-bar.-umb-sticky-bar {
|
||||
top: 100px;
|
||||
}
|
||||
</pre>
|
||||
|
||||
@param {string} scrollableContainer Set the class (".element") or the id ("#element") of the scrollable container element.
|
||||
**/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function StickyBarDirective($rootScope) {
|
||||
function StickyBarDirective() {
|
||||
|
||||
/**
|
||||
On initial load, the intersector fires if the grid editor is in the viewport
|
||||
This flag is used to suppress the setClass behaviour on the initial load
|
||||
**/
|
||||
var initial = true;
|
||||
|
||||
/**
|
||||
Toggle `umb-sticky-bar--active` class on the sticky-bar element
|
||||
**/
|
||||
function setClass(addClass, current) {
|
||||
if (!initial) {
|
||||
current.classList.toggle('umb-sticky-bar--active', addClass);
|
||||
} else {
|
||||
initial = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Inserts two elements in the umbStickyBar parent element
|
||||
These are used by the IntersectionObserve to calculate scroll position
|
||||
**/
|
||||
function addSentinels(current) {
|
||||
['-top', '-bottom'].forEach(s => {
|
||||
const sentinel = document.createElement('div');
|
||||
sentinel.classList.add('umb-sticky-sentinel', s);
|
||||
current.parentElement.appendChild(sentinel);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
Calls into setClass when the footer sentinel enters/exits the bottom of the container
|
||||
Container is the parent element of the umbStickyBar element
|
||||
**/
|
||||
function observeFooter(current, container) {
|
||||
const observer = new IntersectionObserver((records, observer) => {
|
||||
let [target, rootBounds, intersected] = [records[0].boundingClientRect, records[0].rootBounds, records[0].intersectionRatio === 1];
|
||||
|
||||
if (target.bottom > rootBounds.top && intersected) {
|
||||
setClass(true, current);
|
||||
}
|
||||
if (target.top < rootBounds.top && target.bottom < rootBounds.bottom) {
|
||||
setClass(false, current);
|
||||
}
|
||||
}, {
|
||||
threshold: [1],
|
||||
root: container
|
||||
});
|
||||
|
||||
observer.observe(current.parentElement.querySelector('.umb-sticky-sentinel.-bottom'));
|
||||
}
|
||||
|
||||
/**
|
||||
Calls into setClass when the header sentinel enters/exits the top of the container
|
||||
Container is the parent element of the umbStickyBar element
|
||||
**/
|
||||
function observeHeader(current, container) {
|
||||
const observer = new IntersectionObserver((records, observer) => {
|
||||
let [target, rootBounds] = [records[0].boundingClientRect, records[0].rootBounds];
|
||||
|
||||
if (target.bottom < rootBounds.top) {
|
||||
setClass(true, current);
|
||||
}
|
||||
|
||||
if (target.bottom >= rootBounds.top && target.bottom < rootBounds.bottom) {
|
||||
setClass(false, current);
|
||||
}
|
||||
}, {
|
||||
threshold: [0],
|
||||
root: container
|
||||
});
|
||||
|
||||
observer.observe(current.parentElement.querySelector('.umb-sticky-sentinel.-top'));
|
||||
}
|
||||
|
||||
function link(scope, el, attr, ctrl) {
|
||||
|
||||
var bar = $(el);
|
||||
var scrollableContainer = null;
|
||||
var clonedBar = null;
|
||||
var cloneIsMade = false;
|
||||
let current = el[0];
|
||||
let container = current.closest('[data-element="editor-container"]');
|
||||
|
||||
function activate() {
|
||||
|
||||
if (bar.parents(".umb-property").length > 1) {
|
||||
bar.addClass("nested");
|
||||
return;
|
||||
}
|
||||
|
||||
if (attr.scrollableContainer) {
|
||||
scrollableContainer = bar.closest(attr.scrollableContainer);
|
||||
} else {
|
||||
scrollableContainer = $(window);
|
||||
}
|
||||
|
||||
scrollableContainer.on('scroll.umbStickyBar', determineVisibility).trigger("scroll");
|
||||
$(window).on('resize.umbStickyBar', determineVisibility);
|
||||
|
||||
scope.$on('$destroy', function () {
|
||||
scrollableContainer.off('.umbStickyBar');
|
||||
$(window).off('.umbStickyBar');
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function determineVisibility() {
|
||||
|
||||
var barTop = bar[0].offsetTop;
|
||||
var scrollTop = scrollableContainer.scrollTop();
|
||||
|
||||
if (scrollTop > barTop) {
|
||||
|
||||
if (!cloneIsMade) {
|
||||
|
||||
createClone();
|
||||
|
||||
clonedBar.css({
|
||||
'visibility': 'visible'
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
calculateSize();
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (cloneIsMade) {
|
||||
|
||||
//remove cloned element (switched places with original on creation)
|
||||
bar.remove();
|
||||
bar = clonedBar;
|
||||
clonedBar = null;
|
||||
|
||||
bar.removeClass('-umb-sticky-bar');
|
||||
bar.css({
|
||||
position: 'relative',
|
||||
'width': 'auto',
|
||||
'height': 'auto',
|
||||
'z-index': 'auto',
|
||||
'visibility': 'visible'
|
||||
});
|
||||
|
||||
cloneIsMade = false;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function calculateSize() {
|
||||
var width = bar.innerWidth();
|
||||
clonedBar.css({
|
||||
width: width + 10 // + 10 (5*2) because we need to add border to avoid seeing the shadow beneath. Look at the CSS.
|
||||
});
|
||||
}
|
||||
|
||||
function createClone() {
|
||||
//switch place with cloned element, to keep binding intact
|
||||
clonedBar = bar;
|
||||
bar = clonedBar.clone();
|
||||
clonedBar.after(bar);
|
||||
clonedBar.addClass('-umb-sticky-bar');
|
||||
clonedBar.css({
|
||||
'position': 'fixed',
|
||||
// if you change this z-index value, make sure the sticky editor sub headers do not
|
||||
// clash with umb-dropdown (e.g. the content actions dropdown in content list view)
|
||||
'z-index': 99,
|
||||
'visibility': 'hidden'
|
||||
});
|
||||
|
||||
cloneIsMade = true;
|
||||
calculateSize();
|
||||
|
||||
}
|
||||
|
||||
activate();
|
||||
addSentinels(current);
|
||||
|
||||
observeHeader(current, container);
|
||||
observeFooter(current, container);
|
||||
}
|
||||
|
||||
var directive = {
|
||||
|
||||
+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);
|
||||
},
|
||||
|
||||
@@ -133,7 +138,7 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
* ##usage
|
||||
* <pre>
|
||||
* //get media by id
|
||||
* entityResource.getEntityById(0, "Media")
|
||||
* entityResource.getById(0, "Media")
|
||||
* .then(function(ent) {
|
||||
* var myDoc = ent;
|
||||
* alert('its here!');
|
||||
@@ -172,7 +177,7 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
umbRequestHelper.getApiUrl(
|
||||
"entityApiBaseUrl",
|
||||
"GetUrlAndAnchors",
|
||||
{ id: id })),
|
||||
[{ id: id }])),
|
||||
'Failed to retrieve url and anchors data for id ' + id);
|
||||
},
|
||||
|
||||
@@ -204,7 +209,7 @@ function entityResource($q, $http, umbRequestHelper) {
|
||||
* ##usage
|
||||
* <pre>
|
||||
* //Get templates for ids
|
||||
* entityResource.getEntitiesByIds( [1234,2526,28262], "Template")
|
||||
* entityResource.getByIds( [1234,2526,28262], "Template")
|
||||
* .then(function(templateArray) {
|
||||
* var myDoc = contentArray;
|
||||
* alert('they are here!');
|
||||
|
||||
@@ -7,64 +7,44 @@
|
||||
**/
|
||||
function logViewerResource($q, $http, umbRequestHelper) {
|
||||
|
||||
/**
|
||||
* verb => 'get', 'post',
|
||||
* method => API method to call
|
||||
* params => additional data to send
|
||||
* error => error message when things go wrong...
|
||||
*/
|
||||
const request = (verb, method, params, error) =>
|
||||
umbRequestHelper.resourcePromise(
|
||||
(verb === 'GET' ?
|
||||
$http.get(umbRequestHelper.getApiUrl("logViewerApiBaseUrl", method) + (params ? params : '')) :
|
||||
$http.post(umbRequestHelper.getApiUrl("logViewerApiBaseUrl", method), params)),
|
||||
error);
|
||||
|
||||
//the factory object returned
|
||||
return {
|
||||
|
||||
getNumberOfErrors: function (startDate, endDate) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"logViewerApiBaseUrl",
|
||||
"GetNumberOfErrors")+ '?startDate='+startDate+ '&endDate='+ endDate ),
|
||||
'Failed to retrieve number of errors in logs');
|
||||
},
|
||||
getNumberOfErrors: (startDate, endDate) =>
|
||||
request('GET', 'GetNumberOfErrors', '?startDate=' + startDate + '&endDate=' + endDate, 'Failed to retrieve number of errors in logs'),
|
||||
|
||||
getLogLevelCounts: function (startDate, endDate) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"logViewerApiBaseUrl",
|
||||
"GetLogLevelCounts")+ '?startDate='+startDate+ '&endDate='+ endDate ),
|
||||
'Failed to retrieve log level counts');
|
||||
},
|
||||
getLogLevel: () =>
|
||||
request('GET', 'GetLogLevel', null, 'Failed to retrieve log level'),
|
||||
|
||||
getMessageTemplates: function (startDate, endDate) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"logViewerApiBaseUrl",
|
||||
"GetMessageTemplates")+ '?startDate='+startDate+ '&endDate='+ endDate ),
|
||||
'Failed to retrieve log templates');
|
||||
},
|
||||
getLogLevelCounts: (startDate, endDate) =>
|
||||
request('GET', 'GetLogLevelCounts', '?startDate=' + startDate + '&endDate=' + endDate, 'Failed to retrieve log level counts'),
|
||||
|
||||
getSavedSearches: function () {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"logViewerApiBaseUrl",
|
||||
"GetSavedSearches")),
|
||||
'Failed to retrieve saved searches');
|
||||
},
|
||||
getMessageTemplates: (startDate, endDate) =>
|
||||
request('GET', 'GetMessageTemplates', '?startDate=' + startDate + '&endDate=' + endDate, 'Failed to retrieve log templates'),
|
||||
|
||||
postSavedSearch: function (name, query) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"logViewerApiBaseUrl",
|
||||
"PostSavedSearch"), { 'name': name, 'query': query }),
|
||||
'Failed to add new saved search');
|
||||
},
|
||||
getSavedSearches: () =>
|
||||
request('GET', 'GetSavedSearches', null, 'Failed to retrieve saved searches'),
|
||||
|
||||
deleteSavedSearch: function (name, query) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.post(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"logViewerApiBaseUrl",
|
||||
"DeleteSavedSearch"), { 'name': name, 'query': query }),
|
||||
'Failed to delete saved search');
|
||||
},
|
||||
postSavedSearch: (name, query) =>
|
||||
request('POST', 'PostSavedSearch', { 'name': name, 'query': query }, 'Failed to add new saved search'),
|
||||
|
||||
getLogs: function (options) {
|
||||
deleteSavedSearch: (name, query) =>
|
||||
request('POST', 'DeleteSavedSearch', { 'name': name, 'query': query }, 'Failed to delete saved search'),
|
||||
|
||||
getLogs: options => {
|
||||
|
||||
var defaults = {
|
||||
pageSize: 100,
|
||||
@@ -83,7 +63,6 @@ function logViewerResource($q, $http, umbRequestHelper) {
|
||||
//now copy back to the options we will use
|
||||
options = defaults;
|
||||
|
||||
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
@@ -93,15 +72,8 @@ function logViewerResource($q, $http, umbRequestHelper) {
|
||||
'Failed to retrieve common log messages');
|
||||
},
|
||||
|
||||
canViewLogs: function (startDate, endDate) {
|
||||
return umbRequestHelper.resourcePromise(
|
||||
$http.get(
|
||||
umbRequestHelper.getApiUrl(
|
||||
"logViewerApiBaseUrl",
|
||||
"GetCanViewLogs") + '?startDate='+startDate+ '&endDate='+ endDate ),
|
||||
'Failed to retrieve state if logs can be viewed');
|
||||
}
|
||||
|
||||
canViewLogs: (startDate, endDate) =>
|
||||
request('GET', 'GetCanViewLogs', '?startDate=' + startDate + '&endDate=' + endDate, 'Failed to retrieve state if logs can be viewed')
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name umbraco.services.contentEditingHelper
|
||||
@@ -53,6 +53,12 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt
|
||||
}
|
||||
if (args.showNotifications === undefined) {
|
||||
args.showNotifications = true;
|
||||
}
|
||||
// needed for infinite editing to create new items
|
||||
if (args.create === undefined) {
|
||||
if ($routeParams.create) {
|
||||
args.create = true;
|
||||
}
|
||||
}
|
||||
if (args.softRedirect === undefined) {
|
||||
//when true, the url will change but it won't actually re-route
|
||||
@@ -61,6 +67,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt
|
||||
args.softRedirect = false;
|
||||
}
|
||||
|
||||
|
||||
var self = this;
|
||||
|
||||
//we will use the default one for content if not specified
|
||||
@@ -68,7 +75,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, editorSt
|
||||
|
||||
if (formHelper.submitForm({ scope: args.scope, action: args.action })) {
|
||||
|
||||
return args.saveMethod(args.content, $routeParams.create, fileManager.getFiles(), args.showNotifications)
|
||||
return args.saveMethod(args.content, args.create, fileManager.getFiles(), args.showNotifications)
|
||||
.then(function (data) {
|
||||
|
||||
formHelper.resetForm({ scope: args.scope });
|
||||
@@ -484,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;
|
||||
}
|
||||
@@ -510,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;
|
||||
}
|
||||
|
||||
|
||||
@@ -261,7 +261,7 @@ When building a custom infinite editor view you can use the same components as a
|
||||
*/
|
||||
unbindKeyboardShortcuts();
|
||||
|
||||
// set flag so we know when the editor is open in "infinie mode"
|
||||
// set flag so we know when the editor is open in "infinite mode"
|
||||
editor.infiniteMode = true;
|
||||
|
||||
editors.push(editor);
|
||||
@@ -331,13 +331,17 @@ When building a custom infinite editor view you can use the same components as a
|
||||
* @methodOf umbraco.services.editorService
|
||||
*
|
||||
* @description
|
||||
* Opens a media editor in infinite editing, the submit callback returns the updated content item
|
||||
* Opens a content editor in infinite editing, the submit callback returns the updated content item
|
||||
* @param {Object} editor rendering options
|
||||
* @param {String} editor.id The id of the content item
|
||||
* @param {Boolean} editor.create Create new content item
|
||||
* @param {Function} editor.submit Callback function when the publish and close button is clicked. Returns the editor model object
|
||||
* @param {Function} editor.close Callback function when the close button is clicked.
|
||||
*
|
||||
* @param {String} editor.parentId If editor.create is true, provide parentId for the creation of the content item
|
||||
* @param {String} editor.documentTypeAlias If editor.create is true, provide document type alias for the creation of the content item
|
||||
* @param {Boolean} editor.allowSaveAndClose If editor is being used in infinite editing allows the editor to close when the save action is performed
|
||||
* @param {Boolean} editor.allowPublishAndClose If editor is being used in infinite editing allows the editor to close when the publish action is performed
|
||||
*
|
||||
* @returns {Object} editor object
|
||||
*/
|
||||
function contentEditor(editor) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -74,8 +74,11 @@
|
||||
}
|
||||
|
||||
.umb-editor-header__back {
|
||||
color: @gray-6;
|
||||
margin-bottom: 1px;
|
||||
background: transparent;
|
||||
border: 0;
|
||||
color: @gray-6;
|
||||
margin: 0 0 1px 0;
|
||||
padding: 0;
|
||||
transition: color 0.1s ease-in-out;
|
||||
}
|
||||
|
||||
@@ -373,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);
|
||||
}
|
||||
|
||||
+23
-6
@@ -32,15 +32,32 @@
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.umb-editor-sub-header.-umb-sticky-bar {
|
||||
box-shadow: 0 6px 3px -3px rgba(0,0,0,.16);
|
||||
[umb-sticky-bar] {
|
||||
transition: box-shadow 240ms;
|
||||
margin-top: 0;
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
top: calc(@appHeaderHeight + @editorHeaderHeight);
|
||||
position:sticky;
|
||||
z-index: 99;
|
||||
|
||||
.umb-editor--infinityMode & {
|
||||
top: calc(@editorHeaderHeight);
|
||||
&.umb-sticky-bar--active {
|
||||
box-shadow: 0 6px 3px -3px rgba(0,0,0,.16);
|
||||
}
|
||||
}
|
||||
|
||||
.umb-sticky-sentinel {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
pointer-events: none;
|
||||
|
||||
&.-top {
|
||||
top:0px;
|
||||
height:1px;
|
||||
}
|
||||
|
||||
&.-bottom {
|
||||
bottom:50px;
|
||||
height:10px;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
z-index: @zIndexEditor;
|
||||
}
|
||||
|
||||
.umb-editor--infinityMode {
|
||||
.umb-editor--infiniteMode {
|
||||
transform: none;
|
||||
will-change: transform;
|
||||
transition: transform 400ms ease-in-out;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
.umb-notifications {
|
||||
z-index: 1000;
|
||||
z-index: 1100;
|
||||
position: absolute;
|
||||
bottom: @editorFooterHeight;
|
||||
left: 0;
|
||||
|
||||
@@ -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 {
|
||||
@@ -57,19 +50,20 @@
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
flex: 1 0 auto;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
}
|
||||
|
||||
// active is equivilant to selected, its the item that is begin affected by the actions performed in the right-click-dialog.
|
||||
.umb-tree-item.active > .umb-tree-item__inner {
|
||||
border-color: @ui-selected-border;
|
||||
box-shadow: 0 0 2px 0 fade(@ui-selected-border, 80%);
|
||||
color: @ui-selected-type;
|
||||
|
||||
a {
|
||||
color: @ui-selected-type;
|
||||
}
|
||||
|
||||
border-color: @ui-selected-border;
|
||||
box-shadow: 0 0 2px 0 fade(@ui-selected-border, 80%);
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
@@ -79,8 +73,10 @@
|
||||
bottom: 0;
|
||||
border: 2px solid fade(white, 80%);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
color: @ui-selected-type-hover;
|
||||
|
||||
a {
|
||||
color: @ui-selected-type-hover;
|
||||
}
|
||||
@@ -88,7 +84,6 @@
|
||||
}
|
||||
|
||||
.umb-tree-item.current > .umb-tree-item__inner {
|
||||
|
||||
background: @ui-active;
|
||||
color:@ui-active-type;
|
||||
|
||||
|
||||
@@ -33,12 +33,6 @@
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
//loader defaults
|
||||
.umb-loader {
|
||||
height: 10px;
|
||||
margin: 10px 10px 10px 10px;
|
||||
}
|
||||
|
||||
.search-subtitle {
|
||||
color: @gray-7;
|
||||
@@ -72,8 +66,7 @@ body.touch .umb-tree {
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
|
||||
align-items: center;
|
||||
border:2px solid transparent;
|
||||
|
||||
color: @ui-option-type;
|
||||
@@ -183,7 +176,6 @@ body.touch .umb-tree {
|
||||
&:hover {
|
||||
background: @btnBackgroundHighlight;
|
||||
}
|
||||
|
||||
// NOTE - We're having to repeat ourselves here due to an .sr-only class appearing in umbraco/lib/font-awesome/css/font-awesome.min.css
|
||||
&.sr-only--hoverable:hover,
|
||||
&.sr-only--focusable:focus {
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
@boxUnit: 10px;
|
||||
|
||||
.umb-box {
|
||||
background: @white;
|
||||
border-radius: 3px;
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: @boxUnit * 2;
|
||||
box-shadow: 0 1px 1px 0 rgba(0,0,0,.16);
|
||||
}
|
||||
|
||||
.umb-box-header {
|
||||
padding: 10px 20px;
|
||||
padding: @boxUnit @boxUnit * 2;
|
||||
border-bottom: 1px solid @gray-9;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -27,5 +29,19 @@
|
||||
}
|
||||
|
||||
.umb-box-content {
|
||||
padding: 20px;
|
||||
padding: @boxUnit * 2;
|
||||
}
|
||||
|
||||
// allow side-by-side boxes
|
||||
.umb-box-row {
|
||||
margin-left:-@boxUnit;
|
||||
margin-right:-@boxUnit;
|
||||
display:flex;
|
||||
justify-content: space-around;
|
||||
|
||||
.umb-box {
|
||||
margin-left:@boxUnit;
|
||||
margin-right:@boxUnit;
|
||||
flex:1;
|
||||
}
|
||||
}
|
||||
+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);
|
||||
}
|
||||
@@ -14,15 +14,18 @@
|
||||
margin: 0 0 20px 0;
|
||||
position: relative;
|
||||
transition: height 0.8s;
|
||||
|
||||
.illustration {
|
||||
width: 300px;
|
||||
}
|
||||
|
||||
&.is-small {
|
||||
height: 100px;
|
||||
.illustration {
|
||||
width: 200px;
|
||||
}
|
||||
}
|
||||
|
||||
&.drag-over {
|
||||
border: 1px dashed @gray-1;
|
||||
}
|
||||
@@ -35,15 +38,19 @@
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%,-50%);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
|
||||
// file select link
|
||||
.file-select {
|
||||
background: transparent;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
font-size: 15px;
|
||||
color: @ui-action-discreet-type;
|
||||
cursor: pointer;
|
||||
|
||||
margin-top: 10px;
|
||||
|
||||
&:hover {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -264,12 +264,16 @@
|
||||
flex-flow: row wrap;
|
||||
}
|
||||
|
||||
a.umb-package-details__back-link {
|
||||
.umb-package-details__back-action {
|
||||
font-weight: bold;
|
||||
color: @black;
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.umb-package-details__back-link:hover {
|
||||
.umb-package-details__back-action:focus,
|
||||
.umb-package-details__back-action:hover {
|
||||
color: @gray-4;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
@@ -592,13 +556,3 @@ input[type=checkbox]:checked + .input-label--small {
|
||||
background-color: @green-l3;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.visuallyhidden{
|
||||
position: absolute !important;
|
||||
clip: rect(1px, 1px, 1px, 1px);
|
||||
padding:0 !important;
|
||||
border:0 !important;
|
||||
height: 1px !important;
|
||||
width: 1px !important;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -165,8 +165,6 @@
|
||||
.sp-replacer {
|
||||
display: inline-flex;
|
||||
margin-right: 18px;
|
||||
border: solid 1px @gray-8;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
label {
|
||||
|
||||
+8
-2
@@ -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>
|
||||
+3
-3
@@ -59,10 +59,10 @@ angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
|
||||
if (dialogOptions.currentTarget) {
|
||||
// clone the current target so we don't accidentally update the caller's model while manipulating $scope.model.target
|
||||
$scope.model.target = angular.copy(dialogOptions.currentTarget);
|
||||
//if we have a node ID, we fetch the current node to build the form data
|
||||
// if we have a node ID, we fetch the current node to build the form data
|
||||
if ($scope.model.target.id || $scope.model.target.udi) {
|
||||
|
||||
//will be either a udi or an int
|
||||
// will be either a udi or an int
|
||||
var id = $scope.model.target.udi ? $scope.model.target.udi : $scope.model.target.id;
|
||||
|
||||
if ($scope.model.target.udi) {
|
||||
@@ -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(/(#|\?)/);
|
||||
|
||||
+1
-1
@@ -268,7 +268,7 @@ angular.module("umbraco")
|
||||
|
||||
// also make sure the node is not trashed
|
||||
if (nodePath.indexOf($scope.startNodeId.toString()) !== -1 && node.trashed === false) {
|
||||
$scope.gotoFolder({ id: $scope.lastOpenedNode, name: "Media", icon: "icon-folder" });
|
||||
$scope.gotoFolder({ id: $scope.lastOpenedNode, name: "Media", icon: "icon-folder", path: node.path });
|
||||
return true;
|
||||
} else {
|
||||
$scope.gotoFolder({ id: $scope.startNodeId, name: "Media", icon: "icon-folder" });
|
||||
|
||||
+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,25 +1,26 @@
|
||||
<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}">
|
||||
|
||||
|
||||
<div ng-if="!configuredView && !elementNotFound">
|
||||
|
||||
<!-- Regular steps -->
|
||||
<umb-tour-step ng-if="model.currentStepIndex < model.steps.length" on-close="model.endTour()">
|
||||
|
||||
|
||||
<umb-tour-step-header
|
||||
title="model.currentStep.title">
|
||||
</umb-tour-step-header>
|
||||
|
||||
|
||||
<umb-tour-step-content
|
||||
content="model.currentStep.content">
|
||||
</umb-tour-step-content>
|
||||
|
||||
|
||||
<umb-tour-step-footer>
|
||||
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
|
||||
<div>
|
||||
@@ -27,9 +28,11 @@
|
||||
current-step="model.currentStepIndex + 1"
|
||||
total-steps="model.steps.length">
|
||||
</umb-tour-step-counter>
|
||||
<div ng-if="model.allowDisable && model.currentStep.type === 'intro'" style="font-size: 13px;"><a href="" class="underline" ng-click="model.disableTour()">Don't show this tour again</a></div>
|
||||
<div ng-if="model.allowDisable && model.currentStep.type === 'intro'">
|
||||
<button type="button" class="underline" ng-click="model.disableTour()" style="font-size: 13px; background: transparent; border: none; padding: 0;" prevent-default>Don't show this tour again</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div ng-if="model.currentStep.type !== 'intro'">
|
||||
<umb-button size="xs" ng-if="!model.currentStep.event" button-style="action" type="button" action="model.nextStep()" label="Next"></umb-button>
|
||||
</div>
|
||||
@@ -40,7 +43,7 @@
|
||||
</div>
|
||||
|
||||
</umb-tour-step-footer>
|
||||
|
||||
|
||||
</umb-tour-step>
|
||||
|
||||
<!-- Outro step -->
|
||||
@@ -64,7 +67,7 @@
|
||||
|
||||
<!-- Custom step view -->
|
||||
<div ng-if="configuredView && !loadingStep && !elementNotFound" ng-include="configuredView"></div>
|
||||
|
||||
|
||||
<!-- Dom element not found error -->
|
||||
<div ng-if="elementNotFound && !loadingStep">
|
||||
<umb-tour-step class="tc">
|
||||
@@ -83,4 +86,4 @@
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+6
-2
@@ -2,9 +2,13 @@
|
||||
|
||||
|
||||
<div ng-if="hideClose !== true">
|
||||
<button class="icon-wrong umb-tour-step__close" ng-click="close()"></button>
|
||||
<button class="icon-wrong umb-tour-step__close" ng-click="close()">
|
||||
<span class="sr-only">
|
||||
<localize key="general_close">Close</localize>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div ng-transclude></div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
<div
|
||||
class="umb-editor-sub-header umb-editor-sub-header--{{appearance}}"
|
||||
umb-sticky-bar
|
||||
scrollable-container=".umb-editor-container"
|
||||
ng-transclude>
|
||||
</div>
|
||||
|
||||
+25
-18
@@ -3,32 +3,39 @@
|
||||
<div class="flex items-center" style="height: 100%;">
|
||||
|
||||
<div ng-if="showBackButton === true && splitViewOpen !== true" style="margin-right: 15px;">
|
||||
<a class="umb-editor-header__back" href="#" ng-click="goBack()" prevent-default>
|
||||
<button type="button" class="umb-editor-header__back" ng-click="goBack()" prevent-default>
|
||||
<i class="fa fa-arrow-left" aria-hidden="true"></i>
|
||||
</a>
|
||||
<span class="sr-only"><localize key="visuallyHiddenTexts_goBack">Go back</localize></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center" style="flex: 1;">
|
||||
|
||||
<div id="nameField" class="umb-editor-header__name-and-description" style="flex: 1 1 auto;">
|
||||
<div>
|
||||
<p tabindex="0" class="sr-only">
|
||||
{{a11yMessage}}
|
||||
</p>
|
||||
</div>
|
||||
<div class="umb-editor-header__name-wrapper">
|
||||
<label for="headerName" class="sr-only">{{a11yName}}</label>
|
||||
<ng-form name="headerNameForm">
|
||||
<input
|
||||
data-element="editor-name-field"
|
||||
type="text"
|
||||
class="umb-editor-header__name-input"
|
||||
localize="placeholder"
|
||||
placeholder="@placeholders_entername"
|
||||
name="headerName"
|
||||
ng-model="name"
|
||||
ng-class="{'name-is-empty': $parent.name===null || $parent.name===''}"
|
||||
ng-disabled="nameDisabled"
|
||||
umb-auto-focus
|
||||
val-server-field="{{serverValidationNameField}}"
|
||||
required
|
||||
aria-required="true"
|
||||
aria-invalid="{{contentForm.headerNameForm.headerName.$invalid ? true : false}}"
|
||||
autocomplete="off" maxlength="255" />
|
||||
<input data-element="editor-name-field"
|
||||
type="text"
|
||||
class="umb-editor-header__name-input"
|
||||
localize="placeholder"
|
||||
placeholder="@placeholders_entername"
|
||||
name="headerName"
|
||||
id="headerName"
|
||||
ng-model="name"
|
||||
ng-class="{'name-is-empty': $parent.name===null || $parent.name===''}"
|
||||
ng-disabled="nameDisabled"
|
||||
umb-auto-focus
|
||||
val-server-field="{{serverValidationNameField}}"
|
||||
required
|
||||
aria-required="true"
|
||||
aria-invalid="{{contentForm.headerNameForm.headerName.$invalid ? true : false}}"
|
||||
autocomplete="off" maxlength="255" />
|
||||
</ng-form>
|
||||
|
||||
<a ng-if="content.variants.length > 0 && hideChangeVariant !== true" class="umb-variant-switcher__toggle" href="" ng-click="vm.dropdownOpen = !vm.dropdownOpen" ng-class="{'--error': vm.errorsOnOtherVariants}">
|
||||
|
||||
@@ -3,9 +3,10 @@
|
||||
<div class="flex items-center" style="height: 100%;">
|
||||
|
||||
<div ng-if="showBackButton === true && splitViewOpen !== true" style="margin-right: 15px;">
|
||||
<a class="umb-editor-header__back" href="#" ng-click="goBack()" prevent-default>
|
||||
<button type="button" class="umb-editor-header__back" ng-click="goBack()" prevent-default>
|
||||
<i class="fa fa-arrow-left" aria-hidden="true"></i>
|
||||
</a>
|
||||
<span class="sr-only"><localize key="visuallyHiddenTexts_goBack">Go back</localize></span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center" style="flex: 1;">
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
ng-class="{'umb-editor--small': model.size === 'small',
|
||||
'umb-editor--animating': model.animating,
|
||||
'--notInFront': model.inFront !== true,
|
||||
'umb-editor--infinityMode': model.infinityMode,
|
||||
'umb-editor--infiniteMode': model.infiniteMode,
|
||||
'moveRight': model.moveRight,
|
||||
'umb-editor--n0': model.styleIndex === 0,
|
||||
'umb-editor--n1': model.styleIndex === 1,
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<div class="umb-rte"
|
||||
id="{{textAreaHtmlId}}">
|
||||
<div>
|
||||
<umb-load-indicator ng-if="isLoading"></umb-load-indicator>
|
||||
<div class="umb-rte" id="{{textAreaHtmlId}}" ng-style="{ visibility : isLoading ? 'hidden' : 'visible' }"></div>
|
||||
</div>
|
||||
|
||||
@@ -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}">
|
||||
|
||||
@@ -17,13 +17,17 @@
|
||||
|
||||
|
||||
<div class="content" >
|
||||
|
||||
<p>
|
||||
<localize key="media_dragAndDropYourFilesIntoTheArea">Drag and drop your file(s) into the area</localize>
|
||||
</p>
|
||||
<!-- Drag and drop illustration -->
|
||||
<img class="illustration" src="assets/img/uploader/upload-illustration.svg" alt="" draggable="false" />
|
||||
|
||||
|
||||
<!-- Select files -->
|
||||
<div
|
||||
<button
|
||||
type="button"
|
||||
prevent-default
|
||||
data-element="button-uploadMedia"
|
||||
class="file-select"
|
||||
ngf-select
|
||||
@@ -32,8 +36,8 @@
|
||||
ngf-multiple="true"
|
||||
ngf-pattern="{{ accept }}"
|
||||
ngf-max-size="{{ maxFileSize }}">
|
||||
- <localize key="media_orClickHereToUpload">or click here to choose files</localize>
|
||||
</div>
|
||||
- <localize key="media_orClickHereToUpload">or click here to choose files</localize>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -104,7 +108,7 @@
|
||||
ng-if="mediatypepickerOverlay.show"
|
||||
model="mediatypepickerOverlay"
|
||||
view="mediatypepickerOverlay.view"
|
||||
position="right">
|
||||
position="right">
|
||||
</umb-overlay>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,9 @@ function ContentEditController($scope, $routeParams, contentResource) {
|
||||
function scaffoldEmpty() {
|
||||
return contentResource.getScaffold($routeParams.id, $routeParams.doctype);
|
||||
}
|
||||
function scaffoldInfiniteEmpty() {
|
||||
return contentResource.getScaffold($scope.model.parentId, $scope.model.documentTypeAlias);
|
||||
}
|
||||
function scaffoldBlueprint() {
|
||||
return contentResource.getBlueprintScaffold($routeParams.id, $routeParams.blueprintId);
|
||||
}
|
||||
@@ -20,11 +23,11 @@ function ContentEditController($scope, $routeParams, contentResource) {
|
||||
$scope.contentId = infiniteMode ? $scope.model.id : $routeParams.id;
|
||||
$scope.saveMethod = contentResource.save;
|
||||
$scope.getMethod = contentResource.getById;
|
||||
$scope.getScaffoldMethod = $routeParams.blueprintId ? scaffoldBlueprint : scaffoldEmpty;
|
||||
$scope.getScaffoldMethod = $routeParams.blueprintId ? scaffoldBlueprint : infiniteMode ? scaffoldInfiniteEmpty : scaffoldEmpty;
|
||||
$scope.page = $routeParams.page;
|
||||
$scope.isNew = infiniteMode ? $scope.model.create : $routeParams.create;
|
||||
//load the default culture selected in the main tree if any
|
||||
$scope.culture = $routeParams.cculture ? $routeParams.cculture : ($routeParams.mculture === "true");
|
||||
$scope.culture = $routeParams.cculture ? $routeParams.cculture : $routeParams.mculture;
|
||||
|
||||
//Bind to $routeUpdate which will execute anytime a location changes but the route is not triggered.
|
||||
//This is so we can listen to changes on the cculture parameter since that will not cause a route change
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user