Compare commits
247 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| dbb99c2e6b | |||
| 61c76dc28b | |||
| 532f69e9b7 | |||
| e2b1f0a82d | |||
| 9597bde7bb | |||
| 7f45d852ed | |||
| 3f10c78bee | |||
| 4b02bf2ddf | |||
| 542eb2ab1d | |||
| 935a495d0e | |||
| fe7c6bd1ed | |||
| 137c08eaf3 | |||
| 1545fe0d5f | |||
| 9e7a062671 | |||
| 970f336a5d | |||
| c6dfc28f03 | |||
| 873d230e0e | |||
| 4a26bfe3c3 | |||
| 79dd593ee7 | |||
| 919f139607 | |||
| 6e2c143d00 | |||
| 212b0ba932 | |||
| 51be2a5baf | |||
| 44beb81e71 | |||
| 2f187fa403 | |||
| 7359b0b244 | |||
| 8f06603774 | |||
| 688173488d | |||
| edb8340b32 | |||
| 808d33edf6 | |||
| 8714bb816f | |||
| a3e842a315 | |||
| c3bf6b0631 | |||
| bf28dfe04a | |||
| 3e6cdd86b2 | |||
| abd681277d | |||
| 5ad1dcf894 | |||
| 485c1fbf6c | |||
| 447eb88b86 | |||
| ece9c4ae21 | |||
| 1509c7364c | |||
| 010e2e1f19 | |||
| 9b25cdaa14 | |||
| 31eea2a2a8 | |||
| 2e52a869b6 | |||
| 95d1ceb529 | |||
| 10f333081d | |||
| cefff71edf | |||
| 13d97fffdf | |||
| ba297ad839 | |||
| 7e67bbea13 | |||
| 9062b400d4 | |||
| 48ec795e7b | |||
| e7781cd95b | |||
| 1098db1632 | |||
| 6880937b90 | |||
| 52beb01110 | |||
| fbfa7e8566 | |||
| c85c055424 | |||
| 829980adb2 | |||
| 8f3bcf87da | |||
| ba55c24d43 | |||
| 4d806c1cef | |||
| b237e4a55e | |||
| 502794aae9 | |||
| 2352b50d97 | |||
| 356b7681e8 | |||
| 0d58b4c42b | |||
| 171cae5fca | |||
| 979a166b41 | |||
| 623ace56bc | |||
| 7203926cea | |||
| 021bf470c2 | |||
| 7194d7d6b8 | |||
| 45423ae932 | |||
| 2b7f12253f | |||
| 129210946d | |||
| 62808958b0 | |||
| c5096e67e6 | |||
| 320d2ae953 | |||
| 264a96971a | |||
| 8c28172efc | |||
| 8a4dfd4350 | |||
| 3814138d68 | |||
| f54a8725db | |||
| bbc2b1a54a | |||
| 6dc5a3b130 | |||
| 3d941e89a6 | |||
| a988bd2608 | |||
| cb083d5b2a | |||
| 8334d088e7 | |||
| 75a9109971 | |||
| 52cea17816 | |||
| 6a67f38025 | |||
| 22d012c4db | |||
| 3046e44f60 | |||
| 790da9d5ca | |||
| 7f31ddc250 | |||
| 869d088e4b | |||
| 6e3ffc0dd9 | |||
| 45dc3a26ed | |||
| 9ef94a667c | |||
| 70122c85d7 | |||
| 72e236a7ab | |||
| 444497be7c | |||
| b7e929a675 | |||
| 2209b37a4a | |||
| 634138724b | |||
| d1c9b7a060 | |||
| b65f60af78 | |||
| 92453c4652 | |||
| b86a1aa687 | |||
| ac4c98a7fc | |||
| b406835c9c | |||
| 9f7fae2ca6 | |||
| f508a97c18 | |||
| b4de15f19e | |||
| f8abd0f457 | |||
| 31eefe1cf9 | |||
| a14b1540ea | |||
| 67fdf75da8 | |||
| 21405266ef | |||
| a4d25dc594 | |||
| 27cc433b96 | |||
| cfa94b1bb8 | |||
| 7a0f11bc6f | |||
| b665d4825d | |||
| 55a374bb71 | |||
| 13b35ec7ce | |||
| 54968c819b | |||
| c910e3afaf | |||
| 4b7c14113c | |||
| b294b83c9f | |||
| 5ddba3e64e | |||
| 31b293aa4d | |||
| 82b78c7530 | |||
| d3904086f0 | |||
| a43f8c4cbd | |||
| f1d1c95709 | |||
| 58ce528324 | |||
| c72a5c07fe | |||
| eace918258 | |||
| 409ae99bf7 | |||
| 8961e8b4be | |||
| b526b8f246 | |||
| ed6d54e64a | |||
| 89153c2fcf | |||
| c134aff6cd | |||
| 57290c4180 | |||
| 84b60f8b9f | |||
| e33ae253ee | |||
| a67163fd03 | |||
| cfc04a9df0 | |||
| 3e4ff05d37 | |||
| 28034d664e | |||
| edf3fd5d31 | |||
| f7705ef134 | |||
| f0caa6be4b | |||
| 5aa38c1f43 | |||
| b809f9f03a | |||
| eabc05d6f8 | |||
| d3fb614d25 | |||
| 0eb7d404a1 | |||
| 093b57505a | |||
| 2a7cd4d94a | |||
| 4503967778 | |||
| f227f2ed61 | |||
| 553bf6d304 | |||
| 45dfef78bd | |||
| b172a5f847 | |||
| 41f80b942a | |||
| 055f983cbf | |||
| 3e9556fead | |||
| b403272389 | |||
| 60b178dcf7 | |||
| 969a9c1193 | |||
| 3643e170c5 | |||
| b5bda772af | |||
| 02ccd45bf6 | |||
| b86e7dc0e8 | |||
| afc872de5a | |||
| 56aef39014 | |||
| 578eb8b32c | |||
| f2d7ed69ca | |||
| ae07b2b299 | |||
| b99cf238e0 | |||
| 68457b7eaf | |||
| 24c74676f6 | |||
| ff708f4ad5 | |||
| 44212f6b53 | |||
| 5d1fccb2c4 | |||
| ac1ee2fe0c | |||
| 746573d28b | |||
| 09dc908332 | |||
| 35bf75bc82 | |||
| cb0268dfdd | |||
| 9186b392c9 | |||
| 4f30dd32f1 | |||
| bac2b1cb71 | |||
| 57af355d85 | |||
| 9bcce48df3 | |||
| c83630b376 | |||
| e1856bf851 | |||
| fe3525bc54 | |||
| 452dcbd016 | |||
| 7a20ea8781 | |||
| 4b489b52ef | |||
| aa86dfa956 | |||
| 02122f5e03 | |||
| 064f637006 | |||
| a9450f9ed9 | |||
| 04e916b41c | |||
| e167388e74 | |||
| 4d71c5550b | |||
| 0636616a6b | |||
| 8f17d6fcd2 | |||
| 1300389ce6 | |||
| ea8d8ba771 | |||
| 1eb6ae10c9 | |||
| 5d3e1fb95f | |||
| a9fa049183 | |||
| 9f182e6461 | |||
| 2403373457 | |||
| e9e852c499 | |||
| a1abdc8ba7 | |||
| 6130b475da | |||
| 95b4f9141e | |||
| 19aae9ffdc | |||
| 218995f9e0 | |||
| 0d167c4f2d | |||
| d44e0d8664 | |||
| 94a4e34e0c | |||
| 7d42583177 | |||
| 77a8697ca7 | |||
| 7462686778 | |||
| 44d5ce4a2e | |||
| 34888f31e6 | |||
| 0994aac656 | |||
| 0e0d38be30 | |||
| 91735e7e3f | |||
| 0d4b3e4173 | |||
| a0f15bba44 | |||
| 007cdeb9ab | |||
| 5716353518 | |||
| 87340d6c2c | |||
| fc742bcf18 | |||
| 4eb4cd8962 |
@@ -1,4 +1,4 @@
|
||||
_Looking for Umbraco version 8? [Click here](https://github.com/umbraco/Umbraco-CMS/blob/temp8/.github/V8_GETTING_STARTED.md) to go to the v8 branch_
|
||||
_Looking for Umbraco version 8? [Click here](https://github.com/umbraco/Umbraco-CMS/blob/dev-v8/.github/V8_GETTING_STARTED.md) to go to the v8 branch_
|
||||
# Contributing to Umbraco CMS
|
||||
|
||||
👍🎉 First off, thanks for taking the time to contribute! 🎉👍
|
||||
|
||||
@@ -103,11 +103,9 @@ There's two big areas that you should know about:
|
||||
1. The Umbraco backoffice is a extensible AngularJS app and requires you to run a `gulp dev` command while you're working with it, so changes are copied over to the appropriate directories and you can refresh your browser to view the results of your changes.
|
||||
You may need to run the following commands to set up gulp properly:
|
||||
```
|
||||
npm cache clean
|
||||
npm install -g gulp
|
||||
npm install -g gulp-cli
|
||||
npm cache clean --force
|
||||
npm install
|
||||
gulp build
|
||||
npm run build
|
||||
```
|
||||
2. "The rest" is a C# based codebase, with some traces of our WebForms past but mostly ASP.NET MVC based these days. You can make changes, build them in Visual Studio, and hit `F5` to see the result.
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
- [ ] I have added steps to test this contribution in the description below
|
||||
|
||||
If there's an existing issue for this PR then this fixes: <!-- link to the issue here! -->
|
||||
If there's an existing issue for this PR then this fixes <!-- link to the issue here! -->
|
||||
|
||||
### Description
|
||||
<!-- A description of the changes proposed in the pull-request and how to test these changes -->
|
||||
|
||||
+5
-3
@@ -1,7 +1,9 @@
|
||||
_You are browsing the Umbraco v8 branch. Umbraco 8 is currently under development._
|
||||
[](https://pullreminders.com?ref=badge)
|
||||
[](https://umbraco.visualstudio.com/Umbraco%20Cms/_build?definitionId=75) [](https://pullreminders.com?ref=badge)
|
||||
|
||||
_Looking for Umbraco version 7? [Click here](https://github.com/umbraco/Umbraco-CMS) to go to the v7 branch._
|
||||
|
||||
_You are browsing the Umbraco v8 branch. Umbraco 8 is currently under development._
|
||||
|
||||
_Looking for Umbraco version 7? [Click here](https://github.com/umbraco/Umbraco-CMS/tree/dev-v7) to go to the v7 branch._
|
||||
|
||||
_Ready to try out Version 8? [See the quick start guide](V8_GETTING_STARTED.md)._
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* [Visual Studio 2017 Community (Free)](https://www.visualstudio.com/vs/community/), or Professional, Enterprise, etc... _(**Minimum of Version 15.7** or higher, this is important, you WILL get issues with lesser versions)_
|
||||
* .NET Framework 4.7.2 installed, get it here: https://www.microsoft.com/net/download/thank-you/net472?survey=false
|
||||
* .NET Framework 4.7.2 developer pack, get it here: https://www.microsoft.com/net/download/thank-you/net472-developer-pack _(be sure this is the ENU file which will be named `NDP472-DevPack-ENU.exe`)_
|
||||
* Clone the Umbraco repository using the `temp8` branch. If your git client doesn't support specifying the branch as you clone then use the command `git clone --single-branch -b temp8 <your fork url>`. _(If you clone the repo using the default v7 branch and then checkout the `temp8` branch you **might** get problems)_
|
||||
* Clone the Umbraco repository using the `dev-v8` branch. If your git client doesn't support specifying the branch as you clone then use the command `git clone --single-branch -b dev-v8 <your fork url>`. _(If you clone the repo using the default v7 branch and then checkout the `dev-v8` branch you **might** get problems)_
|
||||
|
||||
### Start the solution
|
||||
|
||||
|
||||
+11
-2
@@ -15,7 +15,12 @@
|
||||
[Parameter(Mandatory=$false)]
|
||||
[Alias("c")]
|
||||
[Alias("cont")]
|
||||
[switch] $continue = $false
|
||||
[switch] $continue = $false,
|
||||
|
||||
# execute a command
|
||||
[Parameter(Mandatory=$false, ValueFromRemainingArguments=$true)]
|
||||
[String[]]
|
||||
$command
|
||||
)
|
||||
|
||||
# ################################################################
|
||||
@@ -475,7 +480,11 @@
|
||||
# run
|
||||
if (-not $get)
|
||||
{
|
||||
$ubuild.Build()
|
||||
if ($command.Length -eq 0)
|
||||
{
|
||||
$command = @( "Build" )
|
||||
}
|
||||
$ubuild.RunMethod($command);
|
||||
if ($ubuild.OnError()) { return }
|
||||
}
|
||||
if ($get) { return $ubuild }
|
||||
|
||||
+2
-2
@@ -18,5 +18,5 @@ using System.Resources;
|
||||
[assembly: AssemblyVersion("8.0.0")]
|
||||
|
||||
// these are FYI and changed automatically
|
||||
[assembly: AssemblyFileVersion("8.0.1")]
|
||||
[assembly: AssemblyInformationalVersion("8.0.1")]
|
||||
[assembly: AssemblyFileVersion("8.1.0")]
|
||||
[assembly: AssemblyInformationalVersion("8.1.0")]
|
||||
|
||||
@@ -133,7 +133,11 @@ namespace Umbraco.Core.Composing
|
||||
|
||||
Configs.RegisterWith(_register);
|
||||
|
||||
return _register.CreateFactory();
|
||||
IFactory factory = null;
|
||||
// ReSharper disable once AccessToModifiedClosure -- on purpose
|
||||
_register.Register(_ => factory, Lifetime.Singleton);
|
||||
factory = _register.CreateFactory();
|
||||
return factory;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Linq;
|
||||
using System.Net.Configuration;
|
||||
using System.Web;
|
||||
using System.Web.Configuration;
|
||||
using System.Web.Hosting;
|
||||
using System.Xml.Linq;
|
||||
using Umbraco.Core.IO;
|
||||
|
||||
@@ -17,16 +18,15 @@ namespace Umbraco.Core.Configuration
|
||||
/// </summary>
|
||||
public class GlobalSettings : IGlobalSettings
|
||||
{
|
||||
private string _localTempPath;
|
||||
|
||||
#region Private static fields
|
||||
|
||||
|
||||
// TODO these should not be static
|
||||
private static string _reservedPaths;
|
||||
private static string _reservedUrls;
|
||||
|
||||
//ensure the built on (non-changeable) reserved paths are there at all times
|
||||
internal const string StaticReservedPaths = "~/app_plugins/,~/install/,~/mini-profiler-resources/,"; //must end with a comma!
|
||||
internal const string StaticReservedUrls = "~/config/splashes/noNodes.aspx,~/.well-known,"; //must end with a comma!
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Used in unit testing to reset all config items that were set with property setters (i.e. did not come from config)
|
||||
@@ -131,7 +131,7 @@ namespace Umbraco.Core.Configuration
|
||||
: "~/App_Data/umbraco.config";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the path to umbraco's root directory (/umbraco by default).
|
||||
/// </summary>
|
||||
@@ -163,7 +163,7 @@ namespace Umbraco.Core.Configuration
|
||||
SaveSetting(Constants.AppSettings.ConfigurationStatus, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Saves a setting into the configuration file.
|
||||
/// </summary>
|
||||
@@ -206,7 +206,7 @@ namespace Umbraco.Core.Configuration
|
||||
ConfigurationManager.RefreshSection("appSettings");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether umbraco is running in [debug mode].
|
||||
/// </summary>
|
||||
@@ -250,7 +250,7 @@ namespace Umbraco.Core.Configuration
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of days that should take place between version checks.
|
||||
/// </summary>
|
||||
@@ -269,7 +269,7 @@ namespace Umbraco.Core.Configuration
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public LocalTempStorage LocalTempStorageLocation
|
||||
{
|
||||
@@ -288,25 +288,43 @@ namespace Umbraco.Core.Configuration
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_localTempPath != null)
|
||||
return _localTempPath;
|
||||
|
||||
switch (LocalTempStorageLocation)
|
||||
{
|
||||
case LocalTempStorage.AspNetTemp:
|
||||
return System.IO.Path.Combine(HttpRuntime.CodegenDir, "UmbracoData");
|
||||
return _localTempPath = System.IO.Path.Combine(HttpRuntime.CodegenDir, "UmbracoData");
|
||||
|
||||
case LocalTempStorage.EnvironmentTemp:
|
||||
// include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back
|
||||
// to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not
|
||||
// utilizing an old path - assuming we cannot have SHA1 collisions on AppDomainAppId
|
||||
var appDomainHash = HttpRuntime.AppDomainAppId.GenerateHash();
|
||||
return System.IO.Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData", appDomainHash);
|
||||
|
||||
// environment temp is unique, we need a folder per site
|
||||
|
||||
// use a hash
|
||||
// combine site name and application id
|
||||
// site name is a Guid on Cloud
|
||||
// application id is eg /LM/W3SVC/123456/ROOT
|
||||
// the combination is unique on one server
|
||||
// and, if a site moves from worker A to B and then back to A...
|
||||
// hopefully it gets a new Guid or new application id?
|
||||
|
||||
var siteName = HostingEnvironment.SiteName;
|
||||
var applicationId = HostingEnvironment.ApplicationID; // ie HttpRuntime.AppDomainAppId
|
||||
|
||||
var hashString = siteName + "::" + applicationId;
|
||||
var hash = hashString.GenerateHash();
|
||||
var siteTemp = System.IO.Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData", hash);
|
||||
|
||||
return _localTempPath = System.IO.Path.Combine(siteTemp, "umbraco.config");
|
||||
|
||||
//case LocalTempStorage.Default:
|
||||
//case LocalTempStorage.Unknown:
|
||||
default:
|
||||
return IOHelper.MapPath("~/App_Data/TEMP");
|
||||
return _localTempPath = IOHelper.MapPath("~/App_Data/TEMP");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default UI language.
|
||||
/// </summary>
|
||||
|
||||
@@ -8,12 +8,9 @@ namespace Umbraco.Core.IO.MediaPathSchemes
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>Path is "{combinedGuid}/{filename}" where combinedGuid is a combination of itemGuid and propertyGuid.</para>
|
||||
/// <para>This scheme is dangerous, as it does not prevent potential collisions.</para>
|
||||
/// </remarks>
|
||||
public class CombinedGuidsMediaPathScheme : IMediaPathScheme
|
||||
{
|
||||
private const int DirectoryLength = 8;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string GetFilePath(IMediaFileSystem fileSystem, Guid itemGuid, Guid propertyGuid, string filename, string previous = null)
|
||||
{
|
||||
@@ -21,7 +18,7 @@ namespace Umbraco.Core.IO.MediaPathSchemes
|
||||
// for a single content cannot store two different files with the same name
|
||||
|
||||
var combinedGuid = GuidUtils.Combine(itemGuid, propertyGuid);
|
||||
var directory = GuidUtils.ToBase32String(combinedGuid, DirectoryLength); // see also HexEncoder, we may want to fragment path eg 12/e4/f3...
|
||||
var directory = HexEncoder.Encode(combinedGuid.ToByteArray()/*'/', 2, 4*/); // could use ext to fragment path eg 12/e4/f2/...
|
||||
return Path.Combine(directory, filename).Replace('\\', '/');
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace Umbraco.Core.IO.MediaPathSchemes
|
||||
/// Implements a unique directory media path scheme.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>This scheme provides short paths, yet handle potential collisions.</para>
|
||||
/// <para>This scheme provides deterministic short paths, with potential collisions.</para>
|
||||
/// </remarks>
|
||||
public class UniqueMediaPathScheme : IMediaPathScheme
|
||||
{
|
||||
@@ -16,23 +16,22 @@ namespace Umbraco.Core.IO.MediaPathSchemes
|
||||
/// <inheritdoc />
|
||||
public string GetFilePath(IMediaFileSystem fileSystem, Guid itemGuid, Guid propertyGuid, string filename, string previous = null)
|
||||
{
|
||||
string directory;
|
||||
|
||||
// no point "combining" guids if all we want is some random guid - just get a new one
|
||||
// and then, because we don't want collisions, ensure that the directory does not already exist
|
||||
// (should be quite rare, but eh...)
|
||||
|
||||
do
|
||||
{
|
||||
var combinedGuid = Guid.NewGuid();
|
||||
directory = GuidUtils.ToBase32String(combinedGuid, DirectoryLength); // see also HexEncoder, we may want to fragment path eg 12/e4/f3...
|
||||
|
||||
} while (fileSystem.DirectoryExists(directory));
|
||||
var combinedGuid = GuidUtils.Combine(itemGuid, propertyGuid);
|
||||
var directory = GuidUtils.ToBase32String(combinedGuid, DirectoryLength);
|
||||
|
||||
return Path.Combine(directory, filename).Replace('\\', '/');
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public string GetDeleteDirectory(IMediaFileSystem fileSystem, string filepath) => Path.GetDirectoryName(filepath);
|
||||
/// <remarks>
|
||||
/// <para>Returning null so that <see cref="MediaFileSystem.DeleteMediaFiles"/> does *not*
|
||||
/// delete any directory. This is because the above shortening of the Guid to 8 chars
|
||||
/// means we're increasing the risk of collision, and we don't want to delete files
|
||||
/// belonging to other media items.</para>
|
||||
/// <para>And, at the moment, we cannot delete directory "only if it is empty" because of
|
||||
/// race conditions. We'd need to implement locks in <see cref="MediaFileSystem"/> for
|
||||
/// this.</para>
|
||||
/// </remarks>
|
||||
public string GetDeleteDirectory(IMediaFileSystem fileSystem, string filepath) => null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Serilog.Events;
|
||||
using Serilog.Formatting.Compact.Reader;
|
||||
|
||||
@@ -10,13 +11,15 @@ namespace Umbraco.Core.Logging.Viewer
|
||||
internal class JsonLogViewer : LogViewerSourceBase
|
||||
{
|
||||
private readonly string _logsPath;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public JsonLogViewer(string logsPath = "", string searchPath = "") : base(searchPath)
|
||||
public JsonLogViewer(ILogger logger, string logsPath = "", string searchPath = "") : base(searchPath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(logsPath))
|
||||
logsPath = $@"{AppDomain.CurrentDomain.BaseDirectory}\App_Data\Logs\";
|
||||
|
||||
_logsPath = logsPath;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
private const int FileSizeCap = 100;
|
||||
@@ -77,8 +80,14 @@ namespace Umbraco.Core.Logging.Viewer
|
||||
using (var stream = new StreamReader(fs))
|
||||
{
|
||||
var reader = new LogEventReader(stream);
|
||||
while (reader.TryRead(out var evt))
|
||||
while (TryRead(reader, out var evt))
|
||||
{
|
||||
//We may get a null if log line is malformed
|
||||
if (evt == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (count > skip + take)
|
||||
{
|
||||
break;
|
||||
@@ -105,5 +114,21 @@ namespace Umbraco.Core.Logging.Viewer
|
||||
return logs;
|
||||
}
|
||||
|
||||
private bool TryRead(LogEventReader reader, out LogEvent evt)
|
||||
{
|
||||
try
|
||||
{
|
||||
return reader.TryRead(out evt);
|
||||
}
|
||||
catch (JsonReaderException ex)
|
||||
{
|
||||
// As we are reading/streaming one line at a time in the JSON file
|
||||
// Thus we can not report the line number, as it will always be 1
|
||||
_logger.Error<JsonLogViewer>(ex, "Unable to parse a line in the JSON log file");
|
||||
|
||||
evt = null;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace Umbraco.Core.Logging.Viewer
|
||||
{
|
||||
public void Compose(Composition composition)
|
||||
{
|
||||
composition.SetLogViewer(_ => new JsonLogViewer());
|
||||
composition.SetLogViewer(_ => new JsonLogViewer(composition.Logger));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
using Umbraco.Core.Migrations.PostMigrations;
|
||||
|
||||
namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
|
||||
{
|
||||
public class ChangeNuCacheJsonFormat : MigrationBase
|
||||
{
|
||||
public ChangeNuCacheJsonFormat(IMigrationContext context) : base(context)
|
||||
{ }
|
||||
|
||||
public override void Migrate()
|
||||
{
|
||||
// nothing - just adding the post-migration
|
||||
Context.AddPostMigration<RebuildPublishedSnapshot>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -292,7 +292,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
if (psql.Arguments[i] is string s && s == "[[[ISOCODE]]]")
|
||||
{
|
||||
psql.Arguments[i] = ordering.Culture;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -982,8 +982,14 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
// invariant: left join will yield NULL and we must use pcv to determine published
|
||||
// variant: left join may yield NULL or something, and that determines published
|
||||
|
||||
|
||||
var joins = Sql()
|
||||
.InnerJoin<ContentTypeDto>("ctype").On<ContentDto, ContentTypeDto>((content, contentType) => content.ContentTypeId == contentType.NodeId, aliasRight: "ctype");
|
||||
.InnerJoin<ContentTypeDto>("ctype").On<ContentDto, ContentTypeDto>((content, contentType) => content.ContentTypeId == contentType.NodeId, aliasRight: "ctype")
|
||||
// left join on optional culture variation
|
||||
//the magic "[[[ISOCODE]]]" parameter value will be replaced in ContentRepositoryBase.GetPage() by the actual ISO code
|
||||
.LeftJoin<ContentVersionCultureVariationDto>(nested =>
|
||||
nested.InnerJoin<LanguageDto>("langp").On<ContentVersionCultureVariationDto, LanguageDto>((ccv, lang) => ccv.LanguageId == lang.Id && lang.IsoCode == "[[[ISOCODE]]]", "ccvp", "langp"), "ccvp")
|
||||
.On<ContentVersionDto, ContentVersionCultureVariationDto>((version, ccv) => version.Id == ccv.VersionId, aliasLeft: "pcv", aliasRight: "ccvp");
|
||||
|
||||
sql = InsertJoins(sql, joins);
|
||||
|
||||
@@ -993,7 +999,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
|
||||
// when invariant, ie 'variations' does not have the culture flag (value 1), use the global 'published' flag on pcv.id,
|
||||
// otherwise check if there's a version culture variation for the lang, via ccv.id
|
||||
", (CASE WHEN (ctype.variations & 1) = 0 THEN (CASE WHEN pcv.id IS NULL THEN 0 ELSE 1 END) ELSE (CASE WHEN ccv.id IS NULL THEN 0 ELSE 1 END) END) AS ordering "); // trailing space is important!
|
||||
", (CASE WHEN (ctype.variations & 1) = 0 THEN (CASE WHEN pcv.id IS NULL THEN 0 ELSE 1 END) ELSE (CASE WHEN ccvp.id IS NULL THEN 0 ELSE 1 END) END) AS ordering "); // trailing space is important!
|
||||
|
||||
sql = Sql(sqlText, sql.Arguments);
|
||||
|
||||
|
||||
@@ -2862,7 +2862,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
{
|
||||
if (blueprint == null) throw new ArgumentNullException(nameof(blueprint));
|
||||
|
||||
var contentType = _contentTypeRepository.Get(blueprint.ContentType.Id);
|
||||
var contentType = GetContentType(blueprint.ContentType.Alias);
|
||||
var content = new Content(name, -1, contentType);
|
||||
content.Path = string.Concat(content.ParentId.ToString(), ",", content.Id);
|
||||
|
||||
@@ -2875,7 +2875,14 @@ namespace Umbraco.Core.Services.Implement
|
||||
{
|
||||
foreach (var property in blueprint.Properties)
|
||||
{
|
||||
content.SetValue(property.Alias, property.GetValue(culture), culture);
|
||||
if (property.PropertyType.VariesByCulture())
|
||||
{
|
||||
content.SetValue(property.Alias, property.GetValue(culture), culture);
|
||||
}
|
||||
else
|
||||
{
|
||||
content.SetValue(property.Alias, property.GetValue());
|
||||
}
|
||||
}
|
||||
|
||||
content.Name = blueprint.Name;
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Umbraco.Core.Strings
|
||||
/// Converts an Utf8 string into an Ascii string.
|
||||
/// </summary>
|
||||
/// <param name="text">The text to convert.</param>
|
||||
/// <param name="fail">The character to used to replace characters that cannot properly be converted.</param>
|
||||
/// <param name="fail">The character to use to replace characters that cannot properly be converted.</param>
|
||||
/// <returns>The converted text.</returns>
|
||||
public static string ToAsciiString(string text, char fail = '?')
|
||||
{
|
||||
@@ -39,7 +39,7 @@ namespace Umbraco.Core.Strings
|
||||
/// Converts an Utf8 string into an array of Ascii characters.
|
||||
/// </summary>
|
||||
/// <param name="text">The text to convert.</param>
|
||||
/// <param name="fail">The character to used to replace characters that cannot properly be converted.</param>
|
||||
/// <param name="fail">The character to use to replace characters that cannot properly be converted.</param>
|
||||
/// <returns>The converted text.</returns>
|
||||
public static char[] ToAsciiCharArray(string text, char fail = '?')
|
||||
{
|
||||
@@ -66,7 +66,7 @@ namespace Umbraco.Core.Strings
|
||||
/// </summary>
|
||||
/// <param name="input">The input array.</param>
|
||||
/// <param name="output">The output array.</param>
|
||||
/// <param name="fail">The character to used to replace characters that cannot properly be converted.</param>
|
||||
/// <param name="fail">The character to use to replace characters that cannot properly be converted.</param>
|
||||
/// <returns>The number of characters in the output array.</returns>
|
||||
/// <remarks>The caller must ensure that the output array is big enough.</remarks>
|
||||
/// <exception cref="OverflowException">The output array is not big enough.</exception>
|
||||
@@ -112,7 +112,7 @@ namespace Umbraco.Core.Strings
|
||||
/// <param name="ipos">The input position.</param>
|
||||
/// <param name="output">The output array.</param>
|
||||
/// <param name="opos">The output position.</param>
|
||||
/// <param name="fail">The character to used to replace characters that cannot properly be converted.</param>
|
||||
/// <param name="fail">The character to use to replace characters that cannot properly be converted.</param>
|
||||
/// <remarks>
|
||||
/// <para>Adapted from various sources on the 'net including <c>Lucene.Net.Analysis.ASCIIFoldingFilter</c>.</para>
|
||||
/// <para>Input should contain Utf8 characters exclusively and NOT Unicode.</para>
|
||||
|
||||
@@ -28,6 +28,8 @@ namespace Umbraco.Examine
|
||||
/// </remarks>
|
||||
internal static readonly Regex CultureIsoCodeFieldNameMatchExpression = new Regex("^([_\\w]+)_([a-z]{2}-[a-z0-9]{2,4})$", RegexOptions.Compiled);
|
||||
|
||||
//TODO: We need a public method here to just match a field name against CultureIsoCodeFieldNameMatchExpression
|
||||
|
||||
/// <summary>
|
||||
/// Returns all index fields that are culture specific (suffixed)
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Logging;
|
||||
|
||||
namespace Umbraco.Tests.Composing
|
||||
{
|
||||
[TestFixture]
|
||||
public class CompositionTests
|
||||
{
|
||||
[Test]
|
||||
public void FactoryIsResolvable()
|
||||
{
|
||||
Func<IFactory, IFactory> factoryFactory = null;
|
||||
|
||||
var mockedRegister = Mock.Of<IRegister>();
|
||||
var mockedFactory = Mock.Of<IFactory>();
|
||||
|
||||
// the mocked register creates the mocked factory
|
||||
Mock.Get(mockedRegister)
|
||||
.Setup(x => x.CreateFactory())
|
||||
.Returns(mockedFactory);
|
||||
|
||||
// the mocked register can register a factory factory
|
||||
Mock.Get(mockedRegister)
|
||||
.Setup(x => x.Register(It.IsAny<Func<IFactory, IFactory>>(), Lifetime.Singleton))
|
||||
.Callback<Func<IFactory, IFactory>, Lifetime>((ff, lt) => factoryFactory = ff);
|
||||
|
||||
// the mocked factory can invoke the factory factory
|
||||
Mock.Get(mockedFactory)
|
||||
.Setup(x => x.GetInstance(typeof(IFactory)))
|
||||
.Returns(() => factoryFactory?.Invoke(mockedFactory));
|
||||
|
||||
var logger = new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>());
|
||||
var typeLoader = new TypeLoader(Mock.Of<IAppPolicyCache>(), "", logger);
|
||||
var composition = new Composition(mockedRegister, typeLoader, logger, Mock.Of<IRuntimeState>());
|
||||
|
||||
// create the factory, ensure it is the mocked factory
|
||||
var factory = composition.CreateFactory();
|
||||
Assert.AreSame(mockedFactory, factory);
|
||||
|
||||
// ensure we can get an IFactory instance,
|
||||
// meaning that it has been properly registered
|
||||
|
||||
var resolved = factory.GetInstance<IFactory>();
|
||||
Assert.IsNotNull(resolved);
|
||||
Assert.AreSame(factory, resolved);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,9 +112,19 @@ namespace Umbraco.Tests.IO
|
||||
fs.DeleteMediaFiles(new[] { virtPath });
|
||||
Assert.IsFalse(File.Exists(physPath));
|
||||
|
||||
// ~/media/1234 is gone
|
||||
physPath = Path.GetDirectoryName(physPath);
|
||||
Assert.IsFalse(Directory.Exists(physPath));
|
||||
var scheme = Current.Factory.GetInstance<IMediaPathScheme>();
|
||||
if (scheme is UniqueMediaPathScheme)
|
||||
{
|
||||
// ~/media/1234 is *not* gone
|
||||
physPath = Path.GetDirectoryName(physPath);
|
||||
Assert.IsTrue(Directory.Exists(physPath));
|
||||
}
|
||||
else
|
||||
{
|
||||
// ~/media/1234 is gone
|
||||
physPath = Path.GetDirectoryName(physPath);
|
||||
Assert.IsFalse(Directory.Exists(physPath));
|
||||
}
|
||||
|
||||
// ~/media exists
|
||||
physPath = Path.GetDirectoryName(physPath);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using NUnit.Framework;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
@@ -47,7 +48,8 @@ namespace Umbraco.Tests.Logging
|
||||
File.Copy(exampleLogfilePath, _newLogfilePath, true);
|
||||
File.Copy(exampleSearchfilePath, _newSearchfilePath, true);
|
||||
|
||||
_logViewer = new JsonLogViewer(logsPath: _newLogfileDirPath, searchPath: _newSearchfilePath);
|
||||
var logger = Mock.Of<Core.Logging.ILogger>();
|
||||
_logViewer = new JsonLogViewer(logger, logsPath: _newLogfileDirPath, searchPath: _newSearchfilePath);
|
||||
}
|
||||
|
||||
[OneTimeTearDown]
|
||||
|
||||
@@ -118,6 +118,7 @@
|
||||
<Compile Include="Cache\SnapDictionaryTests.cs" />
|
||||
<Compile Include="Clr\ReflectionUtilitiesTests.cs" />
|
||||
<Compile Include="Collections\OrderedHashSetTests.cs" />
|
||||
<Compile Include="Composing\CompositionTests.cs" />
|
||||
<Compile Include="Composing\LightInjectValidation.cs" />
|
||||
<Compile Include="Composing\ContainerConformingTests.cs" />
|
||||
<Compile Include="CoreThings\CallContextTests.cs" />
|
||||
|
||||
@@ -1,22 +0,0 @@
|
||||
@ECHO OFF
|
||||
|
||||
ECHO.
|
||||
ECHO.
|
||||
ECHO This will only work when you have NPM available on the command line
|
||||
ECHO Works great with NodeJS Portable - https://gareth.flowers/nodejs-portable/
|
||||
ECHO.
|
||||
ECHO.
|
||||
set /P c=Are you sure you want to continue [Y/N]?
|
||||
if /I "%c%" EQU "Y" goto :setupgulp
|
||||
if /I "%c%" EQU "N" goto :eof
|
||||
|
||||
:setupgulp
|
||||
call npm install
|
||||
call npm -g install gulp
|
||||
call npm -g install gulp-cli
|
||||
|
||||
ECHO.
|
||||
ECHO.
|
||||
ECHO You should now be able to run: gulp build or gulp dev
|
||||
ECHO.
|
||||
ECHO.
|
||||
+29
-2
@@ -331,8 +331,35 @@
|
||||
|
||||
// This is a helper method to reduce the amount of code repitition for actions: Save, Publish, SendToPublish
|
||||
function performSave(args) {
|
||||
|
||||
|
||||
|
||||
// Check that all variants for publishing have a name.
|
||||
if (args.action === "publish" || args.action === "sendToPublish") {
|
||||
|
||||
if ($scope.content.variants) {
|
||||
var iVariant;
|
||||
for (var i = 0; i < $scope.content.variants.length; i++) {
|
||||
iVariant = $scope.content.variants[i];
|
||||
|
||||
iVariant.notifications = [];// maybe not needed, need to investigate.
|
||||
|
||||
if(iVariant.publish === true) {
|
||||
if (iVariant.name == null) {
|
||||
|
||||
var tokens = [iVariant.language.name];
|
||||
|
||||
localizationService.localize("publish_contentPublishedFailedByMissingName", tokens).then(function (value) {
|
||||
iVariant.notifications.push({"message": value, "type": 1});
|
||||
});
|
||||
|
||||
return $q.reject();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//Used to check validility of nested form - coming from Content Apps mostly
|
||||
//Set them all to be invalid
|
||||
var fieldsToRollback = checkValidility();
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@
|
||||
item: '=',
|
||||
onOpen: '&',
|
||||
onOpenAnchor: '&',
|
||||
index: '@'
|
||||
hotkey: '<'
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
/**
|
||||
@ngdoc directive
|
||||
@name umbraco.directives.directive:umbCheckbox
|
||||
@restrict E
|
||||
@scope
|
||||
|
||||
@description
|
||||
<b>Added in Umbraco version 7.14.0</b> Use this directive to render an umbraco checkbox.
|
||||
|
||||
<h3>Markup example</h3>
|
||||
<pre>
|
||||
<div ng-controller="My.Controller as vm">
|
||||
|
||||
<umb-checkbox
|
||||
name="checkboxlist"
|
||||
value="{{key}}"
|
||||
model="true"
|
||||
text="{{text}}">
|
||||
</umb-checkbox>
|
||||
|
||||
</div>
|
||||
</pre>
|
||||
|
||||
@param {boolean} model Set to <code>true</code> or <code>false</code> to set the checkbox to checked or unchecked.
|
||||
@param {string} input-id Set the <code>id</code> of the checkbox.
|
||||
@param {string} value Set the value of the checkbox.
|
||||
@param {string} name Set the name of the checkbox.
|
||||
@param {string} text Set the text for the checkbox label.
|
||||
@param {string} server-validation-field Set the <code>val-server-field</code> of the checkbox.
|
||||
@param {boolean} disabled Set the checkbox to be disabled.
|
||||
@param {boolean} required Set the checkbox to be required.
|
||||
@param {string} on-change Callback when the value of the checkbox changed by interaction.
|
||||
|
||||
**/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
|
||||
function UmbCheckboxController($timeout) {
|
||||
|
||||
var vm = this;
|
||||
|
||||
vm.callOnChange = function() {
|
||||
$timeout(function() {
|
||||
vm.onChange({model:vm.model, value:vm.value});
|
||||
}, 0);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
var component = {
|
||||
templateUrl: 'views/components/forms/umb-checkbox.html',
|
||||
controller: UmbCheckboxController,
|
||||
controllerAs: 'vm',
|
||||
bindings: {
|
||||
model: "=",
|
||||
inputId: "@",
|
||||
value: "@",
|
||||
name: "@",
|
||||
text: "@",
|
||||
serverValidationField: "@",
|
||||
disabled: "<",
|
||||
required: "<",
|
||||
onChange: "&"
|
||||
}
|
||||
};
|
||||
|
||||
angular.module('umbraco.directives').component('umbCheckbox', component);
|
||||
|
||||
})();
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
@ngdoc directive
|
||||
@name umbraco.directives.directive:umbRadiobutton
|
||||
@restrict E
|
||||
@scope
|
||||
|
||||
@description
|
||||
<b>Added in Umbraco version 7.14.0</b> Use this directive to render an umbraco radio button.
|
||||
|
||||
<h3>Markup example</h3>
|
||||
<pre>
|
||||
<div ng-controller="My.Controller as vm">
|
||||
|
||||
<umb-radiobutton
|
||||
name="radiobuttonlist"
|
||||
value="{{key}}"
|
||||
model="true"
|
||||
text="{{text}}">
|
||||
</umb-radiobutton>
|
||||
|
||||
</div>
|
||||
</pre>
|
||||
|
||||
@param {boolean} model Set to <code>true</code> or <code>false</code> to set the radiobutton to checked or unchecked.
|
||||
@param {string} value Set the value of the radiobutton.
|
||||
@param {string} name Set the name of the radiobutton.
|
||||
@param {string} text Set the text for the radiobutton label.
|
||||
@param {boolean} disabled Set the radiobutton to be disabled.
|
||||
@param {boolean} required Set the radiobutton to be required.
|
||||
|
||||
**/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function RadiobuttonDirective() {
|
||||
var directive = {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'views/components/forms/umb-radiobutton.html',
|
||||
scope: {
|
||||
model: "=",
|
||||
value: "@",
|
||||
name: "@",
|
||||
text: "@",
|
||||
disabled: "=",
|
||||
required: "="
|
||||
}
|
||||
};
|
||||
|
||||
return directive;
|
||||
|
||||
}
|
||||
|
||||
angular.module('umbraco.directives').directive('umbRadiobutton', RadiobuttonDirective);
|
||||
|
||||
})();
|
||||
+22
-9
@@ -19,9 +19,15 @@ angular.module("umbraco.directives")
|
||||
promises.push(assetsService.loadJs("lib/tinymce/tinymce.min.js", scope));
|
||||
}
|
||||
|
||||
var toolbar = ["code", "styleselect", "bold", "italic", "alignleft", "aligncenter", "alignright", "bullist", "numlist", "link", "umbmediapicker", "umbembeddialog"];
|
||||
if (scope.configuration && scope.configuration.toolbar) {
|
||||
toolbar = scope.configuration.toolbar;
|
||||
var editorConfig = scope.configuration ? scope.configuration : null;
|
||||
if (!editorConfig || angular.isString(editorConfig)) {
|
||||
editorConfig = tinyMceService.defaultPrevalues();
|
||||
//for the grid by default, we don't want to include the macro toolbar
|
||||
editorConfig.toolbar = _.without(editorConfig, "umbmacro");
|
||||
}
|
||||
//make sure there's a max image size
|
||||
if (!scope.configuration.maxImageSize && scope.configuration.maxImageSize !== 0) {
|
||||
editorConfig.maxImageSize = tinyMceService.defaultPrevalues().maxImageSize;
|
||||
}
|
||||
|
||||
//stores a reference to the editor
|
||||
@@ -29,9 +35,9 @@ angular.module("umbraco.directives")
|
||||
|
||||
promises.push(tinyMceService.getTinyMceEditorConfig({
|
||||
htmlId: scope.uniqueId,
|
||||
stylesheets: scope.configuration ? scope.configuration.stylesheets : null,
|
||||
toolbar: toolbar,
|
||||
mode: scope.configuration.mode
|
||||
stylesheets: editorConfig.stylesheets,
|
||||
toolbar: editorConfig.toolbar,
|
||||
mode: editorConfig.mode
|
||||
}));
|
||||
|
||||
// pin toolbar to top of screen if we have focus and it scrolls off the screen
|
||||
@@ -46,9 +52,16 @@ angular.module("umbraco.directives")
|
||||
|
||||
$q.all(promises).then(function (result) {
|
||||
|
||||
var tinyMceEditorConfig = result[promises.length - 1];
|
||||
var standardConfig = result[promises.length - 1];
|
||||
|
||||
tinyMceEditorConfig.setup = function (editor) {
|
||||
//create a baseline Config to extend upon
|
||||
var baseLineConfigObj = {
|
||||
maxImageSize: editorConfig.maxImageSize
|
||||
};
|
||||
|
||||
angular.extend(baseLineConfigObj, standardConfig);
|
||||
|
||||
baseLineConfigObj.setup = function (editor) {
|
||||
|
||||
//set the reference
|
||||
tinyMceEditor = editor;
|
||||
@@ -111,7 +124,7 @@ angular.module("umbraco.directives")
|
||||
//the elements needed
|
||||
$timeout(function () {
|
||||
tinymce.DOM.events.domLoaded = true;
|
||||
tinymce.init(tinyMceEditorConfig);
|
||||
tinymce.init(baseLineConfigObj);
|
||||
}, 150, false);
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -117,9 +117,11 @@ Use this directive to generate a list of content items presented as a flexbox gr
|
||||
};
|
||||
|
||||
scope.clickItemName = function(item, $event, $index) {
|
||||
if(scope.onClickName) {
|
||||
if(scope.onClickName && !($event.metaKey || $event.ctrlKey)) {
|
||||
scope.onClickName(item, $event, $index);
|
||||
$event.preventDefault();
|
||||
}
|
||||
$event.stopPropagation();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -117,10 +117,11 @@
|
||||
var vm = this;
|
||||
|
||||
vm.clickItem = function (item, $event) {
|
||||
if (vm.onClick) {
|
||||
if (vm.onClick && !($event.metaKey || $event.ctrlKey)) {
|
||||
vm.onClick({ item: item});
|
||||
$event.stopPropagation();
|
||||
$event.preventDefault();
|
||||
}
|
||||
$event.stopPropagation();
|
||||
};
|
||||
|
||||
vm.selectItem = function (item, $index, $event) {
|
||||
|
||||
@@ -301,6 +301,19 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
|
||||
return allProps;
|
||||
},
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.contentEditingHelper#buildCompositeVariantId
|
||||
* @methodOf umbraco.services.contentEditingHelper
|
||||
* @function
|
||||
*
|
||||
* @description
|
||||
* Returns a id for the variant that is unique between all variants on the content
|
||||
*/
|
||||
buildCompositeVariantId: function (variant) {
|
||||
return (variant.language ? variant.language.culture : "invariant") + "_" + (variant.segment ? variant.segment : "");
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
|
||||
@@ -26,6 +26,8 @@ function navigationService($routeParams, $location, $q, $timeout, $injector, eve
|
||||
navReadyPromise.resolve(mainTreeApi);
|
||||
});
|
||||
|
||||
|
||||
|
||||
//A list of query strings defined that when changed will not cause a reload of the route
|
||||
var nonRoutingQueryStrings = ["mculture", "cculture", "lq"];
|
||||
var retainedQueryStrings = ["mculture"];
|
||||
|
||||
@@ -427,8 +427,8 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
data["rel"] = img.id;
|
||||
data["data-id"] = img.id;
|
||||
}
|
||||
|
||||
editor.insertContent(editor.dom.createHTML('img', data));
|
||||
|
||||
editor.selection.setContent(editor.dom.createHTML('img', data));
|
||||
|
||||
$timeout(function () {
|
||||
var imgElm = editor.dom.get('__mcenew');
|
||||
|
||||
@@ -350,6 +350,9 @@ function treeService($q, treeResource, iconHelper, notificationsService, eventsS
|
||||
parent.children.splice(parent.children.indexOf(treeNode), 1);
|
||||
|
||||
parent.hasChildren = parent.children.length !== 0;
|
||||
|
||||
//Notify that the node has been removed
|
||||
eventsService.emit("treeService.removeNode", { node: treeNode });
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
* @param {navigationService} navigationService A reference to the navigationService
|
||||
*/
|
||||
function NavigationController($scope, $rootScope, $location, $log, $q, $routeParams, $timeout, $cookies, treeService, appState, navigationService, keyboardService, historyService, eventsService, angularHelper, languageResource, contentResource) {
|
||||
function NavigationController($scope, $rootScope, $location, $log, $q, $routeParams, $timeout, $cookies, treeService, appState, navigationService, keyboardService, historyService, eventsService, angularHelper, languageResource, contentResource, editorState) {
|
||||
|
||||
//this is used to trigger the tree to start loading once everything is ready
|
||||
var treeInitPromise = $q.defer();
|
||||
@@ -249,6 +249,20 @@ function NavigationController($scope, $rootScope, $location, $log, $q, $routePar
|
||||
$scope.infiniteMode = args && args.editors.length > 0 ? true : false;
|
||||
}));
|
||||
|
||||
evts.push(eventsService.on("treeService.removeNode", function (e, args) {
|
||||
//check to see if the current page has been removed
|
||||
|
||||
var currentEditorState = editorState.getCurrent()
|
||||
if (currentEditorState && currentEditorState.id.toString() === args.node.id.toString()) {
|
||||
//current page is loaded, so navigate to root
|
||||
var section = appState.getSectionState("currentSection");
|
||||
$location.path("/" + section);
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Based on the current state of the application, this configures the scope variables that control the main tree and language drop down
|
||||
*/
|
||||
|
||||
@@ -117,6 +117,7 @@
|
||||
@import "components/umb-confirm-action.less";
|
||||
@import "components/umb-keyboard-shortcuts-overview.less";
|
||||
@import "components/umb-checkbox-list.less";
|
||||
@import "components/umb-form-check.less";
|
||||
@import "components/umb-locked-field.less";
|
||||
@import "components/umb-tabs.less";
|
||||
@import "components/umb-load-indicator.less";
|
||||
@@ -166,6 +167,7 @@
|
||||
@import "components/umb-property-file-upload.less";
|
||||
|
||||
@import "components/users/umb-user-cards.less";
|
||||
@import "components/users/umb-user-table.less";
|
||||
@import "components/users/umb-user-details.less";
|
||||
@import "components/users/umb-user-group-picker-list.less";
|
||||
@import "components/users/umb-user-group-preview.less";
|
||||
|
||||
@@ -195,12 +195,9 @@ input[type="button"] {
|
||||
}
|
||||
// Made for Umbraco, 2019
|
||||
.btn-action {
|
||||
.buttonBackground(@blueExtraDark, @blueDark, @white, @u-white);
|
||||
}
|
||||
// Made for Umbraco, 2019
|
||||
.btn-selection {
|
||||
@btnSelectionBackgroundHover: darken(@pinkLight, 10%);
|
||||
.buttonBackground(@pinkLight, @btnSelectionBackgroundHover, @blueExtraDark, @blueDark);
|
||||
.buttonBackground(@blueExtraDark, lighten(@blueExtraDark, 10), @white, @u-white);
|
||||
transition: background-color 240ms;
|
||||
font-weight: 700;
|
||||
}
|
||||
// Made for Umbraco, 2019, used for buttons that has to stand back.
|
||||
.btn-white {
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
.umb-editor-sub-header {
|
||||
padding: 10px 0;
|
||||
margin-bottom: 10px;
|
||||
background: @gray-10;
|
||||
background: @brownGrayLight;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-top: -10px;
|
||||
@@ -12,7 +12,7 @@
|
||||
&.nested {
|
||||
margin-top: 0;
|
||||
margin-bottom: 0;
|
||||
background: @gray-10;
|
||||
background: @brownGrayLight;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -250,3 +250,11 @@
|
||||
.form-horizontal .umb-overlay .controls {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
|
||||
.umb-overlay .text-error {
|
||||
color: @formErrorText;
|
||||
}
|
||||
|
||||
.umb-overlay .text-success {
|
||||
color: @formSuccessText;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
@checkboxWidth: 15px;
|
||||
@checkboxHeight: 15px;
|
||||
|
||||
.umb-checkbox-list {
|
||||
list-style: none;
|
||||
margin-left: 0;
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
user-select: none;
|
||||
box-shadow: 0 1px 1px 0 rgba(0,0,0,0.16);
|
||||
border-radius: 3px;
|
||||
|
||||
}
|
||||
|
||||
.umb-content-grid__item.-selected {
|
||||
@@ -59,7 +58,8 @@
|
||||
display: inline-flex;
|
||||
|
||||
color: @ui-option-type;
|
||||
&:hover {
|
||||
&:hover, &:focus {
|
||||
text-decoration: none;
|
||||
color:@ui-option-type-hover;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,6 +61,9 @@
|
||||
|
||||
.show-validation .umb-sub-views-nav-item > a.-has-error {
|
||||
color: @red;
|
||||
&::after {
|
||||
background-color: @red;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-sub-views-nav-item .icon {
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
@checkboxWidth: 16px;
|
||||
@checkboxHeight: 16px;
|
||||
|
||||
.umb-form-check {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
align-items: center;
|
||||
position: relative;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
min-height: 22px;
|
||||
line-height: 22px;
|
||||
cursor: pointer !important;
|
||||
|
||||
&__text {
|
||||
margin: 0 0 0 26px;
|
||||
position: relative;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
&__input {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
opacity: 0;
|
||||
|
||||
&:checked ~ .umb-form-check__state .umb-form-check__check {
|
||||
border-color: @ui-option-type;
|
||||
}
|
||||
|
||||
&:focus:checked ~ .umb-form-check .umb-form-check__check,
|
||||
&:focus ~ .umb-form-check__state .umb-form-check__check {
|
||||
border-color: @inputBorderFocus;
|
||||
}
|
||||
|
||||
&:checked ~ .umb-form-check__state {
|
||||
.umb-form-check__check {
|
||||
// This only happens if the state has a radiobutton modifier
|
||||
.umb-form-check--radiobutton & {
|
||||
&:before {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
// This only happens if state has the checkbox modifier
|
||||
.umb-form-check--checkbox & {
|
||||
&:before {
|
||||
width: @checkboxWidth;
|
||||
height: @checkboxHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
// This only happens if state has the checkbox modifier
|
||||
.umb-form-check--checkbox & {
|
||||
.umb-form-check__icon {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__state {
|
||||
display: flex;
|
||||
height: 18px;
|
||||
margin-top: 2px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
&__check {
|
||||
display: flex;
|
||||
position: relative;
|
||||
background: @white;
|
||||
border: 1px solid @inputBorder;
|
||||
width: @checkboxWidth;
|
||||
height: @checkboxHeight;
|
||||
|
||||
&:before {
|
||||
content: "";
|
||||
background: @ui-option-type;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
}
|
||||
// This only happens if state has the radiobutton modifier
|
||||
.umb-form-check--radiobutton & {
|
||||
border-radius: 100%;
|
||||
|
||||
&:before {
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
border-radius: 100%;
|
||||
opacity: 0;
|
||||
transform: scale(0);
|
||||
transition: .15s ease-out;
|
||||
}
|
||||
}
|
||||
// This only happens if state has the checkbox modifier
|
||||
.umb-form-check--checkbox & {
|
||||
&:before {
|
||||
width: 0;
|
||||
height: 0;
|
||||
transition: .05s ease-out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&__icon {
|
||||
color: @white;
|
||||
text-align: center;
|
||||
font-size: 12px;
|
||||
opacity: 0;
|
||||
transition: .2s ease-out;
|
||||
|
||||
&:before {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
|
||||
&.umb-form-check--disabled {
|
||||
cursor: not-allowed !important;
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,10 @@ a.umb-list-item:focus {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.umb-list-item--error {
|
||||
color: @red;
|
||||
}
|
||||
|
||||
.umb-list-item:hover .umb-list-checkbox,
|
||||
.umb-list-item--selected .umb-list-checkbox {
|
||||
opacity: 1;
|
||||
@@ -34,4 +38,4 @@ a.umb-list-item:focus {
|
||||
|
||||
.umb-list-checkbox--visible {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -261,6 +261,7 @@
|
||||
|
||||
.umb-package-details {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
}
|
||||
|
||||
a.umb-package-details__back-link {
|
||||
@@ -280,6 +281,7 @@ a.umb-package-details__back-link {
|
||||
flex: 1 1 auto;
|
||||
margin-right: 20px;
|
||||
width: calc(~'100%' - ~'@{sidebarwidth}' - ~'20px'); // Make sure that the main content area doesn't gets affected by inline styling
|
||||
min-width: 500px;
|
||||
}
|
||||
|
||||
.umb-package-details__sidebar {
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
outline: none;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
.umb-user-card.-selectable {
|
||||
cursor: pointer;
|
||||
}
|
||||
.umb-user-card.-selected {
|
||||
&::before {
|
||||
content: "";
|
||||
@@ -31,7 +35,6 @@
|
||||
box-shadow: 0 0 4px 0 darken(@ui-selected-border, 20), inset 0 0 2px 0 darken(@ui-selected-border, 20);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.umb-user-card__content {
|
||||
@@ -44,14 +47,18 @@
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
cursor: pointer;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.umb-user-card__goToUser {
|
||||
&:hover {
|
||||
&:hover, &:focus {
|
||||
text-decoration: none;
|
||||
.umb-user-card__name {
|
||||
text-decoration: underline;
|
||||
text-decoration: underline;
|
||||
color: @ui-option-type-hover;
|
||||
}
|
||||
.umb-avatar {
|
||||
border: 1px solid @ui-option-type-hover;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
.umb-user-table {
|
||||
|
||||
.umb-user-table-col-avatar {
|
||||
flex: 0 0 32px;
|
||||
padding: 15px 0;
|
||||
}
|
||||
|
||||
.umb-table-cell a {
|
||||
&:hover, &:focus {
|
||||
.umb-avatar {
|
||||
border: 1px solid @ui-option-type-hover;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.umb-table-body .umb-table-cell.umb-table__name {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
a {
|
||||
display: flex;
|
||||
padding: 6px 2px;
|
||||
height: 42px;
|
||||
span {
|
||||
margin: auto 14px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.umb-table-cell.umb-table__name a {
|
||||
&:hover, &:focus {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-user-table-row {
|
||||
cursor: default;
|
||||
.umb-checkmark {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-user-table-row.-selectable {
|
||||
cursor: pointer;
|
||||
|
||||
|
||||
}
|
||||
|
||||
&.-has-selection {
|
||||
.umb-user-table-row.-selectable {
|
||||
.umb-checkmark {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.umb-user-table-row.-selectable:hover {
|
||||
.umb-checkmark {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-user-table-row.-selected {
|
||||
|
||||
.umb-checkmark {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
z-index:1;
|
||||
top: 1px;
|
||||
left: 1px;
|
||||
right: 1px;
|
||||
bottom: 1px;
|
||||
border: 2px solid @ui-selected-border;
|
||||
box-shadow: 0 0 2px 0 fade(@ui-selected-border, 80%);
|
||||
pointer-events: none;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,7 +30,7 @@
|
||||
position: absolute;
|
||||
padding: 5px 8px;
|
||||
pointer-events: none;
|
||||
top: 0;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
input[type="text"] {
|
||||
|
||||
@@ -13,23 +13,25 @@
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
overflow-y: auto;
|
||||
background-color: @purple-d2;
|
||||
background-color: @blueNight;
|
||||
}
|
||||
|
||||
.login-overlay__background-image {
|
||||
background-position: center center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: cover;
|
||||
background-image: url('../img/login.jpg');
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
opacity: 0.05;
|
||||
}
|
||||
|
||||
.login-overlay__logo {
|
||||
position: absolute;
|
||||
top: 22px;
|
||||
left: 25px;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,16 @@
|
||||
|
||||
&-push {
|
||||
float:right;
|
||||
}
|
||||
}
|
||||
|
||||
&--list{
|
||||
float: left;
|
||||
}
|
||||
|
||||
&__item{
|
||||
line-height: 1;
|
||||
margin: 0 0 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-property-editor-tiny {
|
||||
@@ -69,6 +78,11 @@
|
||||
}
|
||||
}
|
||||
|
||||
.umb-property .alert {
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// Content picker
|
||||
@@ -213,7 +227,7 @@
|
||||
margin: 24px 0 0;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
|
||||
&__input {
|
||||
width: 100%;
|
||||
&-wrap{
|
||||
|
||||
@@ -37,7 +37,8 @@ ul.sections>li>a::after {
|
||||
height: 4px;
|
||||
width: 100%;
|
||||
background-color: @pinkLight;
|
||||
position: absolute;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: -4px;
|
||||
border-radius: 3px 3px 0 0;
|
||||
opacity: 0;
|
||||
|
||||
@@ -41,8 +41,8 @@
|
||||
@purple-washed: #F6F3FD;
|
||||
|
||||
// UI Colors
|
||||
@red-d1: #F02E28;// currently used for validation, and is hard coded inline in various html places :/
|
||||
@red: #D42054;// updated 2019 - should be used as validation! and is already in some cases like the .umb-validation-label
|
||||
@red-d1: #F02E28;
|
||||
@red: #D42054;// updated 2019
|
||||
@red-l1: #e22c60;// updated 2019
|
||||
@red-l2: #FE8B88;
|
||||
@red-l3: #FFB2B0;
|
||||
@@ -508,7 +508,7 @@
|
||||
@warningBorder: transparent;
|
||||
|
||||
@errorText: @white;
|
||||
@errorBackground: @red-d1;
|
||||
@errorBackground: @red;
|
||||
@errorBorder: transparent;
|
||||
|
||||
@successText: @white;
|
||||
|
||||
+19
-4
@@ -10,7 +10,7 @@
|
||||
(function() {
|
||||
"use strict";
|
||||
|
||||
function DataTypePicker($scope, dataTypeResource, dataTypeHelper, contentTypeResource, localizationService, editorService) {
|
||||
function DataTypePicker($scope, $filter, dataTypeResource, dataTypeHelper, contentTypeResource, localizationService, editorService) {
|
||||
|
||||
var vm = this;
|
||||
|
||||
@@ -119,13 +119,28 @@
|
||||
$scope.model.itemDetails = null;
|
||||
|
||||
if (vm.searchTerm) {
|
||||
vm.showFilterResult = true;
|
||||
vm.showTabs = false;
|
||||
|
||||
var regex = new RegExp(vm.searchTerm, "i");
|
||||
vm.filterResult = {
|
||||
userConfigured: filterCollection(vm.userConfigured, regex),
|
||||
typesAndEditors: filterCollection(vm.typesAndEditors, regex)
|
||||
};
|
||||
} else {
|
||||
vm.showFilterResult = false;
|
||||
vm.filterResult = null;
|
||||
vm.showTabs = true;
|
||||
}
|
||||
}
|
||||
|
||||
function filterCollection(collection, regex) {
|
||||
return _.map(_.keys(collection), function (key) {
|
||||
return {
|
||||
group: key,
|
||||
dataTypes: $filter('filter')(collection[key], function (dataType) {
|
||||
return regex.test(dataType.name) || regex.test(dataType.alias);
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function showDetailsOverlay(property) {
|
||||
@@ -201,4 +216,4 @@
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Editors.DataTypePickerController", DataTypePicker);
|
||||
|
||||
})();
|
||||
})();
|
||||
|
||||
+9
-9
@@ -79,13 +79,13 @@
|
||||
</umb-tab-content>
|
||||
</div>
|
||||
<!-- FILTER RESULTS -->
|
||||
<div ng-if="vm.showFilterResult">
|
||||
<div ng-if="vm.filterResult">
|
||||
<h5 class="-border-bottom -black"><localize key="contentTypeEditor_reuse"></localize></h5>
|
||||
<div ng-repeat="(key,value) in vm.userConfigured">
|
||||
<div ng-if="(value | filter:vm.searchTerm).length > 0">
|
||||
<h5>{{key}}</h5>
|
||||
<div ng-repeat="result in vm.filterResult.userConfigured">
|
||||
<div ng-if="result.dataTypes.length > 0">
|
||||
<h5>{{result.group}}</h5>
|
||||
<ul class="umb-card-grid" ng-mouseleave="vm.hideDetailsOverlay()">
|
||||
<li ng-repeat="dataType in value | orderBy:'name' | filter: vm.searchTerm"
|
||||
<li ng-repeat="dataType in result.dataTypes | orderBy:'name'"
|
||||
ng-mouseover="vm.showDetailsOverlay(dataType)"
|
||||
ng-click="vm.pickDataType(dataType)"
|
||||
class="-four-in-row">
|
||||
@@ -101,11 +101,11 @@
|
||||
</div>
|
||||
</div>
|
||||
<h5 class="-border-bottom -black"><localize key="contentTypeEditor_availableEditors"></localize></h5>
|
||||
<div ng-repeat="(key,value) in vm.typesAndEditors">
|
||||
<div ng-if="(value | filter:vm.searchTerm).length > 0">
|
||||
<h5>{{key}}</h5>
|
||||
<div ng-repeat="result in vm.filterResult.typesAndEditors">
|
||||
<div ng-if="result.dataTypes.length > 0">
|
||||
<h5>{{result.group}}</h5>
|
||||
<ul class="umb-card-grid" ng-mouseleave="vm.hideDetailsOverlay()">
|
||||
<li ng-repeat="systemDataType in value | orderBy:'name' | filter: vm.searchTerm"
|
||||
<li ng-repeat="systemDataType in result.dataTypes | orderBy:'name'"
|
||||
ng-mouseover="vm.showDetailsOverlay(systemDataType)"
|
||||
ng-click="vm.pickEditor(systemDataType)"
|
||||
class="-four-in-row">
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<div ng-controller="Umbraco.Overlays.UserController">
|
||||
|
||||
<div class="umb-control-group" ng-if="!showPasswordFields">
|
||||
|
||||
<h5><localize key="user_yourProfile" /></h5>
|
||||
@@ -79,7 +78,7 @@
|
||||
</div>
|
||||
|
||||
|
||||
<div class="umb-control-group" ng-if="!showPasswordFields">
|
||||
<div class="umb-control-group" ng-if="!showPasswordFields && history.length">
|
||||
<h5><localize key="user_yourHistory" /></h5>
|
||||
<ul class="umb-tree">
|
||||
<li ng-repeat="item in history | orderBy:'time':true">
|
||||
@@ -127,7 +126,7 @@
|
||||
|
||||
</div>
|
||||
|
||||
<div class="umb-control-group">
|
||||
<div class="umb-control-group" ng-if="tab.length">
|
||||
<div ng-repeat="tab in dashboard">
|
||||
<div ng-repeat="property in tab.properties">
|
||||
<div>
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
<div id="login" class="umb-modalcolumn umb-dialog" ng-class="{'show-validation': vm.loginForm.$invalid}" ng-cloak>
|
||||
|
||||
<div class="login-overlay__background-image" ng-if="vm.backgroundImage" ng-style="{'background-image':'url(' + vm.backgroundImage + ')'}"></div>
|
||||
<div class="login-overlay__background-image" ng-style="{'background-image': 'url('+vm.backgroundImage+')'}"></div>
|
||||
|
||||
<div class="login-overlay__logo">
|
||||
<img ng-src="assets/img/application/logo.png" ng-srcset="assets/img/application/logo@2x.png 2x, assets/img/application/logo@3x.png 3x">
|
||||
<img src="assets/img/application/umbraco_logo_white.svg">
|
||||
</div>
|
||||
|
||||
<div ng-show="vm.invitedUser != null" class="umb-login-container">
|
||||
@@ -37,11 +37,11 @@
|
||||
<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>
|
||||
</span>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<umb-button
|
||||
<umb-button
|
||||
type="submit"
|
||||
button-style="success"
|
||||
state="vm.invitedUserPasswordModel.buttonState"
|
||||
@@ -58,7 +58,7 @@
|
||||
|
||||
<ng-form name="vm.avatarForm">
|
||||
|
||||
<umb-progress-bar
|
||||
<umb-progress-bar
|
||||
style="max-width: 100px; margin-bottom: 5px;"
|
||||
ng-show="vm.avatarFile.uploadStatus === 'uploading'"
|
||||
progress="{{ vm.avatarFile.uploadProgress }}"
|
||||
@@ -77,7 +77,7 @@
|
||||
ngf-pattern="{{vm.avatarFile.acceptedFileTypes}}"
|
||||
ngf-max-size="{{ vm.avatarFile.maxFileSize }}">
|
||||
|
||||
<umb-avatar
|
||||
<umb-avatar
|
||||
color="gray"
|
||||
size="xl"
|
||||
unknown-char="+"
|
||||
@@ -94,7 +94,7 @@
|
||||
<localize key="user_userinviteAvatarMessage"></localize>
|
||||
</p>
|
||||
<div class="flex justify-center items-center">
|
||||
<umb-button
|
||||
<umb-button
|
||||
type="button"
|
||||
button-style="success"
|
||||
label="Done"
|
||||
@@ -102,7 +102,7 @@
|
||||
</umb-button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
<div ng-show="vm.invitedUser == null && vm.inviteStep === 3" ng-if="vm.inviteStep === 3" class="umb-login-container">
|
||||
<div class="form">
|
||||
@@ -169,7 +169,7 @@
|
||||
</div>
|
||||
|
||||
<div class="flex justify-between items-center">
|
||||
<umb-button
|
||||
<umb-button
|
||||
button-style="success"
|
||||
size="m"
|
||||
label-key="general_login"
|
||||
@@ -261,4 +261,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+6
-6
@@ -1,10 +1,10 @@
|
||||
<a data-element="sub-view-{{vm.item.alias}}"
|
||||
tabindex="-1"
|
||||
ng-href=""
|
||||
ng-click="vm.clicked()"
|
||||
hotkey="{{vm.index+1}}"
|
||||
hotkey-when-hidden="true"
|
||||
ng-class="{'is-active': vm.item.active, '-has-error': vm.item.hasError}">
|
||||
tabindex="-1"
|
||||
ng-href=""
|
||||
ng-click="vm.clicked()"
|
||||
hotkey="{{::vm.hotkey}}"
|
||||
hotkey-when-hidden="true"
|
||||
ng-class="{'is-active': vm.item.active, '-has-error': vm.item.hasError}">
|
||||
<i class="icon {{ vm.item.icon }}"></i>
|
||||
<span class="umb-sub-views-nav-item-text">{{ vm.item.name }}</span>
|
||||
<div ng-show="vm.item.badge" class="badge -type-{{vm.item.badge.type}}">{{vm.item.badge.count}}</div>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
item="navItem"
|
||||
on-open="openNavigationItem(item)"
|
||||
on-open-anchor="openAnchorItem(item, anchor)"
|
||||
index="{{$index}}">
|
||||
hotkey="$index + 1">
|
||||
</umb-editor-navigation-item>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<label class="checkbox umb-form-check umb-form-check--checkbox" ng-class="{ 'umb-form-check--disabled': disabled }">
|
||||
<input type="checkbox"
|
||||
id="{{vm.inputId}}"
|
||||
name="{{vm.name}}"
|
||||
value="{{vm.value}}"
|
||||
class="umb-form-check__input"
|
||||
val-server-field="{{vm.serverValidationField}}"
|
||||
ng-model="vm.model"
|
||||
ng-disabled="vm.disabled"
|
||||
ng-required="vm.required"
|
||||
ng-change="vm.callOnChange()"/>
|
||||
|
||||
<span class="umb-form-check__state" aria-hidden="true">
|
||||
<span class="umb-form-check__check">
|
||||
<i class="umb-form-check__icon icon-check"></i>
|
||||
</span>
|
||||
</span>
|
||||
<span class="umb-form-check__text">{{vm.text}}</span>
|
||||
</label>
|
||||
@@ -0,0 +1,13 @@
|
||||
<label class="radio umb-form-check umb-form-check--radiobutton" ng-class="{ 'umb-form-check--disabled': disabled }">
|
||||
<input type="radio" name="{{name}}"
|
||||
value="{{value}}"
|
||||
class="umb-form-check__input"
|
||||
ng-model="model"
|
||||
ng-disabled="disabled"
|
||||
ng-required="required" />
|
||||
|
||||
<span class="umb-form-check__state" aria-hidden="true">
|
||||
<span class="umb-form-check__check"></span>
|
||||
</span>
|
||||
<span class="umb-form-check__text">{{text}}</span>
|
||||
</label>
|
||||
@@ -10,10 +10,13 @@
|
||||
|
||||
<div class="umb-content-grid__content">
|
||||
|
||||
<div class="umb-content-grid__item-name" ng-click="clickItemName(item, $event, $index)" ng-class="{'-light': !item.published && item.updater != null}">
|
||||
<a class="umb-content-grid__item-name"
|
||||
ng-href="{{'#' + item.editPath}}"
|
||||
ng-click="clickItemName(item, $event, $index)"
|
||||
ng-class="{'-light': !item.published && item.updater != null}">
|
||||
<i class="umb-content-grid__icon {{ item.icon }}"></i>
|
||||
<span>{{ item.name }}</span>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<ul class="umb-content-grid__details-list" ng-class="{'-light': !item.published && item.updater != null}">
|
||||
<li class="umb-content-grid__details-item" ng-if="item.state">
|
||||
|
||||
@@ -40,7 +40,8 @@
|
||||
<i class="umb-table-body__icon umb-table-body__checkicon icon-check"></i>
|
||||
</div>
|
||||
<div class="umb-table-cell umb-table__name">
|
||||
<a title="{{ item.name }}" class="umb-table-body__link" href=""
|
||||
<a title="{{ item.name }}" class="umb-table-body__link"
|
||||
ng-href="{{'#' + item.editPath}}"
|
||||
ng-click="vm.clickItem(item, $event)"
|
||||
ng-bind="item.name">
|
||||
</a>
|
||||
|
||||
@@ -46,8 +46,7 @@
|
||||
|
||||
if (data.language !== "undefined") {
|
||||
var lang = vm.languages.filter(function (l) {
|
||||
return matchLanguageById(l, data.language.Id);
|
||||
|
||||
return matchLanguageById(l, data.language);
|
||||
});
|
||||
if (lang.length > 0) {
|
||||
vm.language = lang[0];
|
||||
@@ -116,6 +115,7 @@
|
||||
if(response.valid) {
|
||||
|
||||
vm.submitButtonState = "success";
|
||||
closeDialog();
|
||||
|
||||
// show validation messages for each domain
|
||||
} else {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function PublishController($scope, localizationService) {
|
||||
function PublishController($scope, localizationService, contentEditingHelper) {
|
||||
|
||||
var vm = this;
|
||||
vm.loading = true;
|
||||
@@ -14,34 +14,51 @@
|
||||
|
||||
/** Returns true if publishing is possible based on if there are un-published mandatory languages */
|
||||
function canPublish() {
|
||||
var selected = [];
|
||||
|
||||
var possible = false;
|
||||
for (var i = 0; i < vm.variants.length; i++) {
|
||||
var variant = vm.variants[i];
|
||||
|
||||
//if this variant will show up in the publish-able list
|
||||
var publishable = dirtyVariantFilter(variant);
|
||||
var published = !(variant.state === "NotCreated" || variant.state === "Draft");
|
||||
|
||||
if ((variant.language.isMandatory && !published) && (!publishable || !variant.publish)) {
|
||||
//if a mandatory variant isn't published
|
||||
//and it's not publishable or not selected to be published
|
||||
//then we cannot continue
|
||||
|
||||
// TODO: Show a message when this occurs
|
||||
var state = canVariantPublish(variant);
|
||||
if (state === true) {
|
||||
possible = true;
|
||||
}
|
||||
if (state === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (variant.publish) {
|
||||
selected.push(variant.publish);
|
||||
}
|
||||
}
|
||||
return selected.length > 0;
|
||||
return possible;
|
||||
}
|
||||
|
||||
/** Returns true if publishing is possible based on if the variant is a un-published mandatory language */
|
||||
function canVariantPublish(variant) {
|
||||
|
||||
//if this variant will show up in the publish-able list
|
||||
var publishable = dirtyVariantFilter(variant);
|
||||
var published = !(variant.state === "NotCreated" || variant.state === "Draft");
|
||||
|
||||
// is this variant mandatory:
|
||||
if (variant.language.isMandatory && !published && !variant.publish) {
|
||||
//if a mandatory variant isn't published or set to be published
|
||||
//then we cannot continue
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// is this variant selected for publish:
|
||||
if (variant.publish === true) {
|
||||
return publishable;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function changeSelection(variant) {
|
||||
|
||||
$scope.model.disableSubmitButton = !canPublish();
|
||||
//need to set the Save state to true if publish is true
|
||||
variant.save = variant.publish;
|
||||
|
||||
variant.willPublish = canVariantPublish(variant);
|
||||
}
|
||||
|
||||
function dirtyVariantFilter(variant) {
|
||||
@@ -99,32 +116,49 @@
|
||||
|
||||
_.each(vm.variants,
|
||||
function (variant) {
|
||||
if(variant.state !== "NotCreated"){
|
||||
vm.isNew = false;
|
||||
if(variant.state === "NotCreated") {
|
||||
vm.isNew = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
_.each(vm.variants,
|
||||
function (variant) {
|
||||
variant.compositeId = variant.language.culture + "_" + (variant.segment ? variant.segment : "");
|
||||
variant.compositeId = contentEditingHelper.buildCompositeVariantId(variant);
|
||||
variant.htmlId = "_content_variant_" + variant.compositeId;
|
||||
|
||||
// reset to not be published
|
||||
variant.publish = false;
|
||||
variant.save = false;
|
||||
|
||||
//check for pristine variants
|
||||
if (!vm.hasPristineVariants) {
|
||||
vm.hasPristineVariants = pristineVariantFilter(variant);
|
||||
}
|
||||
|
||||
if(hasAnyData(variant)){
|
||||
|
||||
// If the variant havent been created jet.
|
||||
if(variant.state === "NotCreated") {
|
||||
// If the variant is mandatory, then set the variant to be published.
|
||||
if (variant.language.isMandatory === true) {
|
||||
variant.publish = true;
|
||||
variant.save = true;
|
||||
}
|
||||
}
|
||||
|
||||
variant.canPublish = dirtyVariantFilter(variant);
|
||||
|
||||
// if we have data on this variant.
|
||||
if(variant.canPublish && hasAnyData(variant)) {
|
||||
// and if some varaints havent been saved before, or they dont have a publishing date set, then we set it for publishing.
|
||||
if(vm.isNew || variant.publishDate == null){
|
||||
variant.publish = true;
|
||||
variant.save = true;
|
||||
}
|
||||
}else{
|
||||
variant.publish = false;
|
||||
variant.save = false;
|
||||
variant.canSave = false;
|
||||
}
|
||||
});
|
||||
|
||||
variant.willPublish = canVariantPublish(variant);
|
||||
}
|
||||
);
|
||||
|
||||
if (vm.variants.length !== 0) {
|
||||
//now sort it so that the current one is at the top
|
||||
@@ -153,7 +187,6 @@
|
||||
|
||||
localizationService.localize(labelKey).then(function (value) {
|
||||
vm.headline = value;
|
||||
|
||||
vm.loading = false;
|
||||
});
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
<div class="umb-list umb-list--condensed" ng-if="!vm.loading">
|
||||
|
||||
<div class="umb-list-item" ng-repeat="variant in vm.variants | filter:vm.dirtyVariantFilter track by variant.compositeId">
|
||||
<div class="umb-list-item" ng-repeat="variant in vm.variants | filter:vm.dirtyVariantFilter track by variant.compositeId" ng-class="{'umb-list-item--error': publishVariantSelectorForm.publishVariantSelector.$invalid || (variant.notifications | filter:{type:1}).length > 0}">
|
||||
<ng-form name="publishVariantSelectorForm">
|
||||
<div class="flex">
|
||||
<input id="{{variant.htmlId}}"
|
||||
@@ -18,27 +18,28 @@
|
||||
type="checkbox"
|
||||
ng-model="variant.publish"
|
||||
ng-change="vm.changeSelection(variant)"
|
||||
ng-disabled="(vm.isNew && variant.language.isMandatory) || (variant.canSave === false)"
|
||||
ng-disabled="(variant.canPublish === false)"
|
||||
style="margin-right: 8px;"
|
||||
val-server-field="{{variant.htmlId}}" />
|
||||
<div>
|
||||
<label for="{{variant.htmlId}}" style="margin-bottom: 2px;">
|
||||
<span>{{ variant.language.name }}</span>
|
||||
<strong ng-if="variant.language.isMandatory" class="umb-control-required">*</strong>
|
||||
|
||||
<span class="db umb-permission__description" ng-if="!publishVariantSelectorForm.publishVariantSelector.$invalid && !(variant.notifications && variant.notifications.length > 0)">
|
||||
<umb-variant-state variant="variant"></umb-variant-state>
|
||||
<span ng-if="variant.language.isMandatory"> - </span>
|
||||
<span ng-if="variant.language.isMandatory" ng-class="{'text-error': (variant.language.isMandatory && variant.willPublish === false) }"><localize key="languages_mandatoryLanguage"></localize></span>
|
||||
</span>
|
||||
|
||||
<span class="db" ng-messages="publishVariantSelectorForm.publishVariantSelector.$error" show-validation-on-submit>
|
||||
<span class="db umb-permission__description text-error" ng-message="valServerField">{{publishVariantSelectorForm.publishVariantSelector.errorMsg}}</span>
|
||||
</span>
|
||||
|
||||
<span class="db" ng-repeat="notification in variant.notifications">
|
||||
<span class="db umb-permission__description" ng-class="{'text-success': notification.type === 3, 'text-error': notification.type !== 3}">{{notification.message}}</span>
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<div class="umb-permission__description" ng-if="!publishVariantSelectorForm.publishVariantSelector.$invalid && !(variant.notifications && variant.notifications.length > 0)">
|
||||
<umb-variant-state variant="variant"></umb-variant-state>
|
||||
<span ng-if="variant.language.isMandatory"> - <localize key="languages_mandatoryLanguage"></localize></span>
|
||||
</div>
|
||||
|
||||
<div ng-messages="publishVariantSelectorForm.publishVariantSelector.$error" show-validation-on-submit>
|
||||
<div class="umb-permission__description" style="color: #F02E28;" ng-message="valServerField">{{publishVariantSelectorForm.publishVariantSelector.errorMsg}}</div>
|
||||
</div>
|
||||
|
||||
<div ng-repeat="notification in variant.notifications">
|
||||
<div class="umb-permission__description" style="color: #1FB572;">{{notification.message}}</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -64,7 +65,7 @@
|
||||
</div>
|
||||
|
||||
<div ng-repeat="notification in variant.notifications">
|
||||
<div class="umb-permission__description" style="color: #1FB572;">{{notification.message}}</div>
|
||||
<div class="umb-permission__description text-success">{{notification.message}}</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -22,11 +22,13 @@
|
||||
<p><localize key="content_publishDescendantsWithVariantsHelp"></localize></p>
|
||||
</div>
|
||||
|
||||
<div style="margin-bottom: 15px;">
|
||||
<label>
|
||||
<input type="checkbox"
|
||||
ng-model="model.includeUnpublished"
|
||||
style="margin-right: 8px;" />
|
||||
<div style="margin-bottom: 15px;" class="flex">
|
||||
|
||||
<umb-checkbox
|
||||
input-id="includeUnpublishedSelector"
|
||||
model="model.includeUnpublished" />
|
||||
|
||||
<label for="includeUnpublishedSelector">
|
||||
<localize key="content_includeUnpublished"></localize>
|
||||
</label>
|
||||
</div>
|
||||
@@ -40,31 +42,31 @@
|
||||
<div class="umb-list-item umb-list--condensed" ng-repeat="variant in vm.variants">
|
||||
<ng-form name="publishVariantSelectorForm">
|
||||
<div class="flex">
|
||||
<input id="{{variant.htmlId}}"
|
||||
name="publishVariantSelector"
|
||||
type="checkbox"
|
||||
ng-model="variant.publish"
|
||||
ng-change="vm.changeSelection(variant)"
|
||||
style="margin-right: 8px;"
|
||||
val-server-field="{{variant.htmlId}}" />
|
||||
|
||||
<umb-checkbox
|
||||
input-id="{{variant.htmlId}}"
|
||||
name="publishVariantSelector"
|
||||
model="variant.publish"
|
||||
on-change="vm.changeSelection(variant)"
|
||||
server-validation-field="{{variant.htmlId}}"/>
|
||||
|
||||
<div>
|
||||
<label for="{{variant.htmlId}}" style="margin-bottom: 0;">
|
||||
<span>{{ variant.language.name }}</span>
|
||||
|
||||
<span class="db umb-permission__description" ng-if="!publishVariantSelectorForm.publishVariantSelector.$invalid && !(variant.notifications && variant.notifications.length > 0)">
|
||||
<umb-variant-state variant="variant"></umb-variant-state>
|
||||
<span ng-if="variant.language.isMandatory"> - <localize key="languages_mandatoryLanguage"></localize></span>
|
||||
</span>
|
||||
|
||||
<span class="db" ng-messages="publishVariantSelectorForm.publishVariantSelector.$error" show-validation-on-submit>
|
||||
<span class="db umb-permission__description text-error" ng-message="valServerField">{{publishVariantSelectorForm.publishVariantSelector.errorMsg}}</span>
|
||||
</span>
|
||||
|
||||
<span class="db" ng-repeat="notification in variant.notifications">
|
||||
<span class="db umb-permission__description text-success">{{notification.message}}</span>
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<div class="umb-permission__description" ng-if="!publishVariantSelectorForm.publishVariantSelector.$invalid && !(variant.notifications && variant.notifications.length > 0)">
|
||||
<umb-variant-state variant="variant"></umb-variant-state>
|
||||
<span ng-if="variant.language.isMandatory"> - <localize key="languages_mandatoryLanguage"></localize></span>
|
||||
</div>
|
||||
|
||||
<div ng-messages="publishVariantSelectorForm.publishVariantSelector.$error" show-validation-on-submit>
|
||||
<div class="umb-permission__description" style="color: #F02E28;" ng-message="valServerField">{{publishVariantSelectorForm.publishVariantSelector.errorMsg}}</div>
|
||||
</div>
|
||||
|
||||
<div ng-repeat="notification in variant.notifications">
|
||||
<div class="umb-permission__description" style="color: #1FB572;">{{notification.message}}</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function SaveContentController($scope, localizationService) {
|
||||
function SaveContentController($scope, localizationService, contentEditingHelper) {
|
||||
|
||||
var vm = this;
|
||||
vm.loading = true;
|
||||
@@ -75,7 +75,7 @@
|
||||
|
||||
_.each(vm.variants,
|
||||
function (variant) {
|
||||
variant.compositeId = variant.language.culture + "_" + (variant.segment ? variant.segment : "");
|
||||
variant.compositeId = contentEditingHelper.buildCompositeVariantId(variant);
|
||||
variant.htmlId = "_content_variant_" + variant.compositeId;
|
||||
|
||||
//check for pristine variants
|
||||
|
||||
@@ -6,54 +6,12 @@
|
||||
<umb-load-indicator></umb-load-indicator>
|
||||
</div>
|
||||
|
||||
|
||||
<div ng-if="vm.isNew && !vm.loading">
|
||||
<div ng-if="!vm.loading">
|
||||
<div style="margin-bottom: 15px;">
|
||||
<p><localize key="content_languagesToSaveForFirstTime"></localize></p>
|
||||
</div>
|
||||
|
||||
<div class="umb-list umb-list--condensed">
|
||||
|
||||
<div class="umb-list-item" ng-repeat="variant in vm.variants">
|
||||
<ng-form name="saveVariantSelectorForm">
|
||||
<div class="flex">
|
||||
<input id="{{variant.htmlId}}"
|
||||
name="saveVariantSelector"
|
||||
type="checkbox"
|
||||
ng-model="variant.save"
|
||||
ng-disabled="vm.isNew"
|
||||
style="margin-right: 8px;"
|
||||
val-server-field="{{variant.htmlId}}" />
|
||||
<div>
|
||||
<label for="{{variant.htmlId}}" style="margin-bottom: 2px;">
|
||||
<span>{{ variant.language.name }}</span>
|
||||
<strong ng-if="variant.language.isMandatory" class="umb-control-required">*</strong>
|
||||
</label>
|
||||
|
||||
<div ng-if="!saveVariantSelectorForm.$invalid && !(variant.notifications && variant.notifications.length > 0)">
|
||||
<umb-variant-state class="umb-permission__description" variant="variant"></umb-variant-state>
|
||||
</div>
|
||||
|
||||
<div ng-messages="saveVariantSelectorForm.saveVariantSelector.$error" show-validation-on-submit>
|
||||
<div class="umb-permission__description" style="color: #F02E28;" ng-message="valServerField">{{saveVariantSelectorForm.saveVariantSelector.errorMsg}}</div>
|
||||
</div>
|
||||
|
||||
<div ng-repeat="notification in variant.notifications">
|
||||
<div class="umb-permission__description" style="color: #1FB572;">{{notification.message}}</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</ng-form>
|
||||
</div>
|
||||
<br/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="!vm.isNew && !vm.loading">
|
||||
<div style="margin-bottom: 15px;">
|
||||
<p><localize key="content_languagesToSave"></localize></p>
|
||||
<p>
|
||||
<localize ng-if="!vm.isNew" key="content_languagesToSave"></localize>
|
||||
<localize ng-if="vm.isNew" key="content_languagesToSaveForFirstTime"></localize>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="umb-list umb-list--condensed">
|
||||
@@ -61,31 +19,31 @@
|
||||
<div class="umb-list-item" ng-repeat="variant in vm.variants | filter:vm.dirtyVariantFilter track by variant.compositeId">
|
||||
<ng-form name="saveVariantSelectorForm">
|
||||
<div class="flex">
|
||||
<input id="{{variant.htmlId}}"
|
||||
name="saveVariantSelector"
|
||||
type="checkbox"
|
||||
ng-model="variant.save"
|
||||
ng-change="vm.changeSelection(variant)"
|
||||
style="margin-right: 8px;"
|
||||
val-server-field="{{variant.htmlId}}" />
|
||||
|
||||
<umb-checkbox
|
||||
input-id="{{variant.htmlId}}"
|
||||
name="saveVariantSelector"
|
||||
model="variant.save"
|
||||
on-change="vm.changeSelection(variant)"
|
||||
server-validation-field="{{variant.htmlId}}"/>
|
||||
|
||||
<div>
|
||||
<label for="{{variant.htmlId}}" style="margin-bottom: 2px;">
|
||||
<span>{{ variant.language.name }}</span>
|
||||
<strong ng-if="variant.language.isMandatory" class="umb-control-required">*</strong>
|
||||
|
||||
<span class="db" ng-if="!saveVariantSelectorForm.$invalid && !(variant.notifications && variant.notifications.length > 0)">
|
||||
<umb-variant-state class="umb-permission__description" variant="variant"></umb-variant-state>
|
||||
</span>
|
||||
|
||||
<span class="db" ng-messages="saveVariantSelectorForm.saveVariantSelector.$error" show-validation-on-submit>
|
||||
<span class="db umb-permission__description text-error" ng-message="valServerField">{{saveVariantSelectorForm.saveVariantSelector.errorMsg}}</span>
|
||||
</span>
|
||||
|
||||
<span class="db" ng-repeat="notification in variant.notifications">
|
||||
<span class="db umb-permission__description text-success">{{notification.message}}</span>
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<div ng-if="!saveVariantSelectorForm.$invalid && !(variant.notifications && variant.notifications.length > 0)">
|
||||
<umb-variant-state class="umb-permission__description" variant="variant"></umb-variant-state>
|
||||
</div>
|
||||
|
||||
<div ng-messages="saveVariantSelectorForm.saveVariantSelector.$error" show-validation-on-submit>
|
||||
<div class="umb-permission__description" style="color: #F02E28;" ng-message="valServerField">{{saveVariantSelectorForm.saveVariantSelector.errorMsg}}</div>
|
||||
</div>
|
||||
|
||||
<div ng-repeat="notification in variant.notifications">
|
||||
<div class="umb-permission__description" style="color: #1FB572;">{{notification.message}}</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -96,7 +54,10 @@
|
||||
|
||||
<div class="umb-list umb-list--condensed" ng-if="vm.hasPristineVariants">
|
||||
<div style="margin-bottom: 15px; font-weight: bold;">
|
||||
<p><localize key="content_unmodifiedLanguages"></localize></p>
|
||||
<p>
|
||||
<localize ng-if="!vm.isNew" key="content_unmodifiedLanguages"></localize>
|
||||
<localize ng-if="vm.isNew" key="content_untouchedLanguagesForFirstTime"></localize>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="umb-list-item" ng-repeat="variant in vm.variants | filter:vm.pristineVariantFilter">
|
||||
@@ -111,7 +72,7 @@
|
||||
</div>
|
||||
|
||||
<div ng-repeat="notification in variant.notifications">
|
||||
<div class="umb-permission__description" style="color: #1FB572;">{{notification.message}}</div>
|
||||
<div class="umb-permission__description text-success">{{notification.message}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function ScheduleContentController($scope, $timeout, localizationService, dateHelper, userService) {
|
||||
function ScheduleContentController($scope, $timeout, localizationService, dateHelper, userService, contentEditingHelper) {
|
||||
|
||||
var vm = this;
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
|
||||
_.each(vm.variants,
|
||||
function (variant) {
|
||||
variant.compositeId = variant.language.culture + "_" + (variant.segment ? variant.segment : "");
|
||||
variant.compositeId = contentEditingHelper.buildCompositeVariantId(variant);
|
||||
variant.htmlId = "_content_variant_" + variant.compositeId;
|
||||
|
||||
//check for pristine variants
|
||||
|
||||
@@ -87,23 +87,24 @@
|
||||
<div class="umb-list-item" ng-repeat="variant in vm.variants | filter:vm.dirtyVariantFilter">
|
||||
<ng-form name="scheduleSelectorForm">
|
||||
<div class="flex">
|
||||
<input id="{{'saveVariantSelector_' + variant.language.culture}}"
|
||||
name="saveVariantSelector"
|
||||
type="checkbox"
|
||||
ng-model="variant.save"
|
||||
ng-change="vm.changeSelection(variant)"
|
||||
style="margin-right: 8px;" />
|
||||
|
||||
<umb-checkbox
|
||||
input-id="{{'saveVariantSelector_' + variant.language.culture}}"
|
||||
name="saveVariantSelector"
|
||||
model="variant.save"
|
||||
on-change="vm.changeSelection(variant)"/>
|
||||
|
||||
<div>
|
||||
|
||||
<label for="{{'saveVariantSelector_' + variant.language.culture}}" style="margin-bottom: 2px;">
|
||||
<span>{{ variant.language.name }}</span>
|
||||
</label>
|
||||
|
||||
<div class="umb-permission__description"
|
||||
ng-if="!scheduleSelectorForm.$invalid && !(variant.notifications && variant.notifications.length > 0)">
|
||||
<umb-variant-state variant="variant"></umb-variant-state>
|
||||
<span ng-show="variant.language.isMandatory"> - <localize key="languages_mandatoryLanguage"></localize></span>
|
||||
</div>
|
||||
<span class="db umb-permission__description"
|
||||
ng-if="!scheduleSelectorForm.$invalid && !(variant.notifications && variant.notifications.length > 0)">
|
||||
<umb-variant-state variant="variant"></umb-variant-state>
|
||||
<span ng-show="variant.language.isMandatory"> - <localize key="languages_mandatoryLanguage"></localize></span>
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<div class="flex items-center" style="margin-top: 10px; margin-bottom: 10px;">
|
||||
|
||||
@@ -166,11 +167,11 @@
|
||||
val-server-field="{{variant.htmlId}}" />
|
||||
|
||||
<div ng-messages="scheduleSelectorForm.saveVariantReleaseDate.$error" show-validation-on-submit>
|
||||
<div class="umb-permission__description" style="color: #F02E28;" ng-message="valServerField">{{scheduleSelectorForm.saveVariantReleaseDate.errorMsg}}</div>
|
||||
<div class="umb-permission__description text-error" ng-message="valServerField">{{scheduleSelectorForm.saveVariantReleaseDate.errorMsg}}</div>
|
||||
</div>
|
||||
|
||||
<div ng-repeat="notification in variant.notifications">
|
||||
<div class="umb-permission__description" style="color: #1FB572;">{{notification.message}}</div>
|
||||
<div class="umb-permission__description text-success">{{notification.message}}</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function SendToPublishController($scope, localizationService) {
|
||||
function SendToPublishController($scope, localizationService, contentEditingHelper) {
|
||||
|
||||
var vm = this;
|
||||
vm.loading = true;
|
||||
@@ -23,6 +23,12 @@
|
||||
|
||||
|
||||
if (vm.variants.length !== 0) {
|
||||
_.each(vm.variants,
|
||||
function (variant) {
|
||||
variant.compositeId = contentEditingHelper.buildCompositeVariantId(variant);
|
||||
variant.htmlId = "_content_variant_" + variant.compositeId;
|
||||
});
|
||||
|
||||
//now sort it so that the current one is at the top
|
||||
vm.variants = _.sortBy(vm.variants, function (v) {
|
||||
return v.active ? 0 : 1;
|
||||
|
||||
@@ -13,31 +13,31 @@
|
||||
<div class="umb-list-item" ng-repeat="variant in vm.variants | filter:vm.modifiedVariantFilter">
|
||||
<ng-form name="publishVariantSelectorForm">
|
||||
<div class="flex">
|
||||
<input id="{{variant.htmlId}}"
|
||||
name="publishVariantSelector"
|
||||
type="checkbox"
|
||||
ng-model="variant.save"
|
||||
ng-change="vm.changeSelection(variant)"
|
||||
style="margin-right: 8px;"
|
||||
val-server-field="{{variant.htmlId}}" />
|
||||
|
||||
<umb-checkbox
|
||||
input-id="{{variant.htmlId}}"
|
||||
name="publishVariantSelector"
|
||||
model="variant.save"
|
||||
on-change="vm.changeSelection(variant)"
|
||||
server-validation-field="{{variant.htmlId}}"/>
|
||||
|
||||
<div>
|
||||
<label for="{{variant.htmlId}}" style="margin-bottom: 2px;">
|
||||
<span>{{ variant.language.name }}</span>
|
||||
<strong ng-if="variant.language.isMandatory" class="umb-control-required">*</strong>
|
||||
|
||||
<span class="db" ng-if="!publishVariantSelectorForm.publishVariantSelector.$invalid && !(variant.notifications && variant.notifications.length > 0)">
|
||||
<umb-variant-state class="umb-permission__description" variant="variant"></umb-variant-state>
|
||||
</span>
|
||||
|
||||
<span class="db" ng-messages="publishVariantSelectorForm.publishVariantSelector.$error" show-validation-on-submit>
|
||||
<span class="db umb-permission__description text-error" ng-message="valServerField">{{publishVariantSelectorForm.publishVariantSelector.errorMsg}}</span>
|
||||
</span>
|
||||
|
||||
<span class="db" ng-repeat="notification in variant.notifications">
|
||||
<span class="db umb-permission__description text-success">{{notification.message}}</span>
|
||||
</span>
|
||||
</label>
|
||||
|
||||
<div ng-if="!publishVariantSelectorForm.publishVariantSelector.$invalid && !(variant.notifications && variant.notifications.length > 0)">
|
||||
<umb-variant-state class="umb-permission__description" variant="variant"></umb-variant-state>
|
||||
</div>
|
||||
|
||||
<div ng-messages="publishVariantSelectorForm.publishVariantSelector.$error" show-validation-on-submit>
|
||||
<div class="umb-permission__description" style="color: #F02E28;" ng-message="valServerField">{{publishVariantSelectorForm.publishVariantSelector.errorMsg}}</div>
|
||||
</div>
|
||||
|
||||
<div ng-repeat="notification in variant.notifications">
|
||||
<div class="umb-permission__description" style="color: #1FB572;">{{notification.message}}</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function UnpublishController($scope, localizationService) {
|
||||
function UnpublishController($scope, localizationService, contentEditingHelper) {
|
||||
|
||||
var vm = this;
|
||||
var autoSelectedVariants = [];
|
||||
@@ -21,6 +21,12 @@
|
||||
});
|
||||
}
|
||||
|
||||
_.each(vm.variants,
|
||||
function (variant) {
|
||||
variant.compositeId = contentEditingHelper.buildCompositeVariantId(variant);
|
||||
variant.htmlId = "_content_variant_" + variant.compositeId;
|
||||
});
|
||||
|
||||
// node has variants
|
||||
if (vm.variants.length !== 1) {
|
||||
//now sort it so that the current one is at the top
|
||||
@@ -51,7 +57,7 @@
|
||||
});
|
||||
$scope.model.disableSubmitButton = !firstSelected; //disable submit button if there is none selected
|
||||
|
||||
// if a mandatory variant is selected we want to selet all other variants
|
||||
// if a mandatory variant is selected we want to select all other variants
|
||||
// and disable selection for the others
|
||||
if(selectedVariant.save && selectedVariant.language.isMandatory) {
|
||||
|
||||
|
||||
@@ -16,24 +16,24 @@
|
||||
<div class="umb-list-item" ng-repeat="variant in vm.variants | filter:vm.publishedVariantFilter">
|
||||
<ng-form name="unpublishVariantSelectorForm">
|
||||
<div class="flex">
|
||||
<input id="{{variant.htmlId}}"
|
||||
name="unpublishVariantSelector"
|
||||
type="checkbox"
|
||||
ng-model="variant.save"
|
||||
ng-change="vm.changeSelection(variant)"
|
||||
ng-disabled="variant.disabled"
|
||||
style="margin-right: 8px;"
|
||||
val-server-field="{{variant.htmlId}}" />
|
||||
|
||||
<umb-checkbox
|
||||
input-id="{{variant.htmlId}}"
|
||||
name="unpublishVariantSelector"
|
||||
model="variant.save"
|
||||
on-change="vm.changeSelection(variant)"
|
||||
disabled="variant.disabled"
|
||||
server-validation-field="{{variant.htmlId}}"/>
|
||||
|
||||
<div>
|
||||
<label for="{{variant.htmlId}}" style="margin-bottom: 2px;">
|
||||
<span>{{ variant.language.name }}</span>
|
||||
</label>
|
||||
|
||||
<div class="umb-permission__description">
|
||||
<umb-variant-state variant="variant"></umb-variant-state>
|
||||
<span ng-if="variant.language.isMandatory"> - <localize key="languages_mandatoryLanguage"></localize></span>
|
||||
</div>
|
||||
|
||||
|
||||
<span class="db umb-permission__description">
|
||||
<umb-variant-state variant="variant"></umb-variant-state>
|
||||
<span ng-if="variant.language.isMandatory"> - <localize key="languages_mandatoryLanguage"></localize></span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ function startUpVideosDashboardController($scope, dashboardResource) {
|
||||
angular.module("umbraco").controller("Umbraco.Dashboard.StartupVideosController", startUpVideosDashboardController);
|
||||
|
||||
|
||||
function startUpDynamicContentController($timeout, $scope, dashboardResource, assetsService, tourService, eventsService) {
|
||||
function startUpDynamicContentController($q, $timeout, $scope, dashboardResource, assetsService, tourService, eventsService) {
|
||||
var vm = this;
|
||||
var evts = [];
|
||||
|
||||
@@ -167,7 +167,7 @@ function FormsController($scope, $cookies, packageResource, localizationService)
|
||||
return packageResource.installData(pack);
|
||||
}, vm.error)
|
||||
.then(function(pack) {
|
||||
vm.state = installStateComplete;
|
||||
vm.state = labels.installStateComplete;
|
||||
return packageResource.cleanUp(pack);
|
||||
}, vm.error)
|
||||
.then(vm.complete, vm.error);
|
||||
|
||||
@@ -22,7 +22,6 @@ function DataTypeDeleteController($scope, dataTypeResource, treeService, navigat
|
||||
treeService.removeNode($scope.currentNode);
|
||||
navigationService.hideMenu();
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
$scope.performContainerDelete = function () {
|
||||
|
||||
@@ -20,7 +20,8 @@ function DocumentTypesDeleteController($scope, dataTypeResource, contentTypeReso
|
||||
|
||||
// TODO: Need to sync tree, etc...
|
||||
treeService.removeNode($scope.currentNode);
|
||||
navigationService.hideMenu();
|
||||
navigationService.hideMenu();
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
@@ -38,6 +39,7 @@ function DocumentTypesDeleteController($scope, dataTypeResource, contentTypeReso
|
||||
// TODO: Need to sync tree, etc...
|
||||
treeService.removeNode($scope.currentNode);
|
||||
navigationService.hideMenu();
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<umb-editor-sub-header>
|
||||
|
||||
<umb-editor-sub-header-content-left>
|
||||
<umb-button button-style="success"
|
||||
<umb-button button-style="action"
|
||||
type="button"
|
||||
action="vm.addLanguage()"
|
||||
label-key="languages_addLanguage">
|
||||
|
||||
@@ -129,8 +129,8 @@
|
||||
<!-- Log Details (Exception & Properties) -->
|
||||
<tr ng-repeat-end ng-if="log.open">
|
||||
<td colspan="4">
|
||||
<div ng-if="log.Exception" style="border-left:4px solid #fe6561; padding:0 10px 10px 10px; box-shadow:rgba(0,0,0,0.07) 2px 2px 10px">
|
||||
<h3 style="color:#fe6561;">Exception</h3>
|
||||
<div ng-if="log.Exception" style="border-left:4px solid #D42054; padding:0 10px 10px 10px; box-shadow:rgba(0,0,0,0.07) 2px 2px 10px">
|
||||
<h3 class="text-error">Exception</h3>
|
||||
<p style="white-space: pre-wrap;">{{ log.Exception }}</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* @description
|
||||
* The controller for deleting macro items
|
||||
*/
|
||||
function MacrosDeleteController($scope, $location, macroResource, navigationService, treeService) {
|
||||
function MacrosDeleteController($scope, macroResource, navigationService, treeService) {
|
||||
var vm = this;
|
||||
|
||||
vm.name = $scope.currentNode.name;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* @description
|
||||
* The controller for the media type delete dialog
|
||||
*/
|
||||
function MediaTypesDeleteController($scope, dataTypeResource, mediaTypeResource, treeService, navigationService) {
|
||||
function MediaTypesDeleteController($scope, mediaTypeResource, treeService, navigationService) {
|
||||
|
||||
$scope.performDelete = function() {
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ function MemberTypesDeleteController($scope, memberTypeResource, treeService, na
|
||||
// TODO: Need to sync tree, etc...
|
||||
treeService.removeNode($scope.currentNode);
|
||||
navigationService.hideMenu();
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
<div class="umb-info-local-item">
|
||||
<strong><localize key="packager_packageReadme">Read me</localize></strong>
|
||||
<br>
|
||||
<small> {{ vm.package.readme }} </small>
|
||||
<small ng-bind-html="vm.package.readme"></small>
|
||||
</div>
|
||||
|
||||
<div class="umb-info-local-item mt4 flex items-center flex-column" ng-if="vm.installState.status == ''">
|
||||
|
||||
@@ -21,6 +21,7 @@ function PartialViewMacrosDeleteController($scope, codefileResource, treeService
|
||||
// TODO: Need to sync tree, etc...
|
||||
treeService.removeNode($scope.currentNode);
|
||||
navigationService.hideMenu();
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ function PartialViewsDeleteController($scope, codefileResource, treeService, nav
|
||||
// TODO: Need to sync tree, etc...
|
||||
treeService.removeNode($scope.currentNode);
|
||||
navigationService.hideMenu();
|
||||
|
||||
}, function (err) {
|
||||
$scope.currentNode.loading = false;
|
||||
$scope.error = err;
|
||||
|
||||
+15
-14
@@ -37,18 +37,22 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.CheckboxListContro
|
||||
//check if it's already in sync
|
||||
|
||||
//get the checked vals from the view model
|
||||
var selectedVals = _.map(_.filter($scope.selectedItems,
|
||||
var selectedVals = _.map(
|
||||
_.filter($scope.selectedItems,
|
||||
function(f) {
|
||||
return f.checked;
|
||||
}),
|
||||
}
|
||||
),
|
||||
function(m) {
|
||||
return m.value;
|
||||
});
|
||||
}
|
||||
);
|
||||
//get all of the same values between the arrays
|
||||
var same = _.intersection($scope.model.value, selectedVals);
|
||||
//if the lengths are the same as the value, then we are in sync, just exit
|
||||
if (same.length == $scope.model.value.length === selectedVals.length) {
|
||||
return;
|
||||
|
||||
if (same.length === $scope.model.value.length === selectedVals.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.selectedItems = [];
|
||||
@@ -63,19 +67,16 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.CheckboxListContro
|
||||
}
|
||||
}
|
||||
|
||||
function changed(item) {
|
||||
var index = _.findIndex($scope.model.value,
|
||||
function (v) {
|
||||
return v === item.val;
|
||||
});
|
||||
function changed(model, value) {
|
||||
|
||||
if (item.checked) {
|
||||
var index = $scope.model.value.indexOf(value);
|
||||
|
||||
if (model) {
|
||||
//if it doesn't exist in the model, then add it
|
||||
if (index < 0) {
|
||||
$scope.model.value.push(item.val);
|
||||
$scope.model.value.push(value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
//if it exists in the model, then remove it
|
||||
if (index >= 0) {
|
||||
$scope.model.value.splice(index, 1);
|
||||
|
||||
@@ -1,16 +1,7 @@
|
||||
<div class="umb-property-editor umb-checkboxlist" ng-controller="Umbraco.PropertyEditors.CheckboxListController">
|
||||
|
||||
<ul class="unstyled">
|
||||
<li ng-repeat="item in selectedItems track by item.key">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="checkboxlist"
|
||||
value="{{item.value}}"
|
||||
ng-model="item.checked"
|
||||
ng-change="changed(item)"
|
||||
ng-required="model.validation.mandatory && !model.value.length" />
|
||||
{{item.val}}
|
||||
</label>
|
||||
<umb-checkbox name="{{model.alias}}" value="{{item.val}}" model="item.checked" text="{{item.val}}" on-change="changed(model, value)" required="model.validation.mandatory && !model.value.length"></umb-checkbox>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
|
||||
+2
-2
@@ -9,7 +9,7 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function ListViewGridLayoutController($scope, $routeParams, mediaHelper, mediaResource, $location, listViewHelper, mediaTypeHelper) {
|
||||
function ListViewGridLayoutController($scope, mediaHelper, $location, listViewHelper, mediaTypeHelper) {
|
||||
|
||||
var vm = this;
|
||||
var umbracoSettings = Umbraco.Sys.ServerVariables.umbracoSettings;
|
||||
@@ -115,7 +115,7 @@
|
||||
function selectFolder(folder, $event, $index) {
|
||||
listViewHelper.selectHandler(folder, $index, $scope.folders, $scope.selection, $event);
|
||||
}
|
||||
|
||||
|
||||
function goToItem(item, $event, $index) {
|
||||
$location.path($scope.entityType + '/' + $scope.entityType + '/edit/' + item.id);
|
||||
}
|
||||
|
||||
+2
-2
@@ -19,7 +19,7 @@
|
||||
vm.activeDrag = false;
|
||||
vm.isRecycleBin = $scope.contentId === '-21' || $scope.contentId === '-20';
|
||||
vm.acceptedMediatypes = [];
|
||||
|
||||
|
||||
vm.selectItem = selectItem;
|
||||
vm.clickItem = clickItem;
|
||||
vm.selectAll = selectAll;
|
||||
@@ -55,7 +55,7 @@
|
||||
function clickItem(item) {
|
||||
// if item.id is 2147483647 (int.MaxValue) use item.key
|
||||
$location.path($scope.entityType + '/' + $scope.entityType + '/edit/' + (item.id === 2147483647 ? item.key : item.id));
|
||||
}
|
||||
}
|
||||
|
||||
function isSortDirection(col, direction) {
|
||||
return listViewHelper.setSortingDirection(col, direction, $scope.options);
|
||||
|
||||
@@ -13,13 +13,13 @@
|
||||
<umb-editor-sub-header-section ng-if="(listViewAllowedTypes && listViewAllowedTypes.length > 0 && (selection.length == 0)) && (currentNodePermissions == null || currentNodePermissions.canCreate)">
|
||||
|
||||
<div class="btn-group" ng-show="createAllowedButtonSingle">
|
||||
<a class="btn btn-white" ng-click="createBlank(entityType,listViewAllowedTypes[0].alias)">
|
||||
<a class="btn btn-action" ng-click="createBlank(entityType,listViewAllowedTypes[0].alias)">
|
||||
<localize key="actions_create">Create</localize> {{listViewAllowedTypes[0].name}}
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="btn-group" ng-show="createAllowedButtonSingleWithBlueprints">
|
||||
<a class="btn btn-white dropdown-toggle" data-toggle="dropdown" ng-href="">
|
||||
<a class="btn btn-action dropdown-toggle" data-toggle="dropdown" ng-href="">
|
||||
<span ng-click="createBlank(entityType,listViewAllowedTypes[0].alias)">
|
||||
<localize key="actions_create">Create</localize> {{listViewAllowedTypes[0].name}}
|
||||
</span>
|
||||
@@ -37,7 +37,7 @@
|
||||
</div>
|
||||
|
||||
<div class="btn-group" ng-show="createAllowedButtonMultiWithBlueprints">
|
||||
<a class="btn btn-white dropdown-toggle" data-toggle="dropdown" ng-href="" ng-click="page.createDropdownOpen = !page.createDropdownOpen">
|
||||
<a class="btn btn-action dropdown-toggle" data-toggle="dropdown" ng-href="" ng-click="page.createDropdownOpen = !page.createDropdownOpen">
|
||||
<localize key="actions_create">Create</localize>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
|
||||
+1
-3
@@ -19,9 +19,7 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.RadioButtonsContro
|
||||
|
||||
$scope.configItems = configItems;
|
||||
}
|
||||
|
||||
$scope.htmlId = "radiobuttons-" + $scope.model.alias + String.CreateGuid();
|
||||
|
||||
|
||||
}
|
||||
|
||||
init();
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
<div class="umb-property-editor umb-radiobuttons" ng-controller="Umbraco.PropertyEditors.RadioButtonsController">
|
||||
<ul class="unstyled">
|
||||
<li ng-repeat="item in configItems track by item.id">
|
||||
<label class="radio">
|
||||
<input type="radio" name="{{htmlId}}"
|
||||
value="{{item.value}}"
|
||||
ng-model="model.value" />
|
||||
{{item.value}}
|
||||
</label>
|
||||
<umb-radiobutton name="{{model.alias}}" value="{{item.value}}" model="model.value" text="{{item.value}}" required="model.validation.mandatory && model.value == ''"></umb-radiobutton>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -17,12 +17,13 @@ angular.module("umbraco")
|
||||
if (!editorConfig || angular.isString(editorConfig)) {
|
||||
editorConfig = tinyMceService.defaultPrevalues();
|
||||
}
|
||||
|
||||
var promises = [];
|
||||
if (!editorConfig.maxImageSize && editorConfig.maxImageSize != 0) {
|
||||
//make sure there's a max image size
|
||||
if (!editorConfig.maxImageSize && editorConfig.maxImageSize !== 0) {
|
||||
editorConfig.maxImageSize = tinyMceService.defaultPrevalues().maxImageSize;
|
||||
}
|
||||
|
||||
var promises = [];
|
||||
|
||||
//queue file loading
|
||||
if (typeof tinymce === "undefined") { // Don't reload tinymce if already loaded
|
||||
promises.push(assetsService.loadJs("lib/tinymce/tinymce.min.js", $scope));
|
||||
@@ -43,7 +44,7 @@ angular.module("umbraco")
|
||||
|
||||
var standardConfig = result[promises.length - 1];
|
||||
|
||||
//create a baseline Config to exten upon
|
||||
//create a baseline Config to extend upon
|
||||
var baseLineConfigObj = {
|
||||
maxImageSize: editorConfig.maxImageSize
|
||||
};
|
||||
|
||||
@@ -21,6 +21,7 @@ function ScriptsDeleteController($scope, codefileResource, treeService, navigati
|
||||
// TODO: Need to sync tree, etc...
|
||||
treeService.removeNode($scope.currentNode);
|
||||
navigationService.hideMenu();
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* @description
|
||||
* The controller for the template delete dialog
|
||||
*/
|
||||
function TemplatesDeleteController($scope, templateResource , treeService, navigationService) {
|
||||
function TemplatesDeleteController($scope, templateResource, treeService, navigationService) {
|
||||
|
||||
$scope.performDelete = function() {
|
||||
|
||||
@@ -25,6 +25,7 @@ function TemplatesDeleteController($scope, templateResource , treeService, navig
|
||||
// TODO: Need to sync tree, etc...
|
||||
treeService.removeNode($scope.currentNode);
|
||||
navigationService.hideMenu();
|
||||
|
||||
}, function (err) {
|
||||
$scope.currentNode.loading = false;
|
||||
$scope.error = err;
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
(function () {
|
||||
"use strict";
|
||||
|
||||
function UsersController($scope, $timeout, $location, $routeParams, usersResource, userGroupsResource, userService, localizationService, contentEditingHelper, usersHelper, formHelper, notificationsService, dateHelper, editorService) {
|
||||
function UsersController($scope, $timeout, $location, $routeParams, usersResource,
|
||||
userGroupsResource, userService, localizationService, usersHelper, formHelper,
|
||||
dateHelper, editorService, $cookies) {
|
||||
|
||||
var vm = this;
|
||||
var localizeSaving = localizationService.localize("general_saving");
|
||||
@@ -63,10 +65,18 @@
|
||||
"selected": true
|
||||
}
|
||||
];
|
||||
|
||||
// Set card layout to active by default
|
||||
vm.activeLayout = vm.layouts[0];
|
||||
|
||||
|
||||
var cookieUmbUserLayout = $cookies.get("umbUserLayout");
|
||||
|
||||
if (cookieUmbUserLayout) {
|
||||
vm.activeLayout = vm.layouts.find(x => x.path === cookieUmbUserLayout);
|
||||
}
|
||||
if (vm.activeLayout === undefined) {
|
||||
// Set card layout to active by default
|
||||
vm.activeLayout = vm.layouts[0];
|
||||
}
|
||||
|
||||
|
||||
// Don't show the invite button if no email is configured
|
||||
if (Umbraco.Sys.ServerVariables.umbracoSettings.showUserInvite) {
|
||||
vm.defaultButton = {
|
||||
@@ -96,9 +106,11 @@
|
||||
vm.toggleFilter = toggleFilter;
|
||||
vm.setUsersViewState = setUsersViewState;
|
||||
vm.selectLayout = selectLayout;
|
||||
vm.isSelectable = isSelectable;
|
||||
vm.selectUser = selectUser;
|
||||
vm.clearSelection = clearSelection;
|
||||
vm.clickUser = clickUser;
|
||||
vm.getEditPath = getEditPath;
|
||||
vm.disableUsers = disableUsers;
|
||||
vm.enableUsers = enableUsers;
|
||||
vm.unlockUsers = unlockUsers;
|
||||
@@ -199,11 +211,19 @@
|
||||
});
|
||||
selectedLayout.active = true;
|
||||
vm.activeLayout = selectedLayout;
|
||||
|
||||
var expireDate = new Date();
|
||||
expireDate.setDate(expireDate.getDate() + 365);
|
||||
$cookies.put("umbUserLayout", selectedLayout.path, {path: "/", expires: expireDate});
|
||||
}
|
||||
|
||||
|
||||
function isSelectable(user) {
|
||||
return !user.isCurrentUser;
|
||||
}
|
||||
|
||||
function selectUser(user) {
|
||||
|
||||
if (user.isCurrentUser) {
|
||||
if (!isSelectable(user)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -226,9 +246,26 @@
|
||||
});
|
||||
vm.selection = [];
|
||||
}
|
||||
|
||||
function clickUser(user, $event) {
|
||||
|
||||
$event.stopPropagation();
|
||||
|
||||
if ($event) {
|
||||
// targeting a new tab/window?
|
||||
if ($event.ctrlKey ||
|
||||
$event.shiftKey ||
|
||||
$event.metaKey || // apple
|
||||
($event.button && $event.button === 1) // middle click, >IE9 + everyone else
|
||||
) {
|
||||
// yes, let the link open itself
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
goToUser(user);
|
||||
$event.preventDefault();
|
||||
|
||||
function clickUser(user) {
|
||||
goToUser(user.id);
|
||||
}
|
||||
|
||||
function disableUsers() {
|
||||
@@ -551,8 +588,16 @@
|
||||
vm.page.copyPasswordButtonState = "init";
|
||||
}
|
||||
|
||||
function goToUser(userId) {
|
||||
$location.path('users/users/user/' + userId).search("create", null).search("invite", null);
|
||||
function goToUser(user) {
|
||||
$location.path(pathToUser(user)).search("create", null).search("invite", null);
|
||||
}
|
||||
|
||||
function getEditPath(user) {
|
||||
return pathToUser(user) + "?mculture=" + $location.search().mculture;
|
||||
}
|
||||
|
||||
function pathToUser(user) {
|
||||
return "/users/users/user/" + user.id;
|
||||
}
|
||||
|
||||
// helpers
|
||||
@@ -569,7 +614,7 @@
|
||||
vm.usersOptions.pageSize = data.pageSize;
|
||||
vm.usersOptions.totalItems = data.totalItems;
|
||||
vm.usersOptions.totalPages = data.totalPages;
|
||||
|
||||
|
||||
formatDates(vm.users);
|
||||
setUserDisplayState(vm.users);
|
||||
vm.userStatesFilter = usersHelper.getUserStatesFilter(data.userStates);
|
||||
|
||||
@@ -191,18 +191,18 @@
|
||||
|
||||
<!-- Layout: Cards -->
|
||||
<div class="umb-user-cards" ng-if="vm.activeLayout.path === '1' && vm.loading === false">
|
||||
<div class="umb-user-card" ng-class="{'-selected': user.selected}" ng-repeat="user in vm.users track by user.key" ng-click="vm.selectUser(user)">
|
||||
<div class="umb-user-card" ng-class="{'-selected': user.selected, '-selectable': vm.isSelectable(user)}" ng-repeat="user in vm.users track by user.key" ng-click="vm.selectUser(user, $event)">
|
||||
<div class="umb-user-card__content">
|
||||
<div class="umb-user-card__goToUser" ng-click="vm.clickUser(user)">
|
||||
<umb-badge class="umb-user-card__badge" size="xs" ng-if="user.userDisplayState.key !== 'Active'" color="{{user.userDisplayState.color}}">
|
||||
{{ user.userDisplayState.name }}
|
||||
</umb-badge>
|
||||
<umb-badge class="umb-user-card__badge" size="xs" ng-if="user.userDisplayState.key !== 'Active'" color="{{user.userDisplayState.color}}">
|
||||
{{ user.userDisplayState.name }}
|
||||
</umb-badge>
|
||||
<a class="umb-user-card__goToUser" ng-click="vm.clickUser(user, $event)" ng-href="#{{::vm.getEditPath(user)}}">
|
||||
<div class="umb-user-card__avatar">
|
||||
<umb-avatar size="l" color="secondary" name="{{user.name}}" img-src="{{user.avatars[2]}}" img-srcset="{{user.avatars[3]}} 2x, {{user.avatars[4]}} 3x">
|
||||
</umb-avatar>
|
||||
</div>
|
||||
<div class="umb-user-card__name">{{user.name}}</div>
|
||||
</div>
|
||||
</a>
|
||||
<div class="umb-user-card__group">
|
||||
<span ng-repeat="userGroup in user.userGroups">{{ userGroup.name }}<span ng-if="!$last">, </span></span>
|
||||
</div>
|
||||
@@ -226,60 +226,65 @@
|
||||
<!-- Layout: Table -->
|
||||
<div ng-if="vm.activeLayout.path === '2'">
|
||||
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="padding-left: 10px; width: 10px;">
|
||||
<div class="umb-table umb-user-table" ng-class="{'-has-selection': vm.selection.length > 0}">
|
||||
<div class="umb-table-head">
|
||||
<div class="umb-table-row">
|
||||
<div class="umb-table-cell" style="padding-left: 10px; width: 10px;">
|
||||
<a href="" style="text-decoration: none;" ng-click="vm.selectAll()">
|
||||
<umb-checkmark checked="vm.areAllSelected()" size="xs"></umb-checkmark>
|
||||
</a>
|
||||
</th>
|
||||
<th style="width: 70px;"></th>
|
||||
<th><localize key="general_name">Name</localize></th>
|
||||
<th><localize key="user_usergroup">User group</localize></th>
|
||||
<th><localize key="user_lastLogin">Last login</localize></th>
|
||||
<th><localize key="general_status">Status</localize></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="user in vm.users track by user.key"
|
||||
</div>
|
||||
<div class="umb-table-cell umb-user-table-col-avatar" style="width: 70px;"></div>
|
||||
<div class="umb-table-cell umb-table__name"><localize key="general_name">Name</localize></div>
|
||||
<div class="umb-table-cell"><localize key="user_usergroup">User group</localize></div>
|
||||
<div class="umb-table-cell"><localize key="user_lastLogin">Last login</localize></div>
|
||||
<div class="umb-table-cell"><localize key="general_status">Status</localize></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="umb-table-body">
|
||||
<div ng-repeat="user in vm.users track by user.key"
|
||||
ng-click="vm.selectUser(user, vm.selection, $event)"
|
||||
ng-class="{'--selected': user.selected}"
|
||||
style="cursor: pointer;"
|
||||
ng-mouseenter="user.hover = true"
|
||||
ng-mouseleave="user.hover = false">
|
||||
<td style="padding-left: 10px;">
|
||||
ng-class="{'-selected': user.selected, '-selectable': vm.isSelectable(user)}"
|
||||
class="umb-table-row umb-user-table-row">
|
||||
<div class="umb-table-cell" style="padding-left: 10px;">
|
||||
<div ng-if="!user.isCurrentUser">
|
||||
<umb-checkmark
|
||||
ng-if="vm.selection.length > 0 || user.hover"
|
||||
checked="user.selected"
|
||||
size="xs">
|
||||
</umb-checkmark>
|
||||
</div>
|
||||
</td>
|
||||
<td scope="row" ng-click="vm.clickUser(user)">
|
||||
<umb-avatar
|
||||
size="xs"
|
||||
color="secondary"
|
||||
name="{{user.name}}"
|
||||
img-src="{{user.avatars[0]}}"
|
||||
img-srcset="{{user.avatars[1]}} 2x, {{user.avatars[2]}} 3x">
|
||||
</umb-avatar>
|
||||
</td>
|
||||
<td class="bold" ng-click="vm.clickUser(user)">{{user.name}}</td>
|
||||
<td><span ng-repeat="userGroup in user.userGroups">{{ userGroup.name }}<span ng-if="!$last">, </span></span></td>
|
||||
<td>{{ user.formattedLastLogin }}</td>
|
||||
<td style="text-transform: capitalize;">
|
||||
</div>
|
||||
<div class="umb-table-cell umb-user-table-col-avatar" scope="row">
|
||||
<a ng-click="vm.clickUser(user, $event)" ng-href="#{{::vm.getEditPath(user)}}">
|
||||
<umb-avatar
|
||||
size="xs"
|
||||
color="secondary"
|
||||
name="{{user.name}}"
|
||||
img-src="{{user.avatars[0]}}"
|
||||
img-srcset="{{user.avatars[1]}} 2x, {{user.avatars[2]}} 3x">
|
||||
</umb-avatar>
|
||||
</a>
|
||||
</div>
|
||||
<div class="umb-table-cell umb-table__name">
|
||||
<a ng-click="vm.clickUser(user, $event)" ng-href="#{{::vm.getEditPath(user)}}">
|
||||
<span>
|
||||
{{user.name}}
|
||||
</span>
|
||||
</a>
|
||||
</div>
|
||||
<div class="umb-table-cell"><span ng-repeat="userGroup in user.userGroups">{{ userGroup.name }}<span ng-if="!$last">, </span></span></div>
|
||||
<div class="umb-table-cell">{{ user.formattedLastLogin }}</div>
|
||||
<div class="umb-table-cell" style="text-transform: capitalize;">
|
||||
<umb-badge
|
||||
size="xs"
|
||||
ng-if="user.userDisplayState.key !== 'Active'"
|
||||
color="{{user.userDisplayState.color}}">
|
||||
{{ user.userDisplayState.name }}
|
||||
</umb-badge>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -490,7 +495,7 @@
|
||||
type="button"
|
||||
button-style="action"
|
||||
label-key="user_goToProfile"
|
||||
action="vm.goToUser(vm.newUser.id);"
|
||||
action="vm.goToUser(vm.newUser);"
|
||||
size="m">
|
||||
</umb-button>
|
||||
</div>
|
||||
@@ -540,7 +545,7 @@
|
||||
type="button"
|
||||
button-style="action"
|
||||
label-key="user_goToProfile"
|
||||
action="vm.goToUser(vm.newUser.id);"
|
||||
action="vm.goToUser(vm.newUser);"
|
||||
size="m">
|
||||
</umb-button>
|
||||
</div>
|
||||
|
||||
@@ -340,9 +340,9 @@
|
||||
<WebProjectProperties>
|
||||
<UseIIS>False</UseIIS>
|
||||
<AutoAssignPort>True</AutoAssignPort>
|
||||
<DevelopmentServerPort>8010</DevelopmentServerPort>
|
||||
<DevelopmentServerPort>8100</DevelopmentServerPort>
|
||||
<DevelopmentServerVPath>/</DevelopmentServerVPath>
|
||||
<IISUrl>http://localhost:8010</IISUrl>
|
||||
<IISUrl>http://localhost:8100</IISUrl>
|
||||
<NTLMAuthentication>False</NTLMAuthentication>
|
||||
<UseCustomServer>False</UseCustomServer>
|
||||
<CustomServerUrl>
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 315.89 315.89">
|
||||
<path fill="#ffffff" d="M0,157.74A157.95,157.95,0,1,1,158,315.89,157.95,157.95,0,0,1,0,157.74Zm154.74,54.09a155.41,155.41,0,0,1-36.5-3.29,27.92,27.92,0,0,1-19.94-16q-5.35-12.34-5.21-38.1a243,243,0,0,1,1.69-26.84q1.55-13,3.09-21.46l1.07-5.59a2,2,0,0,0,0-.49,3.2,3.2,0,0,0-2.65-3.17L75.92,93.67h-.44a3.19,3.19,0,0,0-3.11,2.48c-.35,1.31-.56,2.27-1.17,5.38-1.16,6-2.24,11.85-3.43,20.38a264.17,264.17,0,0,0-2.3,27.94,145.24,145.24,0,0,0,0,19.57q.72,25.94,8.9,41.42t27.72,22.3q19.53,6.81,54.43,6.66h2.91q34.94.15,54.41-6.66t27.71-22.3q8.17-15.53,8.91-41.42a145.24,145.24,0,0,0,0-19.57,266.84,266.84,0,0,0-2.3-27.94c-1.2-8.44-2.27-14.26-3.44-20.38-.61-3.11-.81-4.07-1.16-5.38a3.21,3.21,0,0,0-3.12-2.48h-.52l-20.38,3.18a3.2,3.2,0,0,0-2.68,3.17,4,4,0,0,0,0,.49l1.08,5.59q1.55,8.48,3.12,21.46a245.68,245.68,0,0,1,1.65,26.84q.27,25.69-5.21,38.07a27.9,27.9,0,0,1-19.76,16.07,155.19,155.19,0,0,1-36.48,3.29Z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 976 B |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user