Merge branch 'temp8' into temp8-sk-installer
This commit is contained in:
@@ -77,7 +77,7 @@
|
||||
/// alias for the macro tree.
|
||||
/// </summary>
|
||||
public const string Macros = "macros";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// alias for the datatype tree.
|
||||
/// </summary>
|
||||
@@ -92,7 +92,7 @@
|
||||
/// alias for the dictionary tree.
|
||||
/// </summary>
|
||||
public const string Dictionary = "dictionary";
|
||||
|
||||
|
||||
public const string Stylesheets = "stylesheets";
|
||||
|
||||
/// <summary>
|
||||
@@ -121,7 +121,7 @@
|
||||
public const string Templates = "templates";
|
||||
|
||||
public const string RelationTypes = "relationTypes";
|
||||
|
||||
|
||||
public const string Languages = "languages";
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -50,8 +50,6 @@ namespace Umbraco.Core.Migrations.Install
|
||||
typeof (MemberTypeDto),
|
||||
typeof (MemberDto),
|
||||
typeof (Member2MemberGroupDto),
|
||||
typeof (ContentXmlDto),
|
||||
typeof (PreviewXmlDto),
|
||||
typeof (PropertyTypeGroupDto),
|
||||
typeof (PropertyTypeDto),
|
||||
typeof (PropertyDataDto),
|
||||
@@ -139,13 +137,18 @@ namespace Umbraco.Core.Migrations.Install
|
||||
/// Validates the schema of the current database.
|
||||
/// </summary>
|
||||
internal DatabaseSchemaResult ValidateSchema()
|
||||
{
|
||||
return ValidateSchema(OrderedTables);
|
||||
}
|
||||
|
||||
internal DatabaseSchemaResult ValidateSchema(IEnumerable<Type> orderedTables)
|
||||
{
|
||||
var result = new DatabaseSchemaResult(SqlSyntax);
|
||||
|
||||
result.IndexDefinitions.AddRange(SqlSyntax.GetDefinedIndexes(_database)
|
||||
.Select(x => new DbIndexDefinition(x)));
|
||||
|
||||
result.TableDefinitions.AddRange(OrderedTables
|
||||
result.TableDefinitions.AddRange(orderedTables
|
||||
.Select(x => DefinitionFactory.GetTableDefinition(x, SqlSyntax)));
|
||||
|
||||
ValidateDbTables(result);
|
||||
|
||||
@@ -96,6 +96,12 @@ namespace Umbraco.Core.Migrations
|
||||
return tables.Any(x => x.InvariantEquals(tableName));
|
||||
}
|
||||
|
||||
protected bool IndexExists(string indexName)
|
||||
{
|
||||
var indexes = SqlSyntax.GetDefinedIndexes(Context.Database);
|
||||
return indexes.Any(x => x.Item2.InvariantEquals(indexName));
|
||||
}
|
||||
|
||||
protected bool ColumnExists(string tableName, string columnName)
|
||||
{
|
||||
var columns = SqlSyntax.GetColumnsInSchema(Context.Database).Distinct().ToArray();
|
||||
|
||||
@@ -127,7 +127,13 @@ namespace Umbraco.Core.Migrations.Upgrade
|
||||
To<ConvertRelatedLinksToMultiUrlPicker>("{ED28B66A-E248-4D94-8CDB-9BDF574023F0}");
|
||||
To<UpdatePickerIntegerValuesToUdi>("{38C809D5-6C34-426B-9BEA-EFD39162595C}");
|
||||
To<RenameUmbracoDomainsTable>("{6017F044-8E70-4E10-B2A3-336949692ADD}");
|
||||
|
||||
To<AddUserLoginDtoDateIndex>("{98339BEF-E4B2-48A8-B9D1-D173DC842BBE}");
|
||||
|
||||
Merge()
|
||||
.To<DropXmlTables>("{CDBEDEE4-9496-4903-9CF2-4104E00FF960}")
|
||||
.With()
|
||||
.To<RadioAndCheckboxAndDropdownPropertyEditorsMigration>("{940FD19A-00A8-4D5C-B8FF-939143585726}")
|
||||
.As("{0576E786-5C30-4000-B969-302B61E90CA3}");
|
||||
|
||||
//FINAL
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
|
||||
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
|
||||
{
|
||||
public class AddUserLoginDtoDateIndex : MigrationBase
|
||||
{
|
||||
public AddUserLoginDtoDateIndex(IMigrationContext context)
|
||||
: base(context)
|
||||
{ }
|
||||
|
||||
public override void Migrate()
|
||||
{
|
||||
if (!IndexExists("IX_umbracoUserLogin_lastValidatedUtc"))
|
||||
Create.Index("IX_umbracoUserLogin_lastValidatedUtc")
|
||||
.OnTable(UserLoginDto.TableName)
|
||||
.OnColumn("lastValidatedUtc")
|
||||
.Ascending()
|
||||
.WithOptions().NonClustered()
|
||||
.Do();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
|
||||
{
|
||||
|
||||
public class DropTaskTables : MigrationBase
|
||||
{
|
||||
public DropTaskTables(IMigrationContext context)
|
||||
|
||||
17
src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DropXmlTables.cs
Normal file
17
src/Umbraco.Core/Migrations/Upgrade/V_8_0_0/DropXmlTables.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
|
||||
{
|
||||
public class DropXmlTables : MigrationBase
|
||||
{
|
||||
public DropXmlTables(IMigrationContext context)
|
||||
: base(context)
|
||||
{ }
|
||||
|
||||
public override void Migrate()
|
||||
{
|
||||
if (TableExists("cmsContentXml"))
|
||||
Delete.Table("cmsContentXml").Do();
|
||||
if (TableExists("cmsPreviewXml"))
|
||||
Delete.Table("cmsPreviewXml").Do();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.PropertyEditors;
|
||||
|
||||
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0
|
||||
{
|
||||
public class RadioAndCheckboxAndDropdownPropertyEditorsMigration : MigrationBase
|
||||
{
|
||||
public RadioAndCheckboxAndDropdownPropertyEditorsMigration(IMigrationContext context)
|
||||
: base(context)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Migrate()
|
||||
{
|
||||
var refreshCache = false;
|
||||
|
||||
refreshCache |= Migrate(Constants.PropertyEditors.Aliases.RadioButtonList, (dto, configuration) => UpdateRadioOrCheckboxPropertyDataDto(dto, configuration, true));
|
||||
refreshCache |= Migrate(Constants.PropertyEditors.Aliases.CheckBoxList, (dto, configuration) => UpdateRadioOrCheckboxPropertyDataDto(dto, configuration, false));
|
||||
refreshCache |= Migrate(Constants.PropertyEditors.Aliases.DropDownListFlexible, UpdateDropDownPropertyDataDto);
|
||||
|
||||
if (refreshCache)
|
||||
{
|
||||
//FIXME: trigger cache rebuild. Currently the data in the database tables is wrong.
|
||||
}
|
||||
}
|
||||
|
||||
private bool Migrate(string editorAlias, Func<PropertyDataDto, ValueListConfiguration, bool> updateRadioPropertyDataFunc)
|
||||
{
|
||||
var refreshCache = false;
|
||||
var dataTypes = GetDataTypes(editorAlias);
|
||||
|
||||
foreach (var dataType in dataTypes)
|
||||
{
|
||||
ValueListConfiguration config;
|
||||
|
||||
if (dataType.Configuration.IsNullOrWhiteSpace())
|
||||
continue;
|
||||
|
||||
// parse configuration, and update everything accordingly
|
||||
try
|
||||
{
|
||||
config = (ValueListConfiguration) new ValueListConfigurationEditor().FromDatabase(
|
||||
dataType.Configuration);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger.Error<DropDownPropertyEditorsMigration>(
|
||||
ex,
|
||||
"Invalid radio button configuration detected: \"{Configuration}\", cannot convert editor, values will be cleared",
|
||||
dataType.Configuration);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// get property data dtos
|
||||
var propertyDataDtos = Database.Fetch<PropertyDataDto>(Sql()
|
||||
.Select<PropertyDataDto>()
|
||||
.From<PropertyDataDto>()
|
||||
.InnerJoin<PropertyTypeDto>()
|
||||
.On<PropertyTypeDto, PropertyDataDto>((pt, pd) => pt.Id == pd.PropertyTypeId)
|
||||
.InnerJoin<DataTypeDto>()
|
||||
.On<DataTypeDto, PropertyTypeDto>((dt, pt) => dt.NodeId == pt.DataTypeId)
|
||||
.Where<PropertyTypeDto>(x => x.DataTypeId == dataType.NodeId));
|
||||
|
||||
// update dtos
|
||||
var updatedDtos = propertyDataDtos.Where(x => updateRadioPropertyDataFunc(x, config));
|
||||
|
||||
// persist changes
|
||||
foreach (var propertyDataDto in updatedDtos) Database.Update(propertyDataDto);
|
||||
|
||||
UpdateDataType(dataType);
|
||||
refreshCache = true;
|
||||
}
|
||||
|
||||
return refreshCache;
|
||||
}
|
||||
|
||||
private List<DataTypeDto> GetDataTypes(string editorAlias)
|
||||
{
|
||||
//need to convert the old drop down data types to use the new one
|
||||
var dataTypes = Database.Fetch<DataTypeDto>(Sql()
|
||||
.Select<DataTypeDto>()
|
||||
.From<DataTypeDto>()
|
||||
.Where<DataTypeDto>(x => x.EditorAlias == editorAlias));
|
||||
return dataTypes;
|
||||
}
|
||||
|
||||
private void UpdateDataType(DataTypeDto dataType)
|
||||
{
|
||||
dataType.DbType = ValueStorageType.Nvarchar.ToString();
|
||||
Database.Update(dataType);
|
||||
}
|
||||
|
||||
private bool UpdateRadioOrCheckboxPropertyDataDto(PropertyDataDto propData, ValueListConfiguration config, bool singleValue)
|
||||
{
|
||||
//Get the INT ids stored for this property/drop down
|
||||
int[] ids = null;
|
||||
if (!propData.VarcharValue.IsNullOrWhiteSpace())
|
||||
{
|
||||
ids = ConvertStringValues(propData.VarcharValue);
|
||||
}
|
||||
else if (!propData.TextValue.IsNullOrWhiteSpace())
|
||||
{
|
||||
ids = ConvertStringValues(propData.TextValue);
|
||||
}
|
||||
else if (propData.IntegerValue.HasValue)
|
||||
{
|
||||
ids = new[] {propData.IntegerValue.Value};
|
||||
}
|
||||
|
||||
//if there are INT ids, convert them to values based on the configuration
|
||||
if (ids == null || ids.Length <= 0) return false;
|
||||
|
||||
//map the ids to values
|
||||
var values = new List<string>();
|
||||
var canConvert = true;
|
||||
|
||||
foreach (var id in ids)
|
||||
{
|
||||
var val = config.Items.FirstOrDefault(x => x.Id == id);
|
||||
if (val != null)
|
||||
values.Add(val.Value);
|
||||
else
|
||||
{
|
||||
Logger.Warn<DropDownPropertyEditorsMigration>(
|
||||
"Could not find associated data type configuration for stored Id {DataTypeId}", id);
|
||||
canConvert = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!canConvert) return false;
|
||||
|
||||
//The radio button only supports selecting a single value, so if there are multiple for some insane reason we can only use the first
|
||||
propData.VarcharValue = singleValue ? values[0] : JsonConvert.SerializeObject(values);
|
||||
propData.TextValue = null;
|
||||
propData.IntegerValue = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool UpdateDropDownPropertyDataDto(PropertyDataDto propData, ValueListConfiguration config)
|
||||
{
|
||||
//Get the INT ids stored for this property/drop down
|
||||
var values = propData.VarcharValue.Split(new []{","}, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
//if there are INT ids, convert them to values based on the configuration
|
||||
if (values == null || values.Length <= 0) return false;
|
||||
|
||||
//The radio button only supports selecting a single value, so if there are multiple for some insane reason we can only use the first
|
||||
propData.VarcharValue = JsonConvert.SerializeObject(values);
|
||||
propData.TextValue = null;
|
||||
propData.IntegerValue = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
private int[] ConvertStringValues(string val)
|
||||
{
|
||||
var splitVals = val.Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries);
|
||||
|
||||
var intVals = splitVals
|
||||
.Select(x => int.TryParse(x, out var i) ? i : int.MinValue)
|
||||
.Where(x => x != int.MinValue)
|
||||
.ToArray();
|
||||
|
||||
//only return if the number of values are the same (i.e. All INTs)
|
||||
if (splitVals.Length == intVals.Length)
|
||||
return intVals;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private class ValueListConfigurationEditor : ConfigurationEditor<ValueListConfiguration>
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,8 +102,8 @@ namespace Umbraco.Core.Packaging
|
||||
{
|
||||
// TODO: I don't think this ordering is necessary
|
||||
var orderedTypes = (from contentType in contentTypes
|
||||
orderby contentType.ParentId descending, contentType.Id descending
|
||||
select contentType).ToList();
|
||||
orderby contentType.ParentId descending, contentType.Id descending
|
||||
select contentType).ToList();
|
||||
removedContentTypes.AddRange(orderedTypes);
|
||||
contentTypeService.Delete(orderedTypes, userId);
|
||||
}
|
||||
@@ -157,7 +157,7 @@ namespace Umbraco.Core.Packaging
|
||||
DictionaryItemsUninstalled = removedDictionaryItems,
|
||||
DataTypesUninstalled = removedDataTypes,
|
||||
LanguagesUninstalled = removedLanguages,
|
||||
|
||||
|
||||
};
|
||||
|
||||
return summary;
|
||||
@@ -188,8 +188,8 @@ namespace Umbraco.Core.Packaging
|
||||
var element = packageDocument.XmlData;
|
||||
|
||||
var roots = from doc in element.Elements()
|
||||
where (string)doc.Attribute("isDoc") == ""
|
||||
select doc;
|
||||
where (string)doc.Attribute("isDoc") == ""
|
||||
select doc;
|
||||
|
||||
var contents = ParseDocumentRootXml(roots, parentId, importedDocumentTypes).ToList();
|
||||
if (contents.Any())
|
||||
@@ -289,13 +289,26 @@ namespace Umbraco.Core.Packaging
|
||||
var nodeName = element.Attribute("nodeName").Value;
|
||||
var path = element.Attribute("path").Value;
|
||||
var templateId = element.AttributeValue<int?>("template");
|
||||
|
||||
|
||||
var properties = from property in element.Elements()
|
||||
where property.Attribute("isDoc") == null
|
||||
select property;
|
||||
|
||||
//TODO: This will almost never work, we can't reference a template by an INT Id within a package manifest, we need to change the
|
||||
// packager to package templates by UDI and resolve by the same, in 98% of cases, this isn't going to work, or it will resolve the wrong template.
|
||||
var template = templateId.HasValue ? _fileService.GetTemplate(templateId.Value) : null;
|
||||
|
||||
//now double check this is correct since its an INT it could very well be pointing to an invalid template :/
|
||||
if (template != null)
|
||||
{
|
||||
if (!contentType.IsAllowedTemplate(template.Alias))
|
||||
{
|
||||
//well this is awkward, we'll set the template to null and it will be wired up to the default template
|
||||
// when it's persisted in the document repository
|
||||
template = null;
|
||||
}
|
||||
}
|
||||
|
||||
IContent content = parent == null
|
||||
? new Content(nodeName, parentId, contentType)
|
||||
{
|
||||
@@ -312,6 +325,12 @@ namespace Umbraco.Core.Packaging
|
||||
Key = key
|
||||
};
|
||||
|
||||
//Here we make sure that we take composition properties in account as well
|
||||
//otherwise we would skip them and end up losing content
|
||||
var propTypes = contentType.CompositionPropertyTypes.Any()
|
||||
? contentType.CompositionPropertyTypes.ToDictionary(x => x.Alias, x => x)
|
||||
: contentType.PropertyTypes.ToDictionary(x => x.Alias, x => x);
|
||||
|
||||
foreach (var property in properties)
|
||||
{
|
||||
string propertyTypeAlias = property.Name.LocalName;
|
||||
@@ -319,10 +338,11 @@ namespace Umbraco.Core.Packaging
|
||||
{
|
||||
var propertyValue = property.Value;
|
||||
|
||||
var propertyType = contentType.PropertyTypes.FirstOrDefault(pt => pt.Alias == propertyTypeAlias);
|
||||
|
||||
//set property value
|
||||
content.SetValue(propertyTypeAlias, propertyValue);
|
||||
if (propTypes.TryGetValue(propertyTypeAlias, out var propertyType))
|
||||
{
|
||||
//set property value
|
||||
content.SetValue(propertyTypeAlias, propertyValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,7 +355,7 @@ namespace Umbraco.Core.Packaging
|
||||
|
||||
public IEnumerable<IContentType> ImportDocumentType(XElement docTypeElement, int userId)
|
||||
{
|
||||
return ImportDocumentTypes(new []{ docTypeElement }, userId);
|
||||
return ImportDocumentTypes(new[] { docTypeElement }, userId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -359,7 +379,7 @@ namespace Umbraco.Core.Packaging
|
||||
public IEnumerable<IContentType> ImportDocumentTypes(IReadOnlyCollection<XElement> unsortedDocumentTypes, bool importStructure, int userId)
|
||||
{
|
||||
var importedContentTypes = new Dictionary<string, IContentType>();
|
||||
|
||||
|
||||
//When you are importing a single doc type we have to assume that the dependencies are already there.
|
||||
//Otherwise something like uSync won't work.
|
||||
var graph = new TopoGraph<string, TopoGraph.Node<string, XElement>>(x => x.Key, x => x.Dependencies);
|
||||
@@ -452,7 +472,7 @@ namespace Umbraco.Core.Packaging
|
||||
if (updatedContentTypes.Any())
|
||||
_contentTypeService.Save(updatedContentTypes, userId);
|
||||
}
|
||||
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -854,7 +874,7 @@ namespace Umbraco.Core.Packaging
|
||||
{
|
||||
_dataTypeService.Save(dataTypes, userId, true);
|
||||
}
|
||||
|
||||
|
||||
return dataTypes;
|
||||
}
|
||||
|
||||
@@ -937,7 +957,7 @@ namespace Umbraco.Core.Packaging
|
||||
var items = new List<IDictionaryItem>();
|
||||
foreach (var dictionaryItemElement in dictionaryItemElementList)
|
||||
items.AddRange(ImportDictionaryItem(dictionaryItemElement, languages, parentId, userId));
|
||||
|
||||
|
||||
return items;
|
||||
}
|
||||
|
||||
@@ -1024,7 +1044,7 @@ namespace Umbraco.Core.Packaging
|
||||
_localizationService.Save(langauge, userId);
|
||||
list.Add(langauge);
|
||||
}
|
||||
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
@@ -1187,7 +1207,7 @@ namespace Umbraco.Core.Packaging
|
||||
|
||||
public IEnumerable<ITemplate> ImportTemplate(XElement templateElement, int userId)
|
||||
{
|
||||
return ImportTemplates(new[] {templateElement}, userId);
|
||||
return ImportTemplates(new[] { templateElement }, userId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1234,7 +1254,7 @@ namespace Umbraco.Core.Packaging
|
||||
var alias = templateElement.Element("Alias").Value;
|
||||
var design = templateElement.Element("Design").Value;
|
||||
var masterElement = templateElement.Element("Master");
|
||||
|
||||
|
||||
var existingTemplate = _fileService.GetTemplate(alias) as Template;
|
||||
var template = existingTemplate ?? new Template(templateName, alias);
|
||||
template.Content = design;
|
||||
|
||||
@@ -5,17 +5,16 @@ namespace Umbraco.Core
|
||||
{
|
||||
public static class DatabaseSchema
|
||||
{
|
||||
//TODO: Why aren't all table names with the same prefix?
|
||||
public const string TableNamePrefix = "umbraco";
|
||||
|
||||
public static class Tables
|
||||
{
|
||||
public const string Lock = /*TableNamePrefix*/ "umbraco" + "Lock";
|
||||
public const string Log = /*TableNamePrefix*/ "umbraco" + "Log";
|
||||
public const string Lock = TableNamePrefix + "Lock";
|
||||
public const string Log = TableNamePrefix + "Log";
|
||||
|
||||
public const string Node = /*TableNamePrefix*/ "umbraco" + "Node";
|
||||
public const string Node = TableNamePrefix + "Node";
|
||||
public const string NodeData = /*TableNamePrefix*/ "cms" + "ContentNu";
|
||||
public const string NodeXml = /*TableNamePrefix*/ "cms" + "ContentXml"; // TODO: get rid of these with the xml cache
|
||||
public const string NodePreviewXml = /*TableNamePrefix*/ "cms" + "PreviewXml"; // TODO: get rid of these with the xml cache
|
||||
|
||||
public const string ContentType = /*TableNamePrefix*/ "cms" + "ContentType";
|
||||
public const string ContentChildType = /*TableNamePrefix*/ "cms" + "ContentTypeAllowedContentType";
|
||||
@@ -37,22 +36,22 @@ namespace Umbraco.Core
|
||||
public const string PropertyTypeGroup = /*TableNamePrefix*/ "cms" + "PropertyTypeGroup";
|
||||
public const string PropertyData = TableNamePrefix + "PropertyData";
|
||||
|
||||
public const string RelationType = /*TableNamePrefix*/ "umbraco" + "RelationType";
|
||||
public const string Relation = /*TableNamePrefix*/ "umbraco" + "Relation";
|
||||
public const string RelationType = TableNamePrefix + "RelationType";
|
||||
public const string Relation = TableNamePrefix + "Relation";
|
||||
|
||||
public const string Domain = /*TableNamePrefix*/ "umbraco" + "Domain";
|
||||
public const string Language = /*TableNamePrefix*/ "umbraco" + "Language";
|
||||
public const string Domain = TableNamePrefix + "Domain";
|
||||
public const string Language = TableNamePrefix + "Language";
|
||||
public const string DictionaryEntry = /*TableNamePrefix*/ "cms" + "Dictionary";
|
||||
public const string DictionaryValue = /*TableNamePrefix*/ "cms" + "LanguageText";
|
||||
|
||||
public const string User = /*TableNamePrefix*/ "umbraco" + "User";
|
||||
public const string UserGroup = /*TableNamePrefix*/ "umbraco" + "UserGroup";
|
||||
public const string UserStartNode = /*TableNamePrefix*/ "umbraco" + "UserStartNode";
|
||||
public const string User2UserGroup = /*TableNamePrefix*/ "umbraco" + "User2UserGroup";
|
||||
public const string User2NodeNotify = /*TableNamePrefix*/ "umbraco" + "User2NodeNotify";
|
||||
public const string UserGroup2App = /*TableNamePrefix*/ "umbraco" + "UserGroup2App";
|
||||
public const string UserGroup2NodePermission = /*TableNamePrefix*/ "umbraco" + "UserGroup2NodePermission";
|
||||
public const string ExternalLogin = /*TableNamePrefix*/ "umbraco" + "ExternalLogin";
|
||||
public const string User = TableNamePrefix + "User";
|
||||
public const string UserGroup = TableNamePrefix + "UserGroup";
|
||||
public const string UserStartNode = TableNamePrefix + "UserStartNode";
|
||||
public const string User2UserGroup = TableNamePrefix + "User2UserGroup";
|
||||
public const string User2NodeNotify = TableNamePrefix + "User2NodeNotify";
|
||||
public const string UserGroup2App = TableNamePrefix + "UserGroup2App";
|
||||
public const string UserGroup2NodePermission = TableNamePrefix + "UserGroup2NodePermission";
|
||||
public const string ExternalLogin = TableNamePrefix + "ExternalLogin";
|
||||
|
||||
public const string Macro = /*TableNamePrefix*/ "cms" + "Macro";
|
||||
public const string MacroProperty = /*TableNamePrefix*/ "cms" + "MacroProperty";
|
||||
@@ -61,21 +60,21 @@ namespace Umbraco.Core
|
||||
public const string MemberType = /*TableNamePrefix*/ "cms" + "MemberType";
|
||||
public const string Member2MemberGroup = /*TableNamePrefix*/ "cms" + "Member2MemberGroup";
|
||||
|
||||
public const string Access = /*TableNamePrefix*/ "umbraco" + "Access";
|
||||
public const string AccessRule = /*TableNamePrefix*/ "umbraco" + "AccessRule";
|
||||
public const string RedirectUrl = /*TableNamePrefix*/ "umbraco" + "RedirectUrl";
|
||||
public const string Access = TableNamePrefix + "Access";
|
||||
public const string AccessRule = TableNamePrefix + "AccessRule";
|
||||
public const string RedirectUrl = TableNamePrefix + "RedirectUrl";
|
||||
|
||||
public const string CacheInstruction = /*TableNamePrefix*/ "umbraco" + "CacheInstruction";
|
||||
public const string Server = /*TableNamePrefix*/ "umbraco" + "Server";
|
||||
public const string CacheInstruction = TableNamePrefix + "CacheInstruction";
|
||||
public const string Server = TableNamePrefix + "Server";
|
||||
|
||||
public const string Tag = /*TableNamePrefix*/ "cms" + "Tags";
|
||||
public const string TagRelationship = /*TableNamePrefix*/ "cms" + "TagRelationship";
|
||||
|
||||
public const string KeyValue = TableNamePrefix + "KeyValue";
|
||||
|
||||
public const string AuditEntry = /*TableNamePrefix*/ "umbraco" + "Audit";
|
||||
public const string Consent = /*TableNamePrefix*/ "umbraco" + "Consent";
|
||||
public const string UserLogin = /*TableNamePrefix*/ "umbraco" + "UserLogin";
|
||||
public const string AuditEntry = TableNamePrefix + "Audit";
|
||||
public const string Consent = TableNamePrefix + "Consent";
|
||||
public const string UserLogin = TableNamePrefix + "UserLogin";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,11 +30,14 @@ namespace Umbraco.Core.Persistence.Dtos
|
||||
/// Updated every time a user's session is validated
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This allows us to guess if a session is timed out if a user doesn't actively log out
|
||||
/// and also allows us to trim the data in the table
|
||||
/// <para>This allows us to guess if a session is timed out if a user doesn't actively
|
||||
/// log out and also allows us to trim the data in the table.</para>
|
||||
/// <para>The index is IMPORTANT as it prevents deadlocks during deletion of
|
||||
/// old sessions (DELETE ... WHERE lastValidatedUtc < date).</para>
|
||||
/// </remarks>
|
||||
[Column("lastValidatedUtc")]
|
||||
[NullSetting(NullSetting = NullSettings.NotNull)]
|
||||
[Index(IndexTypes.NonClustered, Name = "IX_userLoginDto_lastValidatedUtc")]
|
||||
public DateTime LastValidatedUtc { get; set; }
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -202,10 +202,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
"DELETE FROM " + Constants.DatabaseSchema.Tables.DocumentCultureVariation + " WHERE nodeId = @id",
|
||||
"DELETE FROM " + Constants.DatabaseSchema.Tables.DocumentVersion + " WHERE id IN (SELECT id FROM " + Constants.DatabaseSchema.Tables.ContentVersion + " WHERE nodeId = @id)",
|
||||
"DELETE FROM " + Constants.DatabaseSchema.Tables.PropertyData + " WHERE versionId IN (SELECT id FROM " + Constants.DatabaseSchema.Tables.ContentVersion + " WHERE nodeId = @id)",
|
||||
"DELETE FROM cmsPreviewXml WHERE nodeId = @id",
|
||||
"DELETE FROM " + Constants.DatabaseSchema.Tables.ContentVersionCultureVariation + " WHERE versionId IN (SELECT id FROM " + Constants.DatabaseSchema.Tables.ContentVersion + " WHERE nodeId = @id)",
|
||||
"DELETE FROM " + Constants.DatabaseSchema.Tables.ContentVersion + " WHERE nodeId = @id",
|
||||
"DELETE FROM cmsContentXml WHERE nodeId = @id",
|
||||
"DELETE FROM " + Constants.DatabaseSchema.Tables.Content + " WHERE nodeId = @id",
|
||||
"DELETE FROM " + Constants.DatabaseSchema.Tables.Access + " WHERE nodeId = @id",
|
||||
"DELETE FROM " + Constants.DatabaseSchema.Tables.Node + " WHERE id = @id"
|
||||
|
||||
@@ -199,7 +199,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
private IEnumerable<TreeEntityPath> PerformGetAllPaths(Guid objectType, Action<Sql<ISqlContext>> filter = null)
|
||||
{
|
||||
// NodeId is named Id on TreeEntityPath = use an alias
|
||||
var sql = Sql().Select<NodeDto>(x => Alias(x.NodeId, "Id"), x => x.Path).From<NodeDto>().Where<NodeDto>(x => x.NodeObjectType == objectType);
|
||||
var sql = Sql().Select<NodeDto>(x => Alias(x.NodeId, nameof(TreeEntityPath.Id)), x => x.Path).From<NodeDto>().Where<NodeDto>(x => x.NodeObjectType == objectType);
|
||||
filter?.Invoke(sql);
|
||||
return Database.Fetch<TreeEntityPath>(sql);
|
||||
}
|
||||
|
||||
@@ -188,7 +188,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
"DELETE FROM cmsMember2MemberGroup WHERE Member = @id",
|
||||
"DELETE FROM cmsMember WHERE nodeId = @id",
|
||||
"DELETE FROM " + Constants.DatabaseSchema.Tables.ContentVersion + " WHERE nodeId = @id",
|
||||
"DELETE FROM cmsContentXml WHERE nodeId = @id",
|
||||
"DELETE FROM " + Constants.DatabaseSchema.Tables.Content + " WHERE nodeId = @id",
|
||||
"DELETE FROM umbracoNode WHERE id = @id"
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
|
||||
namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
@@ -8,8 +9,6 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
[DefaultPropertyValueConverter]
|
||||
public class CheckboxListValueConverter : PropertyValueConverterBase
|
||||
{
|
||||
private static readonly char[] Comma = { ',' };
|
||||
|
||||
public override bool IsConverter(PublishedPropertyType propertyType)
|
||||
=> propertyType.EditorAlias.InvariantEquals(Constants.PropertyEditors.Aliases.CheckBoxList);
|
||||
|
||||
@@ -26,7 +25,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
if (string.IsNullOrEmpty(sourceString))
|
||||
return Enumerable.Empty<string>();
|
||||
|
||||
return sourceString.Split(Comma, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim());
|
||||
return JsonConvert.DeserializeObject<string[]>(sourceString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,17 +10,17 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
|
||||
=> propertyType.EditorAlias.InvariantEquals(Constants.PropertyEditors.Aliases.RadioButtonList);
|
||||
|
||||
public override Type GetPropertyValueType(PublishedPropertyType propertyType)
|
||||
=> typeof (int);
|
||||
=> typeof (string);
|
||||
|
||||
public override PropertyCacheLevel GetPropertyCacheLevel(PublishedPropertyType propertyType)
|
||||
=> PropertyCacheLevel.Element;
|
||||
|
||||
public override object ConvertSourceToIntermediate(IPublishedElement owner, PublishedPropertyType propertyType, object source, bool preview)
|
||||
{
|
||||
var intAttempt = source.TryConvertTo<int>();
|
||||
var attempt = source.TryConvertTo<string>();
|
||||
|
||||
if (intAttempt.Success)
|
||||
return intAttempt.Result;
|
||||
if (attempt.Success)
|
||||
return attempt.Result;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -100,9 +100,7 @@ namespace Umbraco.Core.Services
|
||||
/// <param name="pageIndex">Page number</param>
|
||||
/// <param name="pageSize">Page size</param>
|
||||
/// <param name="totalRecords">Total records query would return without paging</param>
|
||||
/// <param name="orderBy">Field to order by</param>
|
||||
/// <param name="orderDirection">Direction to order by</param>
|
||||
/// <param name="orderBySystemField">Flag to indicate when ordering by system field</param>
|
||||
/// <param name="ordering"></param>
|
||||
/// <param name="filter"></param>
|
||||
/// <returns>An Enumerable list of <see cref="IContent"/> objects</returns>
|
||||
IEnumerable<IMedia> GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalRecords,
|
||||
|
||||
@@ -99,7 +99,6 @@ namespace Umbraco.Core.Services
|
||||
/// This is simply a helper method which essentially just wraps the MembershipProvider's ChangePassword method which can be
|
||||
/// used during Member creation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <remarks>This method exists so that Umbraco developers can use one entry point to create/update
|
||||
/// this will not work for updating members in most cases (depends on your membership provider settings)
|
||||
///
|
||||
|
||||
@@ -158,7 +158,7 @@ namespace Umbraco.Core.Services
|
||||
// multiple times, but we don't lock the cache while accessing the database = better
|
||||
|
||||
int? val = null;
|
||||
|
||||
|
||||
if (_dictionary.TryGetValue(umbracoObjectType, out var mappers))
|
||||
if ((val = mappers.key2id(key)) == default(int)) val = null;
|
||||
|
||||
|
||||
@@ -367,6 +367,7 @@
|
||||
<Compile Include="Migrations\Upgrade\V_7_9_0\AddUmbracoAuditTable.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_7_9_0\AddUmbracoConsentTable.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_7_9_0\CreateSensitiveDataUserGroup.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\AddUserLoginDtoDateIndex.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\ConvertRelatedLinksToMultiUrlPicker.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\AddContentTypeIsElementColumn.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\AddLogTableColumns.cs" />
|
||||
@@ -378,6 +379,7 @@
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DropPreValueTable.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DropTaskTables.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DropTemplateDesignColumn.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DropXmlTables.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\FixLockTablePrimaryKey.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\LanguageColumns.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\MakeRedirectUrlVariant.cs" />
|
||||
@@ -385,6 +387,7 @@
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\PropertyEditorsMigration.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\RefactorMacroColumns.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\RefactorVariantsModel.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\RadioAndCheckboxAndDropdownPropertyEditorsMigration.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\RenameUmbracoDomainsTable.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\SuperZero.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\TablesForScheduledPublishing.cs" />
|
||||
@@ -825,7 +828,6 @@
|
||||
<Compile Include="Persistence\Dtos\ContentTypeDto.cs" />
|
||||
<Compile Include="Persistence\Dtos\ContentTypeTemplateDto.cs" />
|
||||
<Compile Include="Persistence\Dtos\ContentVersionDto.cs" />
|
||||
<Compile Include="Persistence\Dtos\ContentXmlDto.cs" />
|
||||
<Compile Include="Persistence\Dtos\DataTypeDto.cs" />
|
||||
<Compile Include="Persistence\Dtos\DictionaryDto.cs" />
|
||||
<Compile Include="Persistence\Dtos\DocumentDto.cs" />
|
||||
@@ -845,7 +847,6 @@
|
||||
<Compile Include="Persistence\Dtos\MemberTypeDto.cs" />
|
||||
<Compile Include="Persistence\Dtos\MemberTypeReadOnlyDto.cs" />
|
||||
<Compile Include="Persistence\Dtos\NodeDto.cs" />
|
||||
<Compile Include="Persistence\Dtos\PreviewXmlDto.cs" />
|
||||
<Compile Include="Persistence\Dtos\PropertyDataDto.cs" />
|
||||
<Compile Include="Persistence\Dtos\PropertyTypeDto.cs" />
|
||||
<Compile Include="Persistence\Dtos\PropertyTypeGroupDto.cs" />
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<!-- note: NuGet deals with transitive references now -->
|
||||
<PackageReference Include="Examine" Version="1.0.0-beta078" />
|
||||
<PackageReference Include="Examine" Version="1.0.0-beta079" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
|
||||
<PackageReference Include="NPoco" Version="3.9.4" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
using NPoco;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Dtos
|
||||
namespace Umbraco.Tests.LegacyXmlPublishedCache
|
||||
{
|
||||
[TableName(Constants.DatabaseSchema.Tables.NodeXml)]
|
||||
[TableName("cmsContentXml")]
|
||||
[PrimaryKey("nodeId", AutoIncrement = false)]
|
||||
[ExplicitColumns]
|
||||
internal class ContentXmlDto
|
||||
@@ -20,4 +21,4 @@ namespace Umbraco.Core.Persistence.Dtos
|
||||
[Column("rv")]
|
||||
public long Rv { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
using NPoco;
|
||||
using Umbraco.Core.Persistence.DatabaseAnnotations;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
|
||||
namespace Umbraco.Core.Persistence.Dtos
|
||||
namespace Umbraco.Tests.LegacyXmlPublishedCache
|
||||
{
|
||||
[TableName(Constants.DatabaseSchema.Tables.NodePreviewXml)]
|
||||
[TableName("cmsPreviewXml")]
|
||||
[PrimaryKey("nodeId", AutoIncrement = false)]
|
||||
[ExplicitColumns]
|
||||
internal class PreviewXmlDto
|
||||
@@ -20,4 +21,4 @@ namespace Umbraco.Core.Persistence.Dtos
|
||||
[Column("rv")]
|
||||
public long Rv { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,6 @@ using Umbraco.Core.IO;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Persistence.Repositories.Implement;
|
||||
using Umbraco.Core.Scoping;
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
using Moq;
|
||||
using System.Linq;
|
||||
using Moq;
|
||||
using NUnit.Framework;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Migrations.Install;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Tests.LegacyXmlPublishedCache;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.Testing;
|
||||
|
||||
@@ -21,7 +23,9 @@ namespace Umbraco.Tests.Persistence
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
var schema = new DatabaseSchemaCreator(scope.Database, Logger);
|
||||
result = schema.ValidateSchema();
|
||||
result = schema.ValidateSchema(
|
||||
//TODO: When we remove the xml cache from tests we can remove this too
|
||||
DatabaseSchemaCreator.OrderedTables.Concat(new []{typeof(ContentXmlDto), typeof(PreviewXmlDto)}));
|
||||
}
|
||||
|
||||
// Assert
|
||||
|
||||
@@ -5,6 +5,7 @@ using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Migrations.Install;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Tests.LegacyXmlPublishedCache;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.Testing;
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.SqlSyntax;
|
||||
using Umbraco.Core.Scoping;
|
||||
using Umbraco.Tests.LegacyXmlPublishedCache;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.Testing;
|
||||
|
||||
|
||||
@@ -65,9 +65,9 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
Assert.AreEqual(expected, result);
|
||||
}
|
||||
|
||||
[TestCase("apples", new[] { "apples" })]
|
||||
[TestCase("apples,oranges", new[] { "apples", "oranges" })]
|
||||
[TestCase(" apples, oranges, pears ", new[] { "apples", "oranges", "pears" })]
|
||||
[TestCase("[\"apples\"]", new[] { "apples" })]
|
||||
[TestCase("[\"apples\",\"oranges\"]", new[] { "apples", "oranges" })]
|
||||
[TestCase("[\"apples\",\"oranges\",\"pears\"]", new[] { "apples", "oranges", "pears" })]
|
||||
[TestCase("", new string[] { })]
|
||||
[TestCase(null, new string[] { })]
|
||||
public void CanConvertCheckboxListPropertyEditor(object value, IEnumerable<string> expected)
|
||||
@@ -78,9 +78,9 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
Assert.AreEqual(expected, result);
|
||||
}
|
||||
|
||||
[TestCase("apples", new[] { "apples" })]
|
||||
[TestCase("apples,oranges", new[] { "apples", "oranges" })]
|
||||
[TestCase("apples , oranges, pears ", new[] { "apples", "oranges", "pears" })]
|
||||
[TestCase("[\"apples\"]", new[] { "apples" })]
|
||||
[TestCase("[\"apples\",\"oranges\"]", new[] { "apples", "oranges" })]
|
||||
[TestCase("[\"apples\",\"oranges\",\"pears\"]", new[] { "apples", "oranges", "pears" })]
|
||||
[TestCase("", new string[] { })]
|
||||
[TestCase(null, new string[] { })]
|
||||
public void CanConvertDropdownListMultiplePropertyEditor(object value, IEnumerable<string> expected)
|
||||
@@ -104,7 +104,7 @@ namespace Umbraco.Tests.PropertyEditors
|
||||
|
||||
Assert.AreEqual(expected, result);
|
||||
}
|
||||
|
||||
|
||||
[TestCase("1", 1)]
|
||||
[TestCase("1", 1)]
|
||||
[TestCase("0", 0)]
|
||||
|
||||
@@ -18,6 +18,7 @@ using Umbraco.Core.Services.Implement;
|
||||
using Umbraco.Tests.Testing;
|
||||
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Tests.LegacyXmlPublishedCache;
|
||||
|
||||
namespace Umbraco.Tests.Services
|
||||
{
|
||||
|
||||
@@ -10,6 +10,7 @@ using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Services.Implement;
|
||||
using Umbraco.Tests.LegacyXmlPublishedCache;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
using Umbraco.Tests.Testing;
|
||||
using Umbraco.Tests.Scoping;
|
||||
|
||||
@@ -14,6 +14,7 @@ using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Repositories;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Services.Implement;
|
||||
using Umbraco.Tests.LegacyXmlPublishedCache;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
using Umbraco.Tests.Testing;
|
||||
|
||||
@@ -17,6 +17,7 @@ using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Persistence.Querying;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Services.Implement;
|
||||
using Umbraco.Tests.LegacyXmlPublishedCache;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
using Umbraco.Tests.Testing;
|
||||
using Umbraco.Web.Security.Providers;
|
||||
|
||||
@@ -5,6 +5,7 @@ using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Tests.LegacyXmlPublishedCache;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
using Umbraco.Tests.Testing;
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@ using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Persistence.Dtos;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Core.Services.Implement;
|
||||
using Umbraco.Tests.LegacyXmlPublishedCache;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Entities;
|
||||
using Umbraco.Tests.TestHelpers.Stubs;
|
||||
|
||||
@@ -307,6 +307,13 @@ namespace Umbraco.Tests.TestHelpers
|
||||
var schemaHelper = new DatabaseSchemaCreator(scope.Database, Logger);
|
||||
//Create the umbraco database and its base data
|
||||
schemaHelper.InitializeDatabaseSchema();
|
||||
|
||||
//Special case, we need to create the xml cache tables manually since they are not part of the default
|
||||
//setup.
|
||||
//TODO: Remove this when we update all tests to use nucache
|
||||
schemaHelper.CreateTable<ContentXmlDto>();
|
||||
schemaHelper.CreateTable<PreviewXmlDto>();
|
||||
|
||||
scope.Complete();
|
||||
}
|
||||
|
||||
|
||||
@@ -228,6 +228,7 @@ namespace Umbraco.Tests.Testing
|
||||
.Append<PackagesBackOfficeSection>()
|
||||
.Append<UsersBackOfficeSection>()
|
||||
.Append<MembersBackOfficeSection>()
|
||||
.Append<FormsBackOfficeSection>()
|
||||
.Append<TranslationBackOfficeSection>();
|
||||
Composition.RegisterUnique<ISectionService, SectionService>();
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AutoMapper" Version="8.0.0" />
|
||||
<PackageReference Include="Castle.Core" Version="4.3.1" />
|
||||
<PackageReference Include="Examine" Version="1.0.0-beta078" />
|
||||
<PackageReference Include="Examine" Version="1.0.0-beta079" />
|
||||
<PackageReference Include="HtmlAgilityPack">
|
||||
<Version>1.8.14</Version>
|
||||
</PackageReference>
|
||||
@@ -126,6 +126,8 @@
|
||||
<Compile Include="CoreThings\GuidUtilsTests.cs" />
|
||||
<Compile Include="CoreThings\HexEncoderTests.cs" />
|
||||
<Compile Include="CoreXml\RenamedRootNavigatorTests.cs" />
|
||||
<Compile Include="LegacyXmlPublishedCache\ContentXmlDto.cs" />
|
||||
<Compile Include="LegacyXmlPublishedCache\PreviewXmlDto.cs" />
|
||||
<Compile Include="Logging\LogviewerTests.cs" />
|
||||
<Compile Include="Manifest\ManifestContentAppTests.cs" />
|
||||
<Compile Include="Migrations\MigrationPlanTests.cs" />
|
||||
|
||||
@@ -6,5 +6,5 @@ var runSequence = require('run-sequence');
|
||||
|
||||
// Build - build the files ready for production
|
||||
gulp.task('build', function(cb) {
|
||||
runSequence(["js", "dependencies", "less", "views"], "test:unit", cb);
|
||||
runSequence(["js", "dependencies", "less", "views"], /*"test:unit",*/ cb);
|
||||
});
|
||||
|
||||
@@ -871,6 +871,8 @@
|
||||
|
||||
$scope.app = app;
|
||||
|
||||
$scope.$broadcast("editors.apps.appChanged", { app: app });
|
||||
|
||||
if (infiniteMode) {
|
||||
createInfiniteModeButtons($scope.content);
|
||||
} else {
|
||||
@@ -878,6 +880,15 @@
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Call back when a content app changes
|
||||
* @param {any} app
|
||||
*/
|
||||
$scope.appAnchorChanged = function (app, anchor) {
|
||||
//send an event downwards
|
||||
$scope.$broadcast("editors.apps.appAnchorChanged", { app: app, anchor: anchor });
|
||||
};
|
||||
|
||||
// methods for infinite editing
|
||||
$scope.close = function () {
|
||||
if ($scope.infiniteModel.close) {
|
||||
|
||||
@@ -2,40 +2,153 @@
|
||||
'use strict';
|
||||
|
||||
/** This directive is used to render out the current variant tabs and properties and exposes an API for other directives to consume */
|
||||
function tabbedContentDirective() {
|
||||
function tabbedContentDirective($timeout) {
|
||||
|
||||
function link($scope, $element, $attrs) {
|
||||
|
||||
var appRootNode = $element[0];
|
||||
|
||||
// Directive for cached property groups.
|
||||
var propertyGroupNodesDictionary = {};
|
||||
|
||||
var scrollableNode = appRootNode.closest(".umb-scrollable");
|
||||
scrollableNode.addEventListener("scroll", onScroll);
|
||||
scrollableNode.addEventListener("mousewheel", cancelScrollTween);
|
||||
|
||||
function onScroll(event) {
|
||||
|
||||
var viewFocusY = scrollableNode.scrollTop + scrollableNode.clientHeight * .5;
|
||||
|
||||
for(var i in $scope.content.tabs) {
|
||||
var group = $scope.content.tabs[i];
|
||||
var node = propertyGroupNodesDictionary[group.id];
|
||||
if (viewFocusY >= node.offsetTop && viewFocusY <= node.offsetTop + node.clientHeight) {
|
||||
setActiveAnchor(group);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function setActiveAnchor(tab) {
|
||||
if (tab.active !== true) {
|
||||
var i = $scope.content.tabs.length;
|
||||
while(i--) {
|
||||
$scope.content.tabs[i].active = false;
|
||||
}
|
||||
tab.active = true;
|
||||
}
|
||||
}
|
||||
function getActiveAnchor() {
|
||||
var i = $scope.content.tabs.length;
|
||||
while(i--) {
|
||||
if ($scope.content.tabs[i].active === true)
|
||||
return $scope.content.tabs[i];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function getScrollPositionFor(id) {
|
||||
if (propertyGroupNodesDictionary[id]) {
|
||||
return propertyGroupNodesDictionary[id].offsetTop - 20;// currently only relative to closest relatively positioned parent
|
||||
}
|
||||
return null;
|
||||
}
|
||||
function scrollTo(id) {
|
||||
var y = getScrollPositionFor(id);
|
||||
if (getScrollPositionFor !== null) {
|
||||
|
||||
var viewportHeight = scrollableNode.clientHeight;
|
||||
var from = scrollableNode.scrollTop;
|
||||
var to = Math.min(y, scrollableNode.scrollHeight - viewportHeight);
|
||||
|
||||
var animeObject = {_y: from};
|
||||
$scope.scrollTween = anime({
|
||||
targets: animeObject,
|
||||
_y: to,
|
||||
easing: 'easeOutExpo',
|
||||
duration: 200 + Math.min(Math.abs(to-from)/viewportHeight*100, 400),
|
||||
update: () => {
|
||||
scrollableNode.scrollTo(0, animeObject._y);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
function jumpTo(id) {
|
||||
var y = getScrollPositionFor(id);
|
||||
if (getScrollPositionFor !== null) {
|
||||
cancelScrollTween();
|
||||
scrollableNode.scrollTo(0, y);
|
||||
}
|
||||
}
|
||||
function cancelScrollTween() {
|
||||
if($scope.scrollTween) {
|
||||
$scope.scrollTween.pause();
|
||||
}
|
||||
}
|
||||
|
||||
$scope.registerPropertyGroup = function(element, appAnchor) {
|
||||
propertyGroupNodesDictionary[appAnchor] = element;
|
||||
};
|
||||
|
||||
$scope.$on("editors.apps.appChanged", function($event, $args) {
|
||||
// if app changed to this app, then we want to scroll to the current anchor
|
||||
if($args.app.alias === "umbContent") {
|
||||
var activeAnchor = getActiveAnchor();
|
||||
$timeout(jumpTo.bind(null, [activeAnchor.id]));
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$on("editors.apps.appAnchorChanged", function($event, $args) {
|
||||
if($args.app.alias === "umbContent") {
|
||||
setActiveAnchor($args.anchor);
|
||||
scrollTo($args.anchor.id);
|
||||
}
|
||||
});
|
||||
|
||||
//ensure to unregister from all dom-events
|
||||
$scope.$on('$destroy', function () {
|
||||
cancelScrollTween();
|
||||
scrollableNode.removeEventListener("scroll", onScroll);
|
||||
scrollableNode.removeEventListener("mousewheel", cancelScrollTween);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function controller($scope, $element, $attrs) {
|
||||
|
||||
|
||||
//expose the property/methods for other directives to use
|
||||
this.content = $scope.content;
|
||||
this.activeVariant = _.find(this.content.variants, variant => {
|
||||
return variant.active;
|
||||
});
|
||||
|
||||
$scope.activeVariant = this.activeVariant;
|
||||
|
||||
$scope.defaultVariant = _.find(this.content.variants, variant => {
|
||||
return variant.language.isDefault;
|
||||
});
|
||||
|
||||
$scope.unlockInvariantValue = function(property) {
|
||||
property.unlockInvariantValue = !property.unlockInvariantValue;
|
||||
};
|
||||
|
||||
$scope.$watch("tabbedContentForm.$dirty",
|
||||
function (newValue, oldValue) {
|
||||
if (newValue === true) {
|
||||
$scope.content.isDirty = true;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
var directive = {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'views/components/content/umb-tabbed-content.html',
|
||||
controller: function ($scope) {
|
||||
|
||||
//expose the property/methods for other directives to use
|
||||
this.content = $scope.content;
|
||||
this.activeVariant = _.find(this.content.variants, variant => {
|
||||
return variant.active;
|
||||
});
|
||||
|
||||
$scope.activeVariant = this.activeVariant;
|
||||
|
||||
$scope.defaultVariant = _.find(this.content.variants, variant => {
|
||||
return variant.language.isDefault;
|
||||
});
|
||||
|
||||
$scope.unlockInvariantValue = function(property) {
|
||||
property.unlockInvariantValue = !property.unlockInvariantValue;
|
||||
};
|
||||
|
||||
$scope.$watch("tabbedContentForm.$dirty",
|
||||
function (newValue, oldValue) {
|
||||
if (newValue === true) {
|
||||
$scope.content.isDirty = true;
|
||||
}
|
||||
});
|
||||
},
|
||||
link: function(scope) {
|
||||
|
||||
},
|
||||
controller: controller,
|
||||
link: link,
|
||||
scope: {
|
||||
content: "="
|
||||
}
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
onCloseSplitView: "&",
|
||||
onSelectVariant: "&",
|
||||
onOpenSplitView: "&",
|
||||
onSelectApp: "&"
|
||||
onSelectApp: "&",
|
||||
onSelectAppAnchor: "&"
|
||||
},
|
||||
controllerAs: 'vm',
|
||||
controller: umbVariantContentController
|
||||
@@ -35,6 +36,7 @@
|
||||
vm.selectVariant = selectVariant;
|
||||
vm.openSplitView = openSplitView;
|
||||
vm.selectApp = selectApp;
|
||||
vm.selectAppAnchor = selectAppAnchor;
|
||||
|
||||
function onInit() {
|
||||
// disable the name field if the active content app is not "Content"
|
||||
@@ -78,16 +80,31 @@
|
||||
* @param {any} item
|
||||
*/
|
||||
function selectApp(item) {
|
||||
// disable the name field if the active content app is not "Content" or "Info"
|
||||
vm.nameDisabled = false;
|
||||
if(item && item.alias !== "umbContent" && item.alias !== "umbInfo") {
|
||||
vm.nameDisabled = true;
|
||||
}
|
||||
// call the callback if any is registered
|
||||
if(vm.onSelectApp) {
|
||||
vm.onSelectApp({"app": item});
|
||||
}
|
||||
}
|
||||
|
||||
$scope.$on("editors.apps.appChanged", function($event, $args) {
|
||||
var app = $args.app;
|
||||
// disable the name field if the active content app is not "Content" or "Info"
|
||||
vm.nameDisabled = false;
|
||||
if(app && app.alias !== "umbContent" && app.alias !== "umbInfo") {
|
||||
vm.nameDisabled = true;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Used to proxy a callback
|
||||
* @param {any} item
|
||||
*/
|
||||
function selectAppAnchor(item, anchor) {
|
||||
// call the callback if any is registered
|
||||
if(vm.onSelectAppAnchor) {
|
||||
vm.onSelectAppAnchor({"app": item, "anchor": anchor});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to proxy a callback
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
page: "<",
|
||||
content: "<", // TODO: Not sure if this should be = since we are changing the 'active' property of a variant
|
||||
culture: "<",
|
||||
onSelectApp: "&?"
|
||||
onSelectApp: "&?",
|
||||
onSelectAppAnchor: "&?"
|
||||
},
|
||||
controllerAs: 'vm',
|
||||
controller: umbVariantContentEditorsController
|
||||
@@ -32,6 +33,7 @@
|
||||
vm.closeSplitView = closeSplitView;
|
||||
vm.selectVariant = selectVariant;
|
||||
vm.selectApp = selectApp;
|
||||
vm.selectAppAnchor = selectAppAnchor;
|
||||
|
||||
//Used to track how many content views there are (for split view there will be 2, it could support more in theory)
|
||||
vm.editors = [];
|
||||
@@ -316,13 +318,24 @@
|
||||
* @param {any} app This is the model of the selected app
|
||||
*/
|
||||
function selectApp(app) {
|
||||
if(app && app.alias) {
|
||||
activeAppAlias = app.alias;
|
||||
}
|
||||
if(vm.onSelectApp) {
|
||||
vm.onSelectApp({"app": app});
|
||||
}
|
||||
}
|
||||
|
||||
function selectAppAnchor(app, anchor) {
|
||||
if(vm.onSelectAppAnchor) {
|
||||
vm.onSelectAppAnchor({"app": app, "anchor": anchor});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$scope.$on("editors.apps.appChanged", function($event, $args) {
|
||||
var app = $args.app;
|
||||
if(app && app.alias) {
|
||||
activeAppAlias = app.alias;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -11,17 +11,26 @@
|
||||
if (!scope.serverValidationAliasField) {
|
||||
scope.serverValidationAliasField = "Alias";
|
||||
}
|
||||
|
||||
|
||||
scope.vm = {};
|
||||
scope.vm.dropdownOpen = false;
|
||||
scope.vm.currentVariant = "";
|
||||
|
||||
function onInit() {
|
||||
|
||||
setCurrentVariant();
|
||||
|
||||
angular.forEach(scope.content.apps, (app) => {
|
||||
if (app.alias === "umbContent") {
|
||||
console.log("app: ", app)
|
||||
app.anchors = scope.content.tabs;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function setCurrentVariant() {
|
||||
angular.forEach(scope.variants, function (variant) {
|
||||
angular.forEach(scope.content.variants, function (variant) {
|
||||
if (variant.active) {
|
||||
scope.vm.currentVariant = variant;
|
||||
}
|
||||
@@ -46,6 +55,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
scope.selectAnchorItem = function(item, anchor) {
|
||||
if(scope.onSelectAnchorItem) {
|
||||
scope.onSelectAnchorItem({"item": item, "anchor": anchor});
|
||||
}
|
||||
}
|
||||
|
||||
scope.closeSplitView = function () {
|
||||
if (scope.onCloseSplitView) {
|
||||
scope.onCloseSplitView();
|
||||
@@ -72,10 +87,10 @@
|
||||
onInit();
|
||||
|
||||
//watch for the active culture changing, if it changes, update the current variant
|
||||
if (scope.variants) {
|
||||
if (scope.content.variants) {
|
||||
scope.$watch(function () {
|
||||
for (var i = 0; i < scope.variants.length; i++) {
|
||||
var v = scope.variants[i];
|
||||
for (var i = 0; i < scope.content.variants.length; i++) {
|
||||
var v = scope.content.variants[i];
|
||||
if (v.active) {
|
||||
return v.language.culture;
|
||||
}
|
||||
@@ -100,11 +115,11 @@
|
||||
nameDisabled: "<?",
|
||||
menu: "=",
|
||||
hideMenu: "<?",
|
||||
variants: "=",
|
||||
content: "=",
|
||||
openVariants: "<",
|
||||
hideChangeVariant: "<?",
|
||||
navigation: "=",
|
||||
onSelectNavigationItem: "&?",
|
||||
onSelectAnchorItem: "&?",
|
||||
showBackButton: "<?",
|
||||
splitViewOpen: "=?",
|
||||
onOpenInSplitView: "&?",
|
||||
|
||||
@@ -17,14 +17,24 @@
|
||||
name: "More"
|
||||
};
|
||||
|
||||
scope.clickNavigationItem = function (selectedItem) {
|
||||
scope.openNavigationItem = function(item) {
|
||||
|
||||
scope.showDropdown = false;
|
||||
runItemAction(selectedItem);
|
||||
setItemToActive(selectedItem);
|
||||
runItemAction(item);
|
||||
setItemToActive(item);
|
||||
if(scope.onSelect) {
|
||||
scope.onSelect({"item": selectedItem});
|
||||
scope.onSelect({"item": item});
|
||||
}
|
||||
eventsService.emit("app.tabChange", item);
|
||||
};
|
||||
|
||||
scope.openAnchorItem = function(item, anchor) {
|
||||
if(scope.onAnchorSelect) {
|
||||
scope.onAnchorSelect({"item": item, "anchor": anchor});
|
||||
}
|
||||
if (item.active !== true) {
|
||||
scope.openNavigationItem(item);
|
||||
}
|
||||
eventsService.emit("app.tabChange", selectedItem);
|
||||
};
|
||||
|
||||
scope.toggleDropdown = function () {
|
||||
@@ -128,7 +138,8 @@
|
||||
templateUrl: 'views/components/editor/umb-editor-navigation.html',
|
||||
scope: {
|
||||
navigation: "=",
|
||||
onSelect: "&"
|
||||
onSelect: "&",
|
||||
onAnchorSelect: "&"
|
||||
},
|
||||
link: link
|
||||
};
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function UmbEditorNavigationItemController($scope, $element, $attrs) {
|
||||
|
||||
var vm = this;
|
||||
|
||||
vm.clicked = function() {
|
||||
vm.onOpen({item:vm.item});
|
||||
};
|
||||
|
||||
vm.anchorClicked = function(anchor, $event) {
|
||||
vm.onOpenAnchor({item:vm.item, anchor:anchor});
|
||||
$event.stopPropagation();
|
||||
$event.preventDefault();
|
||||
};
|
||||
|
||||
// needed to make sure that we update what anchors are active.
|
||||
vm.mouseOver = function() {
|
||||
$scope.$digest();
|
||||
}
|
||||
|
||||
var componentNode = $element[0];
|
||||
|
||||
componentNode.classList.add('umb-sub-views-nav-item');
|
||||
componentNode.addEventListener('mouseover', vm.mouseOver);
|
||||
|
||||
//ensure to unregister from all dom-events
|
||||
$scope.$on('$destroy', function () {
|
||||
componentNode.removeEventListener("mouseover", vm.mouseOver);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
angular
|
||||
.module('umbraco.directives.html')
|
||||
.component('umbEditorNavigationItem', {
|
||||
templateUrl: 'views/components/editor/umb-editor-navigation-item.html',
|
||||
controller: UmbEditorNavigationItemController,
|
||||
controllerAs: 'vm',
|
||||
bindings: {
|
||||
item: '=',
|
||||
onOpen: '&',
|
||||
onOpenAnchor: '&',
|
||||
index: '@'
|
||||
}
|
||||
});
|
||||
|
||||
})();
|
||||
@@ -29,6 +29,8 @@
|
||||
let typeahead;
|
||||
let tagsHound;
|
||||
|
||||
let initLoad = true;
|
||||
|
||||
vm.$onInit = onInit;
|
||||
vm.$onChanges = onChanges;
|
||||
vm.$onDestroy = onDestroy;
|
||||
@@ -53,7 +55,7 @@
|
||||
vm.isLoading = false;
|
||||
|
||||
//ensure that the models are formatted correctly
|
||||
configureViewModel();
|
||||
configureViewModel(true);
|
||||
|
||||
// Set the visible prompt to -1 to ensure it will not be visible
|
||||
vm.promptIsVisible = "-1";
|
||||
@@ -139,8 +141,7 @@
|
||||
if (!changes.value.isFirstChange() && changes.value.currentValue !== changes.value.previousValue) {
|
||||
|
||||
configureViewModel();
|
||||
reValidate()
|
||||
|
||||
reValidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -154,13 +155,19 @@
|
||||
$element.find('.tags-' + vm.htmlId).typeahead('destroy');
|
||||
}
|
||||
|
||||
function configureViewModel() {
|
||||
function configureViewModel(isInitLoad) {
|
||||
if (vm.value) {
|
||||
if (angular.isString(vm.value) && vm.value.length > 0) {
|
||||
if (vm.config.storageType === "Json") {
|
||||
//json storage
|
||||
vm.viewModel = JSON.parse(vm.value);
|
||||
updateModelValue(vm.viewModel);
|
||||
|
||||
//if this is the first load, we are just re-formatting the underlying model to be consistent
|
||||
//we don't want to notify the component parent of any changes, that will occur if the user actually
|
||||
//changes a value. If we notify at this point it will signal a form dirty change which we don't want.
|
||||
if (!isInitLoad) {
|
||||
updateModelValue(vm.viewModel);
|
||||
}
|
||||
}
|
||||
else {
|
||||
//csv storage
|
||||
@@ -174,8 +181,12 @@
|
||||
return self.indexOf(v) === i;
|
||||
});
|
||||
|
||||
updateModelValue(vm.viewModel);
|
||||
|
||||
//if this is the first load, we are just re-formatting the underlying model to be consistent
|
||||
//we don't want to notify the component parent of any changes, that will occur if the user actually
|
||||
//changes a value. If we notify at this point it will signal a form dirty change which we don't want.
|
||||
if (!isInitLoad) {
|
||||
updateModelValue(vm.viewModel);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (angular.isArray(vm.value)) {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
bindings: {
|
||||
layouts: '<',
|
||||
activeLayout: '<',
|
||||
onLayoutSelect: "&"
|
||||
onLayoutSelect: '&'
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
angular.module("umbraco.directives").directive("retriveDomElement", function () {
|
||||
var directiveDefinitionObject = {
|
||||
|
||||
restrict: "A",
|
||||
selector: '[retriveDomElement]',
|
||||
scope: {
|
||||
"retriveDomElement": "&"
|
||||
},
|
||||
link: {
|
||||
post: function(scope, iElement, iAttrs, controller) {
|
||||
scope.retriveDomElement({element:iElement, attributes: iAttrs});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return directiveDefinitionObject;
|
||||
});
|
||||
@@ -26,7 +26,9 @@
|
||||
//dealing with requests:
|
||||
'request': function(config) {
|
||||
if(config.method === "POST"){
|
||||
transform(config.data);
|
||||
var clone = angular.copy(config);
|
||||
transform(clone.data);
|
||||
return clone;
|
||||
}
|
||||
|
||||
return config;
|
||||
|
||||
@@ -161,6 +161,10 @@ function umbRequestHelper($http, $q, notificationsService, eventsService, formHe
|
||||
|
||||
}, function (response) {
|
||||
|
||||
if (!response) {
|
||||
return; //sometimes oddly this happens, nothing we can do
|
||||
}
|
||||
|
||||
if (!response.status && response.message && response.stack) {
|
||||
//this is a JS/angular error that we should deal with
|
||||
return $q.reject({
|
||||
|
||||
@@ -91,6 +91,7 @@
|
||||
@import "components/application/umb-dashboard.less";
|
||||
|
||||
@import "components/html/umb-expansion-panel.less";
|
||||
@import "components/html/umb-group-panel.less";
|
||||
@import "components/html/umb-alert.less";
|
||||
|
||||
@import "components/tree/umb-tree.less";
|
||||
@@ -105,6 +106,7 @@
|
||||
@import "components/editor/umb-editor.less";
|
||||
@import "components/umb-sub-views.less";
|
||||
@import "components/umb-editor-navigation.less";
|
||||
@import "components/umb-editor-navigation-item.less";
|
||||
@import "components/umb-editor-sub-views.less";
|
||||
@import "components/editor/subheader/umb-editor-sub-header.less";
|
||||
@import "components/umb-flatpickr.less";
|
||||
|
||||
@@ -191,13 +191,13 @@ input[type="button"] {
|
||||
.btn-success {
|
||||
.buttonBackground(@btnSuccessBackground, @btnSuccessBackgroundHighlight, @btnSuccessType);
|
||||
}
|
||||
// Info appears as a neutral blue
|
||||
// Info appears as a sand color
|
||||
.btn-info {
|
||||
.buttonBackground(@sand-5, @blueDark, @blueExtraDark, @u-white);
|
||||
.buttonBackground(@sand-5, @sand-6, @blueExtraDark, @blueMid);
|
||||
}
|
||||
// Made for Umbraco, 2019
|
||||
.btn-action {
|
||||
.buttonBackground(@blueExtraDark, @blueDark, @pinkLight, @u-white);
|
||||
.buttonBackground(@blueExtraDark, @blueDark, @white, @u-white);
|
||||
}
|
||||
// Made for Umbraco, 2019
|
||||
.btn-selection {
|
||||
@@ -236,11 +236,11 @@ input[type="button"] {
|
||||
padding: 15px 50px;
|
||||
font-size: 16px;
|
||||
border: none;
|
||||
background: @green;
|
||||
background: @ui-btn-positive;
|
||||
color: @white;
|
||||
font-weight: bold;
|
||||
&:hover {
|
||||
background: @green-d1;
|
||||
background: @ui-btn-positive-hover;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -176,6 +176,7 @@ a, a:hover{
|
||||
|
||||
.dropdown-menu {
|
||||
position: absolute;
|
||||
display: block;
|
||||
top: auto;
|
||||
right: 0;
|
||||
z-index: 1000;
|
||||
|
||||
@@ -15,6 +15,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
.umb-editor-sub-header.--state-selection {
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
background-color: @pinkLight;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.umb-editor-sub-header.-umb-sticky-bar {
|
||||
box-shadow: 0 6px 3px -3px rgba(0,0,0,.16);
|
||||
transition: box-shadow 1s;
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
.umb-group-panel {
|
||||
background: @white;
|
||||
border-radius: 3px;
|
||||
margin-bottom: 16px;
|
||||
box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.16);
|
||||
}
|
||||
|
||||
.umb-group-panel__header {
|
||||
padding: 10px 20px;
|
||||
font-weight: bold;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
color: @black;
|
||||
}
|
||||
|
||||
.umb-group-panel__content {
|
||||
padding: 20px;
|
||||
border-top: 1px solid @gray-9;
|
||||
}
|
||||
@@ -232,43 +232,40 @@ body.touch .umb-tree {
|
||||
}
|
||||
}
|
||||
|
||||
.protected,
|
||||
.has-unpublished-version,
|
||||
.is-container,
|
||||
.locked {
|
||||
.umb-tree-item__annotation {
|
||||
&::before {
|
||||
font-family: 'icomoon';
|
||||
position: absolute;
|
||||
font-size: 20px;
|
||||
padding-left: 7px;
|
||||
padding-top: 7px;
|
||||
bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.protected::before {
|
||||
content: "\e256";
|
||||
color: @red;
|
||||
}
|
||||
|
||||
.has-unpublished-version::before {
|
||||
.has-unpublished-version > .umb-tree-item__inner > .umb-tree-item__annotation::before {
|
||||
content: "\e25a";
|
||||
color: @green;
|
||||
font-size: 20px;
|
||||
margin-left: -25px;
|
||||
}
|
||||
|
||||
.is-container::before {
|
||||
.is-container > .umb-tree-item__inner > .umb-tree-item__annotation::before {
|
||||
content: "\e04e";
|
||||
color: @blue;
|
||||
font-size: 8px;
|
||||
padding-left: 13px;
|
||||
padding-top: 8px;
|
||||
pointer-events: none;
|
||||
font-size: 9px;
|
||||
margin-left: -20px;
|
||||
}
|
||||
|
||||
.protected > .umb-tree-item__inner > .umb-tree-item__annotation::before {
|
||||
content: "\e256";
|
||||
color: @red;
|
||||
font-size: 20px;
|
||||
margin-left: -25px;
|
||||
}
|
||||
|
||||
.locked::before {
|
||||
.locked > .umb-tree-item__inner > .umb-tree-item__annotation::before {
|
||||
content: "\e0a7";
|
||||
color: @red;
|
||||
font-size: 9px;
|
||||
margin-left: -20px;
|
||||
}
|
||||
|
||||
.no-access {
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
.umb-sub-views-nav-item {
|
||||
position: relative;
|
||||
display: block;
|
||||
}
|
||||
.umb-sub-views-nav-item > a {
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
padding: 4px 10px 0 10px;
|
||||
min-width: 70px;
|
||||
border-right: 1px solid @gray-9;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: @editorHeaderHeight;
|
||||
position: relative;
|
||||
|
||||
color: @ui-active-type;
|
||||
|
||||
&:hover {
|
||||
color: @ui-active-type-hover !important;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
height: 0px;
|
||||
left: 8px;
|
||||
right: 8px;
|
||||
background-color: @ui-light-active-border;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
border-radius: 3px 3px 0 0;
|
||||
opacity: 0;
|
||||
transition: all .2s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-sub-views-nav-item > a:active {
|
||||
.box-shadow(~"inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05)");
|
||||
}
|
||||
.umb-sub-views-nav-item > a:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.umb-sub-views-nav-item > a:hover,
|
||||
.umb-sub-views-nav-item > a:focus {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.umb-sub-views-nav-item > a.is-active {
|
||||
|
||||
color: @ui-light-active-type;
|
||||
|
||||
&::after {
|
||||
opacity: 1;
|
||||
height: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.show-validation .umb-sub-views-nav-item > a.-has-error {
|
||||
color: @red;
|
||||
}
|
||||
|
||||
.umb-sub-views-nav-item .icon {
|
||||
font-size: 24px;
|
||||
display: block;
|
||||
text-align: center;
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
.umb-sub-views-nav-item .badge {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 6px;
|
||||
min-width: 16px;
|
||||
color: @white;
|
||||
background-color: @ui-active-type;
|
||||
border: 2px solid @white;
|
||||
border-radius: 50%;
|
||||
font-size: 10px;
|
||||
font-weight: bold;
|
||||
padding: 2px;
|
||||
line-height: 16px;
|
||||
display: block;
|
||||
|
||||
&.-type-alert {
|
||||
background-color: @red;
|
||||
}
|
||||
&.-type-warning {
|
||||
background-color: @yellow-d2;
|
||||
}
|
||||
&:empty {
|
||||
height: 12px;
|
||||
min-width: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-sub-views-nav-item-text {
|
||||
font-size: 12px;
|
||||
line-height: 1em;
|
||||
}
|
||||
|
||||
|
||||
.umb-sub-views-nav-item__anchor_dropdown {// inherits from .dropdown-menu
|
||||
display: block;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
|
||||
// center align horizontal
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
|
||||
visibility:hidden;
|
||||
opacity: 0;
|
||||
transition: visibility 0s 500ms, opacity 250ms 250ms;
|
||||
}
|
||||
.umb-sub-views-nav-item__anchor_dropdown li a {
|
||||
border-left: 4px solid transparent;
|
||||
}
|
||||
.umb-sub-views-nav-item__anchor_dropdown li.is-active a {
|
||||
border-left-color: @ui-selected-border;
|
||||
}
|
||||
|
||||
.umb-sub-views-nav-item:hover .umb-sub-views-nav-item__anchor_dropdown {
|
||||
visibility:visible;
|
||||
opacity: 1;
|
||||
transition: visibility 0s 0s, opacity 20ms 0s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// --------------------------------
|
||||
// item__more, appears when there is not enough room for the visible items.
|
||||
// --------------------------------
|
||||
|
||||
.umb-sub-views-nav-item-more__icon {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.umb-sub-views-nav-item-more__icon i {
|
||||
height: 5px;
|
||||
width: 5px;
|
||||
border-radius: 50%;
|
||||
background: @ui-active-type;// fallback if browser doesnt support currentColor
|
||||
background: currentColor;
|
||||
display: inline-block;
|
||||
margin: 0 5px 0 0;
|
||||
}
|
||||
|
||||
.umb-sub-views-nav-item-more__icon i:last-of-type {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.umb-sub-views-nav-item-more__dropdown {
|
||||
left: auto;
|
||||
right: 0;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
min-width: auto;
|
||||
margin-top: 10px;
|
||||
}
|
||||
.umb-sub-views-nav-item-more__dropdown > li {
|
||||
display: flex;
|
||||
}
|
||||
.umb-sub-views-nav-item-more__dropdown .umb-sub-views-nav-item:first {
|
||||
border-left: none;
|
||||
}
|
||||
@@ -4,135 +4,3 @@
|
||||
margin: 0;
|
||||
border-left: 1px solid @gray-9;
|
||||
}
|
||||
|
||||
.umb-sub-views-nav-item {
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
padding: 4px 10px 0 10px;
|
||||
//border-bottom: 4px solid transparent;
|
||||
min-width: 70px;
|
||||
border-right: 1px solid @gray-9;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
height: @editorHeaderHeight;
|
||||
position: relative;
|
||||
|
||||
color: @ui-active-type;
|
||||
|
||||
&:hover {
|
||||
color: @ui-active-type-hover !important;
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: "";
|
||||
height: 0px;
|
||||
left: 8px;
|
||||
right: 8px;
|
||||
background-color: @ui-light-active-border;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
border-radius: 3px 3px 0 0;
|
||||
opacity: 0;
|
||||
transition: all .2s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-sub-views-nav-item:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.umb-sub-views-nav-item:hover,
|
||||
.umb-sub-views-nav-item:focus {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.umb-sub-views-nav-item.is-active {
|
||||
//color: @ui-active;
|
||||
//border-bottom-color: @ui-active;
|
||||
|
||||
//background-color: rgba(@ui-active, 0.25);
|
||||
color: @ui-light-active-type;
|
||||
//border-bottom-color: @ui-active;
|
||||
&::after {
|
||||
opacity: 1;
|
||||
height: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.show-validation .umb-sub-views-nav-item.-has-error {
|
||||
color: @red;
|
||||
}
|
||||
|
||||
.umb-sub-views-nav-item .icon {
|
||||
font-size: 24px;
|
||||
display: block;
|
||||
text-align: center;
|
||||
margin-bottom: 7px;
|
||||
}
|
||||
|
||||
.umb-sub-views-nav-item .badge {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
right: 6px;
|
||||
min-width: 16px;
|
||||
color: @white;
|
||||
background-color: @ui-active-type;
|
||||
border: 2px solid @white;
|
||||
border-radius: 50%;
|
||||
font-size: 10px;
|
||||
font-weight: bold;
|
||||
padding: 2px;
|
||||
line-height: 16px;
|
||||
display: block;
|
||||
|
||||
&.-type-alert {
|
||||
background-color: @red;
|
||||
}
|
||||
&.-type-warning {
|
||||
background-color: @yellow-d2;
|
||||
}
|
||||
&:empty {
|
||||
height: 12px;
|
||||
min-width: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-sub-views-nav-item-text {
|
||||
font-size: 12px;
|
||||
line-height: 1em;
|
||||
}
|
||||
|
||||
.umb-sub-views-nav-item__more {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.umb-sub-views-nav-item__more i {
|
||||
height: 5px;
|
||||
width: 5px;
|
||||
border-radius: 50%;
|
||||
background: @gray-3;
|
||||
display: inline-block;
|
||||
margin: 0 5px 0 0;
|
||||
}
|
||||
|
||||
.umb-sub-views-nav-item__more i:last-of-type {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
// make dots green the an item is active
|
||||
.umb-sub-views-nav-item.is-active .umb-sub-views-nav-item__more i {
|
||||
background-color: @ui-active;
|
||||
}
|
||||
|
||||
.umb-sub-views-nav__dropdown.umb-sub-views-nav__dropdown {
|
||||
left: auto;
|
||||
right: 0;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
min-width: auto;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
box-sizing: border-box;
|
||||
max-width: 100%;
|
||||
display: flex;
|
||||
position: relative;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.umb-user-card:hover,
|
||||
@@ -15,6 +17,22 @@
|
||||
outline: none;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
.umb-user-card.-selected {
|
||||
&::before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
z-index:2;
|
||||
top: -2px;
|
||||
left: -2px;
|
||||
right: -2px;
|
||||
bottom: -2px;
|
||||
border: 2px solid @ui-selected-border;
|
||||
border-radius: 5px;
|
||||
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 {
|
||||
position: relative;
|
||||
@@ -30,9 +48,12 @@
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.umb-user-card__content:hover,
|
||||
.umb-user-card:focus .umb-user-card__content {
|
||||
border-color: @turquoise;
|
||||
.umb-user-card__goToUser {
|
||||
&:hover {
|
||||
.umb-user-card__name {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.umb-user-card__avatar {
|
||||
@@ -47,24 +68,13 @@
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
|
||||
.umb-user-card__name {
|
||||
font-size: 15px;
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-bottom: 2px;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.umb-user-card__checkmark {
|
||||
position: absolute;
|
||||
top: 10px;
|
||||
right: 10px;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.umb-user-card:hover .umb-user-card__checkmark,
|
||||
.umb-user-card__checkmark--visible {
|
||||
display: block;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
.umb-user-card__group {
|
||||
@@ -77,4 +87,4 @@
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
margin-top: auto;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -539,7 +539,7 @@
|
||||
|
||||
&.disabled, &[disabled] {
|
||||
color: @white;
|
||||
background-color: @sand-2;
|
||||
background-color: @sand-1;
|
||||
}
|
||||
/*
|
||||
// IE 7 + 8 can't handle box-shadow to show active, so we darken a bit ourselves
|
||||
|
||||
@@ -220,6 +220,7 @@
|
||||
// DROPDOWNS
|
||||
// ---------
|
||||
.dropdown-menu {
|
||||
display: block;
|
||||
border-radius: @dropdownBorderRadius;
|
||||
box-shadow: 0 5px 20px rgba(0,0,0,.3);
|
||||
padding-top: 0;
|
||||
|
||||
@@ -62,6 +62,15 @@ table {
|
||||
}
|
||||
|
||||
|
||||
.table tr > td:first-child {
|
||||
border-left: 4px solid transparent;
|
||||
}
|
||||
.table tr.--selected > td:first-child {
|
||||
border-left-color:@ui-selected-border;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// CONDENSED TABLE W/ HALF PADDING
|
||||
// -------------------------------
|
||||
|
||||
@@ -76,9 +76,10 @@
|
||||
@gray-10: #F3F3F5;
|
||||
@gray-11: #F6F6F7;
|
||||
|
||||
@sand-1: hsl(22, 33%, 93%);// added 2019
|
||||
@sand-1: hsl(22, 18%, 84%);// added 2019
|
||||
@sand-2: hsl(22, 34%, 88%);// added 2019
|
||||
@sand-5: hsl(22, 31%, 93%);// added 2019
|
||||
@sand-6: hsl(22, 29%, 95%);// added 2019
|
||||
@sand-7: hsl(22, 26%, 97%);// added 2019
|
||||
|
||||
|
||||
@@ -138,8 +139,8 @@
|
||||
@ui-active-type: @blueExtraDark;
|
||||
@ui-active-type-hover: @blueMid;
|
||||
|
||||
@ui-selected: @sand-1;
|
||||
@ui-selected-hover: ligthen(@sand-1, 10);
|
||||
@ui-selected: @sand-5;
|
||||
@ui-selected-hover: ligthen(@sand-5, 10);
|
||||
@ui-selected-type: @blueExtraDark;
|
||||
@ui-selected-type-hover: @blueMid;
|
||||
@ui-selected-border: @pinkLight;
|
||||
@@ -176,7 +177,7 @@
|
||||
@ui-btn-type: @white;
|
||||
|
||||
@ui-btn-positive: @green;
|
||||
@ui-btn-positive-hover: @green-l1;
|
||||
@ui-btn-positive-hover: lighten(@green, 6%);
|
||||
@ui-btn-positive-type: @white;
|
||||
|
||||
@ui-btn-negative: @red;
|
||||
|
||||
@@ -180,6 +180,7 @@
|
||||
button-style="success"
|
||||
label="Select image"
|
||||
type="button"
|
||||
disabled="model.selection.length === 0"
|
||||
action="submit(model)">
|
||||
</umb-button>
|
||||
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
page="page"
|
||||
content="content"
|
||||
culture="culture"
|
||||
on-select-app="appChanged(app)">
|
||||
on-select-app="appChanged(app)"
|
||||
on-select-app-anchor="appAnchorChanged(app, anchor)">
|
||||
</umb-variant-content-editors>
|
||||
|
||||
<umb-editor-footer>
|
||||
|
||||
@@ -1,16 +1,15 @@
|
||||
<div>
|
||||
<ng-form name="tabbedContentForm">
|
||||
<div class="umb-expansion-panel" data-element="group-{{group.alias}}" ng-repeat="group in content.tabs track by group.label">
|
||||
<div class="umb-group-panel" retrive-dom-element="registerPropertyGroup(element[0], attributes.appAnchor)" data-app-anchor="{{group.id}}" data-element="group-{{group.alias}}" ng-repeat="group in content.tabs track by group.label">
|
||||
|
||||
<div class="umb-expansion-panel__header" ng-click="group.open = !group.open">
|
||||
<div class="umb-group-panel__header">
|
||||
<div>{{ group.label }}</div>
|
||||
<ins class="umb-expansion-panel__expand" ng-class="{'icon-navigation-down': !group.open, 'icon-navigation-up': group.open}"> </ins>
|
||||
</div>
|
||||
|
||||
<div class="umb-expansion-panel__content" ng-show="group.open">
|
||||
<umb-property
|
||||
data-element="property-{{property.alias}}"
|
||||
ng-repeat="property in group.properties track by property.alias"
|
||||
<div class="umb-group-panel__content">
|
||||
<umb-property
|
||||
data-element="property-{{property.alias}}"
|
||||
ng-repeat="property in group.properties track by property.alias"
|
||||
property="property"
|
||||
show-inherit="content.variants.length > 1 && !property.culture && !activeVariant.language.isDefault"
|
||||
inherits-from="defaultVariant.language.name">
|
||||
|
||||
@@ -13,7 +13,8 @@
|
||||
on-open-split-view="vm.openSplitView(variant)"
|
||||
on-close-split-view="vm.closeSplitView($index)"
|
||||
on-select-variant="vm.selectVariant(variant, $index)"
|
||||
on-select-app="vm.selectApp(app)">
|
||||
on-select-app="vm.selectApp(app)"
|
||||
on-select-app-anchor="vm.selectAppAnchor(app, anchor)">
|
||||
</umb-variant-content>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
<div>
|
||||
<umb-load-indicator
|
||||
<umb-load-indicator
|
||||
ng-if="vm.editor.loading">
|
||||
</umb-load-indicator>
|
||||
|
||||
<div class="umb-split-view__content" ng-show="!vm.editor.loading">
|
||||
|
||||
<ng-form name="contentHeaderForm">
|
||||
<umb-editor-content-header
|
||||
<umb-editor-content-header
|
||||
menu="vm.page.menu"
|
||||
hide-menu="vm.page.hideActionsMenu"
|
||||
name="vm.editor.content.name"
|
||||
name-disabled="vm.nameDisabled"
|
||||
navigation="vm.editor.content.apps"
|
||||
content="vm.editor.content"
|
||||
on-select-navigation-item="vm.selectApp(item)"
|
||||
variants="vm.editor.content.variants"
|
||||
on-select-anchor-item="vm.selectAppAnchor(item, anchor)"
|
||||
open-variants="vm.openVariants"
|
||||
hide-change-variant="vm.page.hideChangeVariant"
|
||||
show-back-button="vm.page.listViewPath !== null"
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
autocomplete="off" />
|
||||
</ng-form>
|
||||
|
||||
<a ng-if="variants.length > 0 && hideChangeVariant !== true" class="umb-variant-switcher__toggle" href="" ng-click="vm.dropdownOpen = !vm.dropdownOpen">
|
||||
<a ng-if="content.variants.length > 0 && hideChangeVariant !== true" class="umb-variant-switcher__toggle" href="" ng-click="vm.dropdownOpen = !vm.dropdownOpen">
|
||||
<span>{{vm.currentVariant.language.name}}</span>
|
||||
<ins class="umb-variant-switcher__expand" ng-class="{'icon-navigation-down': !vm.dropdownOpen, 'icon-navigation-up': vm.dropdownOpen}"> </ins>
|
||||
</a>
|
||||
@@ -39,7 +39,7 @@
|
||||
</span>
|
||||
|
||||
<umb-dropdown ng-if="vm.dropdownOpen" style="width: 100%; max-height: 250px; overflow-y: scroll; margin-top: 5px;" on-close="vm.dropdownOpen = false" umb-keyboard-list>
|
||||
<umb-dropdown-item class="umb-variant-switcher__item" ng-class="{'umb-variant-switcher_item--current': variant.active, 'umb-variant-switcher_item--not-allowed': variantIsOpen(variant.language.culture)}" ng-repeat="variant in variants">
|
||||
<umb-dropdown-item class="umb-variant-switcher__item" ng-class="{'umb-variant-switcher_item--current': variant.active, 'umb-variant-switcher_item--not-allowed': variantIsOpen(variant.language.culture)}" ng-repeat="variant in content.variants">
|
||||
<a href="" class="umb-variant-switcher__name-wrapper" ng-click="selectVariant($event, variant)" prevent-default>
|
||||
<span class="umb-variant-switcher__name" ng-class="{'bold': variant.language.isDefault}">{{variant.language.name}}</span>
|
||||
<umb-variant-state variant="variant" class="umb-variant-switcher__state"></umb-variant-state>
|
||||
@@ -60,11 +60,12 @@
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div ng-if="navigation && splitViewOpen !== true" style="margin-left: 20px;">
|
||||
<div ng-if="content.apps && splitViewOpen !== true" style="margin-left: 20px;">
|
||||
<umb-editor-navigation
|
||||
data-element="editor-sub-views"
|
||||
navigation="navigation"
|
||||
on-select="selectNavigationItem(item)">
|
||||
navigation="content.apps"
|
||||
on-select="selectNavigationItem(item)"
|
||||
on-anchor-select="selectAnchorItem(item, anchor)">
|
||||
</umb-editor-navigation>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
<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}">
|
||||
<i class="icon {{ vm.item.icon }}"></i>
|
||||
<span class="umb-sub-views-nav-item-text">{{ vm.item.name }}</span>
|
||||
<div ng-show="item.badge" class="badge -type-{{vm.item.badge.type}}">{{vm.item.badge.count}}</div>
|
||||
</a>
|
||||
|
||||
<ul class="dropdown-menu umb-sub-views-nav-item__anchor_dropdown" ng-class="{'show': vm.showDropdown}">
|
||||
<li ng-repeat="anchor in vm.item.anchors" ng-class="{'is-active': vm.item.active && anchor.active}">
|
||||
<a href="" ng-click="vm.anchorClicked(anchor, $event)">
|
||||
{{anchor.label}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -1,46 +1,41 @@
|
||||
<ul class="umb-sub-views-nav" ng-show="showNavigation">
|
||||
|
||||
<li ng-repeat="item in navigation | limitTo: itemsLimit ">
|
||||
<div ng-show="item.alias !== 'more'"
|
||||
ng-class="item.errorClass">
|
||||
<a data-element="sub-view-{{item.alias}}"
|
||||
tabindex="-1"
|
||||
class="umb-sub-views-nav-item js-umb-sub-views-nav-item"
|
||||
href=""
|
||||
ng-click="clickNavigationItem(item, $index)"
|
||||
hotkey="{{$index+1}}"
|
||||
ng-class="{'is-active': item.active, '-has-error': item.hasError}">
|
||||
<i class="icon {{ item.icon }}"></i>
|
||||
<span class="umb-sub-views-nav-item-text">{{ item.name }}</span>
|
||||
<div ng-show="item.badge" class="badge -type-{{item.badge.type}}">{{item.badge.count}}</div>
|
||||
</a>
|
||||
<li ng-repeat="navItem in navigation | limitTo: itemsLimit ">
|
||||
<div ng-show="navItem.alias !== 'more'"
|
||||
ng-class="navItem.errorClass">
|
||||
<umb-editor-navigation-item
|
||||
item="navItem"
|
||||
on-open="openNavigationItem(item)"
|
||||
on-open-anchor="openAnchorItem(item, anchor)"
|
||||
index="{{$index}}">
|
||||
</umb-editor-navigation-item>
|
||||
</div>
|
||||
</li>
|
||||
|
||||
<li ng-show="showMoreButton" style="position: relative;">
|
||||
|
||||
<a data-element="sub-view-{{moreButton.alias}}"
|
||||
class="umb-sub-views-nav-item"
|
||||
href=""
|
||||
ng-click="toggleDropdown()"
|
||||
ng-class="{'is-active': moreButton.active}">
|
||||
<div class="umb-sub-views-nav-item__more"><i></i><i></i><i></i></div>
|
||||
<span class="umb-sub-views-nav-item-text">{{ moreButton.name }}</span>
|
||||
</a>
|
||||
<div class="umb-sub-views-nav-item umb-sub-views-nav-item-more">
|
||||
|
||||
<umb-dropdown ng-show="showDropdown" on-close="hideDropdown()" class="umb-sub-views-nav__dropdown">
|
||||
<umb-dropdown-item ng-repeat="item in navigation | limitTo: overflowingItems">
|
||||
<a data-element="sub-view-{{item.alias}}"
|
||||
style="display: flex; border: none;"
|
||||
class="umb-sub-views-nav-item"
|
||||
ng-href=""
|
||||
ng-click="clickNavigationItem(item, $index)"
|
||||
ng-class="{'is-active': item.active, '-has-error': item.hasError}">
|
||||
<i class="icon {{ item.icon }}"></i>
|
||||
<span class="umb-sub-views-nav-item-text">{{ item.name }}</span>
|
||||
</a>
|
||||
</umb-dropdown-item>
|
||||
</umb-dropdown>
|
||||
<a data-element="sub-view-{{moreButton.alias}}"
|
||||
href=""
|
||||
ng-click="toggleDropdown()"
|
||||
ng-class="{'is-active': moreButton.active}">
|
||||
<div class="umb-sub-views-nav-item-more__icon"><i></i><i></i><i></i></div>
|
||||
<span class="umb-sub-views-nav-item-text">{{ moreButton.name }}</span>
|
||||
</a>
|
||||
|
||||
<umb-dropdown ng-show="showDropdown" on-close="hideDropdown()" class="umb-sub-views-nav-item-more__dropdown">
|
||||
<umb-dropdown-item ng-repeat="navItem in navigation | limitTo: overflowingItems">
|
||||
<umb-editor-navigation-item
|
||||
item="navItem"
|
||||
on-open="openNavigationItem(item)"
|
||||
on-open-anchor="openAnchorItem(item, anchor)"
|
||||
index="{{$index}}">
|
||||
</umb-editor-navigation-item>
|
||||
</umb-dropdown-item>
|
||||
</umb-dropdown>
|
||||
|
||||
</div>
|
||||
|
||||
</li>
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
<li class="umb-tree-item" data-element="tree-item-{{::node.dataElement}}" ng-class="getNodeCssClass(node)" on-right-click="altSelect(node, $event)">
|
||||
<div class="umb-tree-item__inner" ng-swipe-right="options(node, $event)" ng-dblclick="load(node)" >
|
||||
<ins data-element="tree-item-expand"
|
||||
ng-class="{'icon-navigation-right': !node.expanded || node.metaData.isContainer, 'icon-navigation-down': node.expanded && !node.metaData.isContainer}"
|
||||
ng-style="{'visibility': (scope.enablelistviewexpand === 'true' || node.hasChildren && (!node.metaData.isContainer || isDialog)) ? 'visible' : 'hidden'}"
|
||||
ng-click="load(node)"> </ins>
|
||||
ng-class="{'icon-navigation-right': !node.expanded || node.metaData.isContainer, 'icon-navigation-down': node.expanded && !node.metaData.isContainer}"
|
||||
ng-style="{'visibility': (scope.enablelistviewexpand === 'true' || node.hasChildren && (!node.metaData.isContainer || isDialog)) ? 'visible' : 'hidden'}"
|
||||
ng-click="load(node)"> </ins>
|
||||
|
||||
<i class="icon umb-tree-icon sprTree" ng-class="::node.cssClass" title="{{::node.routePath}}" ng-click="select(node, $event)" ng-style="::node.style"></i>
|
||||
<span class="umb-tree-item__annotation"></span>
|
||||
<a class="umb-tree-item__label" ng-href="#/{{::node.routePath}}" ng-click="select(node, $event)">{{node.name}}</a>
|
||||
|
||||
<!-- NOTE: These are the 'option' elipses -->
|
||||
|
||||
@@ -1 +1 @@
|
||||
<ul class="dropdown-menu db" on-outside-click="close()" ng-transclude></ul>
|
||||
<ul class="dropdown-menu" on-outside-click="close()" ng-transclude></ul>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
class="umb-layout-selector__dropdown shadow-depth-3 animated -half-second fadeIn"
|
||||
on-outside-click="vm.closeLayoutDropdown()">
|
||||
|
||||
<div ng-repeat="layout in vm.layouts | filter:{selected:true} track by layout.name"
|
||||
<div ng-repeat="layout in vm.layouts | filter:{selected:true} track by $id(layout)"
|
||||
class="umb-layout-selector__dropdown-item"
|
||||
ng-click="vm.pickLayout(layout)"
|
||||
ng-class="{'-active': layout.active }"
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<!--<i ng-show="item.selected" class="icon-check umb-media-grid__checkmark"></i>-->
|
||||
<a ng-if="allowOnClickEdit === 'true'" ng-click="clickEdit(item, $event)" ng-href="" class="icon-edit umb-media-grid__edit"></a>
|
||||
|
||||
<div data-element="media-grid-item-edit" class="umb-media-grid__item-overlay" ng-class="{'-locked': item.selected}" ng-click="clickItemName(item, $event, $index)">
|
||||
<div data-element="media-grid-item-edit" class="umb-media-grid__item-overlay" ng-class="{'-locked': item.selected || !item.file}" ng-click="clickItemName(item, $event, $index)">
|
||||
<i ng-if="onDetailsHover" class="icon-info umb-media-grid__info" ng-mouseover="hoverItemDetails(item, $event, true)" ng-mouseleave="hoverItemDetails(item, $event, false)"></i>
|
||||
<div class="umb-media-grid__item-name">{{item.name}}</div>
|
||||
</div>
|
||||
|
||||
@@ -192,7 +192,6 @@ function FormsController($scope, $route, $cookies, packageResource, localization
|
||||
function Video_player (videoId) {
|
||||
// Get dom elements
|
||||
this.container = document.getElementById(videoId);
|
||||
this.video = this.container.getElementsByTagName('video')[0];
|
||||
|
||||
//Create controls
|
||||
this.controls = document.createElement('div');
|
||||
@@ -215,104 +214,6 @@ function FormsController($scope, $route, $cookies, packageResource, localization
|
||||
this.controls.appendChild(this.loader);
|
||||
this.loader.appendChild(this.progress_bar);
|
||||
}
|
||||
|
||||
|
||||
Video_player.prototype
|
||||
.seeking = function() {
|
||||
// get the value of the seekbar (hidden input[type="range"])
|
||||
var time = this.video.duration * (this.seek_bar.value / 100);
|
||||
|
||||
// Update video to seekbar value
|
||||
this.video.currentTime = time;
|
||||
};
|
||||
|
||||
// Stop video when user initiates seeking
|
||||
Video_player.prototype
|
||||
.start_seek = function() {
|
||||
this.video.pause();
|
||||
};
|
||||
|
||||
// Start video when user stops seeking
|
||||
Video_player.prototype
|
||||
.stop_seek = function() {
|
||||
this.video.play();
|
||||
};
|
||||
|
||||
// Update the progressbar (span.loader) according to video.currentTime
|
||||
Video_player.prototype
|
||||
.update_progress_bar = function() {
|
||||
// Get video progress in %
|
||||
var value = (100 / this.video.duration) * this.video.currentTime;
|
||||
|
||||
// Update progressbar
|
||||
this.progress_bar.style.width = value + '%';
|
||||
};
|
||||
|
||||
// Bind progressbar to mouse when seeking
|
||||
Video_player.prototype
|
||||
.handle_mouse_move = function(event) {
|
||||
// Get position of progressbar relative to browser window
|
||||
var pos = this.progress_bar.getBoundingClientRect().left;
|
||||
|
||||
// Make sure event is reckonized cross-browser
|
||||
event = event || window.event;
|
||||
|
||||
// Update progressbar
|
||||
this.progress_bar.style.width = (event.clientX - pos) + "px";
|
||||
};
|
||||
|
||||
// Eventlisteners for seeking
|
||||
Video_player.prototype
|
||||
.video_event_handler = function(videoPlayer, interval) {
|
||||
// Update the progress bar
|
||||
var animate_progress_bar = setInterval(function () {
|
||||
videoPlayer.update_progress_bar();
|
||||
}, interval);
|
||||
|
||||
// Fire when input value changes (user seeking)
|
||||
videoPlayer.seek_bar
|
||||
.addEventListener("change", function() {
|
||||
videoPlayer.seeking();
|
||||
});
|
||||
|
||||
// Fire when user clicks on seekbar
|
||||
videoPlayer.seek_bar
|
||||
.addEventListener("mousedown", function (clickEvent) {
|
||||
// Pause video playback
|
||||
videoPlayer.start_seek();
|
||||
|
||||
// Stop updating progressbar according to video progress
|
||||
clearInterval(animate_progress_bar);
|
||||
|
||||
// Update progressbar to where user clicks
|
||||
videoPlayer.handle_mouse_move(clickEvent);
|
||||
|
||||
// Bind progressbar to cursor
|
||||
window.onmousemove = function(moveEvent){
|
||||
videoPlayer.handle_mouse_move(moveEvent);
|
||||
};
|
||||
});
|
||||
|
||||
// Fire when user releases seekbar
|
||||
videoPlayer.seek_bar
|
||||
.addEventListener("mouseup", function () {
|
||||
|
||||
// Unbind progressbar from cursor
|
||||
window.onmousemove = null;
|
||||
|
||||
// Start video playback
|
||||
videoPlayer.stop_seek();
|
||||
|
||||
// Animate the progressbar
|
||||
animate_progress_bar = setInterval(function () {
|
||||
videoPlayer.update_progress_bar();
|
||||
}, interval);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
var videoPlayer = new Video_player('video_1');
|
||||
videoPlayer.video_event_handler(videoPlayer, 17);
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.Dashboard.FormsDashboardController", FormsController);
|
||||
|
||||
@@ -8,14 +8,6 @@
|
||||
|
||||
<div class="step-one" ng-hide="state"> <!-- STEP one -->
|
||||
|
||||
<div id="video_1" class="video_player" style="margin-bottom: 40px">
|
||||
<video autoplay loop>
|
||||
<!-- <source src="videos/gif.webm" type="video/webm"> -->
|
||||
<source src="https://player.vimeo.com/external/110229004.hd.mp4?s=823f701836260bd08fb783d38389f628" type="video/mp4">
|
||||
Sorry, you don't have HTML5 video and we didn't catch this properly in javascript.
|
||||
</video>
|
||||
</div>
|
||||
|
||||
<p style="font-size: 16px; line-height: 1.5; color: #4c4c4c; margin-bottom: 20px;">Create forms using an intuitive drag and drop interface. From simple contact forms that sends e-mails to advanced questionaires that integrate with CRM systems. Your clients will love it!</p>
|
||||
|
||||
<umb-button
|
||||
|
||||
@@ -24,13 +24,13 @@
|
||||
<div>{{ group.label }}</div>
|
||||
<ins class="umb-expansion-panel__expand" ng-class="{'icon-navigation-down': !group.open, 'icon-navigation-up': group.open}" class="icon-navigation-right"> </ins>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="umb-expansion-panel__content" ng-show="group.open">
|
||||
<umb-property data-element="property-{{group.alias}}" ng-repeat="property in group.properties track by property.alias" property="property">
|
||||
<umb-property-editor model="property"></umb-property-editor>
|
||||
</umb-property>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</umb-editor-container>
|
||||
@@ -38,8 +38,8 @@
|
||||
<umb-editor-footer>
|
||||
|
||||
<umb-editor-footer-content-left>
|
||||
<umb-breadcrumbs
|
||||
ng-if="ancestors && ancestors.length > 0"
|
||||
<umb-breadcrumbs
|
||||
ng-if="ancestors && ancestors.length > 0"
|
||||
ancestors="ancestors">
|
||||
</umb-breadcrumbs>
|
||||
</umb-editor-footer-content-left>
|
||||
@@ -51,6 +51,7 @@
|
||||
ng-if="page.listViewPath"
|
||||
type="link"
|
||||
href="#{{page.listViewPath}}"
|
||||
button-style="link"
|
||||
label="Return to list"
|
||||
label-key="buttons_returnToList">
|
||||
</umb-button>
|
||||
|
||||
@@ -42,7 +42,7 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.CheckboxListContro
|
||||
return f.checked;
|
||||
}),
|
||||
function(m) {
|
||||
return m.key;
|
||||
return m.value;
|
||||
});
|
||||
//get all of the same values between the arrays
|
||||
var same = _.intersection($scope.model.value, selectedVals);
|
||||
@@ -54,7 +54,7 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.CheckboxListContro
|
||||
$scope.selectedItems = [];
|
||||
|
||||
for (var i = 0; i < configItems.length; i++) {
|
||||
var isChecked = _.contains($scope.model.value, configItems[i].id);
|
||||
var isChecked = _.contains($scope.model.value, configItems[i].value);
|
||||
$scope.selectedItems.push({
|
||||
checked: isChecked,
|
||||
key: configItems[i].id,
|
||||
@@ -66,13 +66,13 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.CheckboxListContro
|
||||
function changed(item) {
|
||||
var index = _.findIndex($scope.model.value,
|
||||
function (v) {
|
||||
return v === item.key;
|
||||
return v === item.value;
|
||||
});
|
||||
|
||||
|
||||
if (item.checked) {
|
||||
//if it doesn't exist in the model, then add it
|
||||
if (index < 0) {
|
||||
$scope.model.value.push(item.key);
|
||||
$scope.model.value.push(item.value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
<li ng-repeat="item in selectedItems track by item.key">
|
||||
<label class="checkbox">
|
||||
<input type="checkbox" name="checkboxlist"
|
||||
value="{{item.key}}"
|
||||
value="{{item.value}}"
|
||||
ng-model="item.checked"
|
||||
ng-change="changed(item)"
|
||||
ng-change="changed(item)"
|
||||
ng-required="model.validation.mandatory && !model.value.length" />
|
||||
{{item.val}}
|
||||
</label>
|
||||
|
||||
@@ -105,6 +105,10 @@ function contentPickerController($scope, entityResource, editorState, iconHelper
|
||||
};
|
||||
|
||||
if ($scope.model.config) {
|
||||
//special case, if the `startNode` is falsy on the server config delete it entirely so the default value is merged in
|
||||
if (!$scope.model.config.startNode) {
|
||||
delete $scope.model.config.startNode;
|
||||
}
|
||||
//merge the server config on top of the default config, then set the server config to use the result
|
||||
$scope.model.config = angular.extend(defaultConfig, $scope.model.config);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
function EditConfigController($scope) {
|
||||
|
||||
$scope.close = function() {
|
||||
if($scope.model.close) {
|
||||
$scope.model.close();
|
||||
}
|
||||
}
|
||||
|
||||
$scope.submit = function() {
|
||||
if($scope.model && $scope.model.submit) {
|
||||
$scope.model.submit($scope.model);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.PropertyEditors.GridPrevalueEditor.EditConfigController", EditConfigController);
|
||||
@@ -1,3 +1,25 @@
|
||||
<div class="usky-grid usky-grid-configuration" ng-controller="Umbraco.PropertyEditors.GridPrevalueEditor.EditConfigController">
|
||||
|
||||
|
||||
|
||||
<umb-editor-view>
|
||||
|
||||
<form novalidate name="EditConfigForm" val-form-manager>
|
||||
|
||||
<umb-editor-header
|
||||
name="model.title"
|
||||
name-locked="true"
|
||||
hide-alias="true"
|
||||
hide-icon="true"
|
||||
hide-description="true">
|
||||
</umb-editor-header>
|
||||
|
||||
<umb-editor-container>
|
||||
<umb-box>
|
||||
<umb-box-content>
|
||||
|
||||
|
||||
|
||||
<form name="gridConfigEditor">
|
||||
|
||||
<h4>{{model.name}}</h4>
|
||||
@@ -12,3 +34,34 @@
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
|
||||
|
||||
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
</umb-editor-container>
|
||||
|
||||
<umb-editor-footer>
|
||||
<umb-editor-footer-content-right>
|
||||
<umb-button
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="close()">
|
||||
</umb-button>
|
||||
<umb-button
|
||||
type="button"
|
||||
button-style="success"
|
||||
label-key="general_submit"
|
||||
action="submit()">
|
||||
</umb-button>
|
||||
</umb-editor-footer-content-right>
|
||||
</umb-editor-footer>
|
||||
|
||||
</form>
|
||||
|
||||
</umb-editor-view>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,10 +1,25 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.PropertyEditors.GridPrevalueEditor.LayoutConfigController",
|
||||
function ($scope) {
|
||||
function ($scope, localizationService) {
|
||||
|
||||
|
||||
function init() {
|
||||
setTitle();
|
||||
}
|
||||
|
||||
function setTitle() {
|
||||
if (!$scope.model.title) {
|
||||
localizationService.localize("grid_addGridLayout")
|
||||
.then(function(data){
|
||||
$scope.model.title = data;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
$scope.currentLayout = $scope.model.currentLayout;
|
||||
$scope.columns = $scope.model.columns;
|
||||
$scope.rows = $scope.model.rows;
|
||||
$scope.currentSection = undefined;
|
||||
|
||||
$scope.scaleUp = function(section, max, overflow){
|
||||
var add = 1;
|
||||
@@ -57,9 +72,12 @@ angular.module("umbraco")
|
||||
template.sections.splice(index, 1);
|
||||
};
|
||||
|
||||
$scope.closeSection = function(){
|
||||
$scope.currentSection = undefined;
|
||||
};
|
||||
|
||||
$scope.close = function() {
|
||||
if($scope.model.close) {
|
||||
$scope.model.close();
|
||||
}
|
||||
}
|
||||
|
||||
$scope.$watch("currentLayout", function(layout){
|
||||
if(layout){
|
||||
@@ -71,4 +89,6 @@ angular.module("umbraco")
|
||||
$scope.availableLayoutSpace = $scope.columns - total;
|
||||
}
|
||||
}, true);
|
||||
|
||||
init();
|
||||
});
|
||||
|
||||
@@ -1,8 +1,31 @@
|
||||
<div class="usky-grid usky-grid-configuration" ng-controller="Umbraco.PropertyEditors.GridPrevalueEditor.LayoutConfigController">
|
||||
|
||||
<div class="umb-forms-settings">
|
||||
|
||||
<h5><localize key="grid_addGridLayout" /></h5>
|
||||
|
||||
|
||||
<umb-editor-view>
|
||||
|
||||
<form novalidate name="LayoutConfigForm" val-form-manager>
|
||||
|
||||
<umb-editor-header
|
||||
name="model.title"
|
||||
name-locked="true"
|
||||
hide-alias="true"
|
||||
hide-icon="true"
|
||||
hide-description="true">
|
||||
</umb-editor-header>
|
||||
|
||||
<umb-editor-container>
|
||||
<umb-box>
|
||||
<umb-box-content>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="umb-forms-settings form-horizontal">
|
||||
|
||||
<p><localize key="grid_addGridLayoutDetail" /></p>
|
||||
|
||||
<umb-control-group label="@general_name">
|
||||
@@ -32,7 +55,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div ng-if="currentSection" style="padding-bottom: 50px;">
|
||||
<div ng-if="currentSection != null" style="padding-bottom: 50px;">
|
||||
|
||||
<umb-control-group label="@general_width">
|
||||
<div class="grid-size-scaler">
|
||||
@@ -111,4 +134,27 @@
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
</umb-editor-container>
|
||||
|
||||
<umb-editor-footer>
|
||||
<umb-editor-footer-content-right>
|
||||
<umb-button
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="close()">
|
||||
</umb-button>
|
||||
</umb-editor-footer-content-right>
|
||||
</umb-editor-footer>
|
||||
|
||||
</form>
|
||||
|
||||
</umb-editor-view>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
function RowConfigController($scope) {
|
||||
function RowConfigController($scope, localizationService) {
|
||||
|
||||
function init() {
|
||||
setTitle();
|
||||
}
|
||||
|
||||
function setTitle() {
|
||||
if (!$scope.model.title) {
|
||||
localizationService.localize("grid_addRowConfiguration")
|
||||
.then(function(data){
|
||||
$scope.model.title = data;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$scope.currentRow = $scope.model.currentRow;
|
||||
$scope.editors = $scope.model.editors;
|
||||
$scope.columns = $scope.model.columns;
|
||||
@@ -69,6 +83,12 @@ function RowConfigController($scope) {
|
||||
$scope.closeArea = function() {
|
||||
$scope.currentCell = undefined;
|
||||
};
|
||||
|
||||
$scope.close = function() {
|
||||
if($scope.model.close) {
|
||||
$scope.model.close();
|
||||
}
|
||||
}
|
||||
|
||||
$scope.nameChanged = false;
|
||||
var originalName = $scope.currentRow.name;
|
||||
@@ -93,6 +113,10 @@ function RowConfigController($scope) {
|
||||
}
|
||||
}, true);
|
||||
|
||||
|
||||
init();
|
||||
|
||||
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.PropertyEditors.GridPrevalueEditor.RowConfigController", RowConfigController);
|
||||
|
||||
@@ -1,8 +1,30 @@
|
||||
<div class="usky-grid usky-grid-configuration" ng-controller="Umbraco.PropertyEditors.GridPrevalueEditor.RowConfigController">
|
||||
|
||||
<div class="umb-form-settings">
|
||||
|
||||
<h5><localize key="grid_addRowConfiguration" /></h5>
|
||||
|
||||
<umb-editor-view>
|
||||
|
||||
<form novalidate name="RowConfigurationForm" val-form-manager>
|
||||
|
||||
<umb-editor-header
|
||||
name="model.title"
|
||||
name-locked="true"
|
||||
hide-alias="true"
|
||||
hide-icon="true"
|
||||
hide-description="true">
|
||||
</umb-editor-header>
|
||||
|
||||
<umb-editor-container>
|
||||
<umb-box>
|
||||
<umb-box-content>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<div class="umb-form-settings form-horizontal">
|
||||
|
||||
<p><localize key="grid_addRowConfigurationDetail" /></p>
|
||||
|
||||
<div class="alert alert-warn ng-scope" ng-show="nameChanged">
|
||||
@@ -14,7 +36,7 @@
|
||||
<umb-control-group label="@general_name">
|
||||
<input type="text" ng-model="currentRow.name" />
|
||||
</umb-control-group>
|
||||
|
||||
|
||||
<umb-control-group label="@general_label">
|
||||
<input type="text" ng-model="currentRow.label" placeholder="Overrides name" />
|
||||
</umb-control-group>
|
||||
@@ -54,7 +76,7 @@
|
||||
</a>
|
||||
</div>
|
||||
</umb-control-group>
|
||||
|
||||
|
||||
<umb-control-group label="@grid_maxItems" description="@grid_maxItemsDescription">
|
||||
<input type="number" ng-model="currentCell.maxItems" class="umb-property-editor-tiny" placeholder="Max" min="0" />
|
||||
</umb-control-group>
|
||||
@@ -97,4 +119,27 @@
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
</umb-editor-container>
|
||||
|
||||
<umb-editor-footer>
|
||||
<umb-editor-footer-content-right>
|
||||
<umb-button
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="close()">
|
||||
</umb-button>
|
||||
</umb-editor-footer-content-right>
|
||||
</umb-editor-footer>
|
||||
|
||||
</form>
|
||||
|
||||
</umb-editor-view>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
function DeleteRowConfirmController($scope) {
|
||||
|
||||
$scope.close = function() {
|
||||
if($scope.model.close) {
|
||||
$scope.model.close();
|
||||
}
|
||||
}
|
||||
|
||||
$scope.submit = function() {
|
||||
if($scope.model && $scope.model.submit) {
|
||||
$scope.model.submit($scope.model);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
angular.module("umbraco").controller("Umbraco.PropertyEditors.GridPrevalueEditor.DeleteRowConfirmController", DeleteRowConfirmController);
|
||||
@@ -1,4 +1,13 @@
|
||||
<div>
|
||||
<div class="usky-grid usky-grid-configuration" ng-controller="Umbraco.PropertyEditors.GridPrevalueEditor.DeleteRowConfirmController">
|
||||
|
||||
|
||||
<umb-editor-view>
|
||||
|
||||
<umb-editor-container>
|
||||
<umb-box>
|
||||
<umb-box-content>
|
||||
|
||||
|
||||
|
||||
<h3 class="alert alert-warn ng-scope">Warning!</h3>
|
||||
|
||||
@@ -15,4 +24,31 @@
|
||||
<localize key="general_areyousure">Are you sure?</localize>
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
|
||||
</umb-box-content>
|
||||
</umb-box>
|
||||
</umb-editor-container>
|
||||
|
||||
<umb-editor-footer>
|
||||
<umb-editor-footer-content-right>
|
||||
<umb-button
|
||||
type="button"
|
||||
button-style="link"
|
||||
label-key="general_close"
|
||||
shortcut="esc"
|
||||
action="close()">
|
||||
</umb-button>
|
||||
<umb-button
|
||||
type="button"
|
||||
button-style="warning"
|
||||
label-key="general_delete"
|
||||
action="submit(model)">
|
||||
</umb-button>
|
||||
</umb-editor-footer-content-right>
|
||||
</umb-editor-footer>
|
||||
|
||||
</umb-editor-view>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
angular.module("umbraco")
|
||||
.controller("Umbraco.PropertyEditors.GridPrevalueEditorController",
|
||||
function ($scope, gridService) {
|
||||
function ($scope, gridService, editorService) {
|
||||
|
||||
var emptyModel = {
|
||||
styles:[
|
||||
@@ -89,28 +89,23 @@ angular.module("umbraco")
|
||||
};
|
||||
$scope.model.value.templates.push(template);
|
||||
}
|
||||
|
||||
var layoutConfigOverlay = {
|
||||
currentLayout: template,
|
||||
rows: $scope.model.value.layouts,
|
||||
columns: $scope.model.value.columns,
|
||||
view: "views/propertyEditors/grid/dialogs/layoutconfig.html",
|
||||
size: "small",
|
||||
submit: function(model) {
|
||||
editorService.close();
|
||||
},
|
||||
close: function(model) {
|
||||
editorService.close();
|
||||
}
|
||||
};
|
||||
|
||||
$scope.layoutConfigOverlay = {};
|
||||
$scope.layoutConfigOverlay.view = "views/propertyEditors/grid/dialogs/layoutconfig.html";
|
||||
$scope.layoutConfigOverlay.currentLayout = template;
|
||||
$scope.layoutConfigOverlay.rows = $scope.model.value.layouts;
|
||||
$scope.layoutConfigOverlay.columns = $scope.model.value.columns;
|
||||
$scope.layoutConfigOverlay.show = true;
|
||||
editorService.open(layoutConfigOverlay);
|
||||
|
||||
$scope.layoutConfigOverlay.submit = function(model) {
|
||||
$scope.layoutConfigOverlay.show = false;
|
||||
$scope.layoutConfigOverlay = null;
|
||||
};
|
||||
|
||||
$scope.layoutConfigOverlay.close = function(oldModel) {
|
||||
|
||||
//reset templates
|
||||
$scope.model.value.templates = templatesCopy;
|
||||
|
||||
$scope.layoutConfigOverlay.show = false;
|
||||
$scope.layoutConfigOverlay = null;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
$scope.deleteTemplate = function(index){
|
||||
@@ -135,50 +130,44 @@ angular.module("umbraco")
|
||||
};
|
||||
$scope.model.value.layouts.push(layout);
|
||||
}
|
||||
|
||||
$scope.rowConfigOverlay = {};
|
||||
$scope.rowConfigOverlay.view = "views/propertyEditors/grid/dialogs/rowconfig.html";
|
||||
$scope.rowConfigOverlay.currentRow = layout;
|
||||
$scope.rowConfigOverlay.editors = $scope.editors;
|
||||
$scope.rowConfigOverlay.columns = $scope.model.value.columns;
|
||||
$scope.rowConfigOverlay.show = true;
|
||||
|
||||
$scope.rowConfigOverlay.submit = function(model) {
|
||||
$scope.rowConfigOverlay.show = false;
|
||||
$scope.rowConfigOverlay = null;
|
||||
};
|
||||
|
||||
$scope.rowConfigOverlay.close = function(oldModel) {
|
||||
$scope.model.value.layouts = layoutsCopy;
|
||||
$scope.rowConfigOverlay.show = false;
|
||||
$scope.rowConfigOverlay = null;
|
||||
|
||||
var rowConfigOverlay = {
|
||||
currentRow: layout,
|
||||
editors: $scope.editors,
|
||||
columns: $scope.model.value.columns,
|
||||
view: "views/propertyEditors/grid/dialogs/rowconfig.html",
|
||||
size: "small",
|
||||
submit: function(model) {
|
||||
editorService.close();
|
||||
},
|
||||
close: function(model) {
|
||||
editorService.close();
|
||||
}
|
||||
};
|
||||
|
||||
editorService.open(rowConfigOverlay);
|
||||
|
||||
};
|
||||
|
||||
//var rowDeletesPending = false;
|
||||
$scope.deleteLayout = function(index) {
|
||||
|
||||
var rowDeleteOverlay = {
|
||||
dialogData: {
|
||||
rowName: $scope.model.value.layouts[index].name
|
||||
},
|
||||
view: "views/propertyEditors/grid/dialogs/rowdeleteconfirm.html",
|
||||
size: "small",
|
||||
submit: function(model) {
|
||||
$scope.model.value.layouts.splice(index, 1);
|
||||
editorService.close();
|
||||
},
|
||||
close: function(model) {
|
||||
editorService.close();
|
||||
}
|
||||
};
|
||||
|
||||
$scope.rowDeleteOverlay = {};
|
||||
$scope.rowDeleteOverlay.view = "views/propertyEditors/grid/dialogs/rowdeleteconfirm.html";
|
||||
$scope.rowDeleteOverlay.dialogData = {
|
||||
rowName: $scope.model.value.layouts[index].name
|
||||
};
|
||||
$scope.rowDeleteOverlay.show = true;
|
||||
|
||||
$scope.rowDeleteOverlay.submit = function(model) {
|
||||
|
||||
$scope.model.value.layouts.splice(index, 1);
|
||||
|
||||
$scope.rowDeleteOverlay.show = false;
|
||||
$scope.rowDeleteOverlay = null;
|
||||
};
|
||||
|
||||
$scope.rowDeleteOverlay.close = function(oldModel) {
|
||||
$scope.rowDeleteOverlay.show = false;
|
||||
$scope.rowDeleteOverlay = null;
|
||||
};
|
||||
|
||||
editorService.open(rowDeleteOverlay);
|
||||
};
|
||||
|
||||
|
||||
@@ -210,26 +199,22 @@ angular.module("umbraco")
|
||||
};
|
||||
|
||||
var editConfigCollection = function(configValues, title, callback) {
|
||||
|
||||
var editConfigCollectionOverlay = {
|
||||
config: configValues,
|
||||
title: title,
|
||||
view: "views/propertyeditors/grid/dialogs/editconfig.html",
|
||||
size: "small",
|
||||
submit: function(model) {
|
||||
callback(model.config);
|
||||
editorService.close();
|
||||
},
|
||||
close: function(model) {
|
||||
editorService.close();
|
||||
}
|
||||
};
|
||||
|
||||
$scope.editConfigCollectionOverlay = {};
|
||||
$scope.editConfigCollectionOverlay.view = "views/propertyeditors/grid/dialogs/editconfig.html";
|
||||
$scope.editConfigCollectionOverlay.config = configValues;
|
||||
$scope.editConfigCollectionOverlay.title = title;
|
||||
$scope.editConfigCollectionOverlay.show = true;
|
||||
|
||||
$scope.editConfigCollectionOverlay.submit = function(model) {
|
||||
|
||||
callback(model.config);
|
||||
|
||||
$scope.editConfigCollectionOverlay.show = false;
|
||||
$scope.editConfigCollectionOverlay = null;
|
||||
};
|
||||
|
||||
$scope.editConfigCollectionOverlay.close = function(oldModel) {
|
||||
$scope.editConfigCollectionOverlay.show = false;
|
||||
$scope.editConfigCollectionOverlay = null;
|
||||
};
|
||||
|
||||
editorService.open(editConfigCollectionOverlay);
|
||||
};
|
||||
|
||||
$scope.editConfig = function() {
|
||||
|
||||
@@ -158,28 +158,4 @@
|
||||
</umb-control-group>
|
||||
</div>
|
||||
|
||||
<umb-overlay ng-if="layoutConfigOverlay.show"
|
||||
model="layoutConfigOverlay"
|
||||
view="layoutConfigOverlay.view"
|
||||
position="right">
|
||||
</umb-overlay>
|
||||
|
||||
<umb-overlay ng-if="rowConfigOverlay.show"
|
||||
model="rowConfigOverlay"
|
||||
view="rowConfigOverlay.view"
|
||||
position="right">
|
||||
</umb-overlay>
|
||||
|
||||
<umb-overlay ng-if="editConfigCollectionOverlay.show"
|
||||
model="editConfigCollectionOverlay"
|
||||
view="editConfigCollectionOverlay.view"
|
||||
position="right">
|
||||
</umb-overlay>
|
||||
|
||||
<umb-overlay ng-if="rowDeleteOverlay.show"
|
||||
model="rowDeleteOverlay"
|
||||
view="rowDeleteOverlay.view"
|
||||
position="right">
|
||||
</umb-overlay>
|
||||
|
||||
</div>
|
||||
|
||||
@@ -142,7 +142,6 @@ function listViewController($scope, $routeParams, $injector, $timeout, currentUs
|
||||
}
|
||||
|
||||
$scope.options = {
|
||||
displayAtTabNumber: $scope.model.config.displayAtTabNumber ? $scope.model.config.displayAtTabNumber : 1,
|
||||
pageSize: $scope.model.config.pageSize ? $scope.model.config.pageSize : 10,
|
||||
pageNumber: ($routeParams.page && Number($routeParams.page) != NaN && Number($routeParams.page) > 0) ? $routeParams.page : 1,
|
||||
filter: '',
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
<div class="row-fluid" ng-switch-when="false">
|
||||
|
||||
<umb-editor-sub-header>
|
||||
<umb-editor-sub-header ng-class="{'--state-selection':(selection.length > 0)}">
|
||||
|
||||
<umb-editor-sub-header-content-left>
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
type="button"
|
||||
label="Clear selection"
|
||||
label-key="buttons_clearSelection"
|
||||
button-style="selection"
|
||||
button-style="white"
|
||||
action="clearSelection()"
|
||||
disabled="actionInProgress">
|
||||
</umb-button>
|
||||
@@ -140,7 +140,7 @@
|
||||
ng-if="options.allowBulkPublish && (buttonPermissions == null || buttonPermissions.canPublish)"
|
||||
style="margin-right: 5px;"
|
||||
type="button"
|
||||
button-style="selection"
|
||||
button-style="white"
|
||||
label-key="actions_publish"
|
||||
icon="icon-globe"
|
||||
action="publish()"
|
||||
@@ -153,7 +153,7 @@
|
||||
ng-if="options.allowBulkUnpublish && (buttonPermissions == null || buttonPermissions.canUnpublish)"
|
||||
style="margin-right: 5px;"
|
||||
type="button"
|
||||
button-style="selection"
|
||||
button-style="white"
|
||||
label-key="actions_unpublish"
|
||||
icon="icon-block"
|
||||
action="unpublish()"
|
||||
@@ -166,7 +166,7 @@
|
||||
ng-if="options.allowBulkCopy && (buttonPermissions == null || buttonPermissions.canCopy)"
|
||||
style="margin-right: 5px;"
|
||||
type="button"
|
||||
button-style="selection"
|
||||
button-style="white"
|
||||
label-key="actions_copy"
|
||||
icon="icon-documents"
|
||||
action="copy()"
|
||||
@@ -179,7 +179,7 @@
|
||||
ng-if="options.allowBulkMove && (buttonPermissions == null || buttonPermissions.canMove)"
|
||||
style="margin-right: 5px;"
|
||||
type="button"
|
||||
button-style="selection"
|
||||
button-style="white"
|
||||
label-key="actions_move"
|
||||
icon="icon-enter"
|
||||
action="move()"
|
||||
@@ -191,7 +191,7 @@
|
||||
<umb-button
|
||||
ng-if="options.allowBulkDelete && (buttonPermissions == null || buttonPermissions.canDelete)"
|
||||
type="button"
|
||||
button-style="selection"
|
||||
button-style="white"
|
||||
label-key="actions_delete"
|
||||
icon="icon-trash"
|
||||
action="delete()"
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
<li ng-repeat="item in configItems track by item.id">
|
||||
<label class="radio">
|
||||
<input type="radio" name="{{htmlId}}"
|
||||
value="{{item.id}}"
|
||||
value="{{item.value}}"
|
||||
ng-model="model.value" />
|
||||
{{item.value}}
|
||||
</label>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -12,9 +12,9 @@
|
||||
hide-alias="true"
|
||||
navigation="vm.user.navigation">
|
||||
</umb-editor-header>
|
||||
|
||||
|
||||
<umb-editor-container>
|
||||
|
||||
|
||||
<div ng-if="!vm.loading" class="umb-user-details-view-wrapper" style="padding: 0;">
|
||||
|
||||
<umb-editor-sub-views
|
||||
@@ -42,6 +42,7 @@
|
||||
|
||||
<umb-button type="button"
|
||||
action="vm.goToPage(vm.breadcrumbs[0])"
|
||||
button-style="link"
|
||||
label="Return to list"
|
||||
label-key="buttons_returnToList"
|
||||
disabled="vm.loading">
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
<umb-load-indicator ng-if="vm.loading"></umb-load-indicator>
|
||||
|
||||
<umb-editor-sub-header>
|
||||
|
||||
<umb-editor-sub-header ng-class="{'--state-selection':(vm.selection.length > 0)}">
|
||||
|
||||
<!-- No selection -->
|
||||
<umb-editor-sub-header-content-left ng-if="vm.selection.length === 0">
|
||||
<umb-button
|
||||
type="button"
|
||||
button-style="success"
|
||||
button-style="action"
|
||||
action="vm.createUserGroup()"
|
||||
label="Create Group"
|
||||
label-key="actions_createGroup">
|
||||
@@ -40,6 +40,7 @@
|
||||
<umb-button
|
||||
type="button"
|
||||
label-key="buttons_clearSelection"
|
||||
button-style="white"
|
||||
action="vm.clearSelection()"
|
||||
size="xs">
|
||||
</umb-button>
|
||||
@@ -54,6 +55,7 @@
|
||||
type="button"
|
||||
label="Delete"
|
||||
label-key="general_delete"
|
||||
button-style="white"
|
||||
icon="icon-trash"
|
||||
action="vm.deleteUserGroups()"
|
||||
size="xs">
|
||||
@@ -64,7 +66,7 @@
|
||||
|
||||
<div style="margin-bottom: 20px;" class="flex items-center">
|
||||
<div style="font-size: 16px;">
|
||||
<span class="bold"><localize key="general_groups">Groups</localize> </span> <span>({{vm.userGroups.length}})</span>
|
||||
<span class="bold"><localize key="general_groups">Groups</localize> </span> <span>({{vm.userGroups.length}})</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -76,19 +78,20 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="group in vm.userGroups | filter:vm.filter"
|
||||
ng-click="vm.goToUserGroup(group)"
|
||||
ng-class="{'cursor-pointer': group.hasAccess, 'cursor-not-allowed': !group.hasAccess}">
|
||||
|
||||
<td style="width: 20px; padding-right: 5px">
|
||||
<tr ng-repeat="group in vm.userGroups | filter:vm.filter"
|
||||
ng-click="vm.goToUserGroup(group)"
|
||||
ng-class="{'cursor-pointer': group.hasAccess, 'cursor-not-allowed': !group.hasAccess, '--selected': group.selected}">
|
||||
|
||||
<td style="padding-right: 5px">
|
||||
<input
|
||||
ng-show="group.hasAccess && group.group.alias !== 'admin' && group.group.alias !== 'translator'"
|
||||
type="checkbox"
|
||||
type="checkbox"
|
||||
ng-model="group.selected"
|
||||
ng-click="vm.selectUserGroup(group, vm.selection, $event)" />
|
||||
ng-click="vm.selectUserGroup(group, vm.selection, $event)"
|
||||
style="width: 20px; height: 100px;"/>
|
||||
</td>
|
||||
<td>
|
||||
<umb-user-group-preview
|
||||
<umb-user-group-preview
|
||||
style="border-bottom: none; margin-bottom: 0; padding: 0;"
|
||||
icon="group.group.icon"
|
||||
name="group.group.name"
|
||||
@@ -101,4 +104,4 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -59,13 +59,10 @@
|
||||
}
|
||||
];
|
||||
|
||||
vm.activeLayout = {
|
||||
"icon": "icon-thumbnails-small",
|
||||
"path": "1",
|
||||
"selected": true
|
||||
};
|
||||
// Set card layout to active by default
|
||||
vm.activeLayout = vm.layouts[0];
|
||||
|
||||
//don't show the invite button if no email is configured
|
||||
// Don't show the invite button if no email is configured
|
||||
if (Umbraco.Sys.ServerVariables.umbracoSettings.showUserInvite) {
|
||||
vm.defaultButton = {
|
||||
labelKey: "user_inviteUser",
|
||||
@@ -199,27 +196,23 @@
|
||||
vm.activeLayout = selectedLayout;
|
||||
}
|
||||
|
||||
function selectUser(user, selection, event) {
|
||||
|
||||
// prevent the current user to be selected
|
||||
if (!user.isCurrentUser) {
|
||||
|
||||
if (user.selected) {
|
||||
var index = selection.indexOf(user.id);
|
||||
selection.splice(index, 1);
|
||||
user.selected = false;
|
||||
} else {
|
||||
user.selected = true;
|
||||
vm.selection.push(user.id);
|
||||
}
|
||||
|
||||
setBulkActions(vm.users);
|
||||
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
function selectUser(user) {
|
||||
|
||||
if (user.isCurrentUser) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (user.selected) {
|
||||
var index = vm.selection.indexOf(user.id);
|
||||
vm.selection.splice(index, 1);
|
||||
user.selected = false;
|
||||
} else {
|
||||
user.selected = true;
|
||||
vm.selection.push(user.id);
|
||||
}
|
||||
|
||||
setBulkActions(vm.users);
|
||||
|
||||
}
|
||||
|
||||
function clearSelection() {
|
||||
@@ -230,11 +223,7 @@
|
||||
}
|
||||
|
||||
function clickUser(user) {
|
||||
if (vm.selection.length > 0) {
|
||||
selectUser(user, vm.selection);
|
||||
} else {
|
||||
goToUser(user.id);
|
||||
}
|
||||
goToUser(user.id);
|
||||
}
|
||||
|
||||
function disableUsers() {
|
||||
@@ -628,18 +617,20 @@
|
||||
var firstSelectedUserGroups;
|
||||
|
||||
angular.forEach(users, function (user) {
|
||||
|
||||
|
||||
if (!user.selected) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// if the current user is selected prevent any bulk actions with the user included
|
||||
if (user.isCurrentUser) {
|
||||
vm.allowDisableUser = false;
|
||||
vm.allowEnableUser = false;
|
||||
vm.allowUnlockUser = false;
|
||||
vm.allowSetUserGroup = false;
|
||||
return;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (user.userDisplayState && user.userDisplayState.key === "Disabled") {
|
||||
@@ -663,16 +654,17 @@
|
||||
}
|
||||
|
||||
// store the user group aliases of the first selected user
|
||||
if (!firstSelectedUserGroups) {
|
||||
firstSelectedUserGroups = user.userGroups.map(function (ug) { return ug.alias; });
|
||||
vm.allowSetUserGroup = true;
|
||||
} else if (vm.allowSetUserGroup === true) {
|
||||
// for 2nd+ selected user, compare the user group aliases to determine if we should allow bulk editing.
|
||||
// we don't allow bulk editing of users not currently having the same assigned user groups, as we can't
|
||||
// really support that in the user group picker.
|
||||
var userGroups = user.userGroups.map(function (ug) { return ug.alias; });
|
||||
if (_.difference(firstSelectedUserGroups, userGroups).length > 0) {
|
||||
vm.allowSetUserGroup = false;
|
||||
if (vm.allowSetUserGroup === true) {
|
||||
if (!firstSelectedUserGroups) {
|
||||
firstSelectedUserGroups = user.userGroups.map(function (ug) { return ug.alias; });
|
||||
} else {
|
||||
// for 2nd+ selected user, compare the user group aliases to determine if we should allow bulk editing.
|
||||
// we don't allow bulk editing of users not currently having the same assigned user groups, as we can't
|
||||
// really support that in the user group picker.
|
||||
var userGroups = user.userGroups.map(function (ug) { return ug.alias; });
|
||||
if (_.difference(firstSelectedUserGroups, userGroups).length > 0) {
|
||||
vm.allowSetUserGroup = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
<umb-load-indicator ng-show="vm.loading"></umb-load-indicator>
|
||||
|
||||
<umb-editor-sub-header>
|
||||
<umb-editor-sub-header ng-class="{'--state-selection':(vm.selection.length > 0)}">
|
||||
|
||||
<!-- No selection -->
|
||||
<umb-editor-sub-header-content-left ng-if="vm.selection.length === 0">
|
||||
@@ -23,21 +23,20 @@
|
||||
ng-if="vm.layouts"
|
||||
layouts="vm.layouts"
|
||||
active-layout="vm.activeLayout"
|
||||
on-layout-select="vm.selectLayout">
|
||||
on-layout-select="vm.selectLayout(layout)">
|
||||
</umb-layout-selector>
|
||||
</umb-editor-sub-header-section>
|
||||
<umb-editor-sub-header-section>
|
||||
<div class="form-search -no-margin-bottom pull-right">
|
||||
<div class="inner-addon left-addon">
|
||||
<i class="icon icon-search"></i>
|
||||
<input
|
||||
class="form-control search-input"
|
||||
type="text" localize="placeholder"
|
||||
placeholder="@general_typeToSearch"
|
||||
ng-model="vm.usersOptions.filter"
|
||||
ng-change="vm.searchUsers()"
|
||||
prevent-enter-submit
|
||||
no-dirty-check>
|
||||
<input class="form-control search-input"
|
||||
type="text" localize="placeholder"
|
||||
placeholder="@general_typeToSearch"
|
||||
ng-model="vm.usersOptions.filter"
|
||||
ng-change="vm.searchUsers()"
|
||||
prevent-enter-submit
|
||||
no-dirty-check>
|
||||
</div>
|
||||
</div>
|
||||
</umb-editor-sub-header-section>
|
||||
@@ -49,7 +48,7 @@
|
||||
<umb-button
|
||||
type="button"
|
||||
size="xs"
|
||||
button-style="outline"
|
||||
button-style="white"
|
||||
label-key="buttons_clearSelection"
|
||||
action="vm.clearSelection()"
|
||||
disabled="actionInProgress">
|
||||
@@ -58,16 +57,16 @@
|
||||
<umb-editor-sub-header-section>
|
||||
<strong>{{ vm.selection.length }} <localize key="general_of">of</localize> {{ vm.users.length }} <localize key="general_selected">selected</localize></strong>
|
||||
</umb-editor-sub-header-section>
|
||||
|
||||
|
||||
</umb-editor-sub-header-content-left>
|
||||
|
||||
<umb-editor-sub-header-content-right ng-if="vm.selection.length > 0">
|
||||
<umb-button
|
||||
style="margin-right: 5px;"
|
||||
ng-if="vm.allowSetUserGroup"
|
||||
type="button"
|
||||
disabled="!vm.allowSetUserGroup"
|
||||
type="button"
|
||||
size="xs"
|
||||
button-style="outline"
|
||||
button-style="white"
|
||||
label-key="actions_setGroup"
|
||||
icon="icon-users"
|
||||
action="vm.openBulkUserGroupPicker()">
|
||||
@@ -75,22 +74,22 @@
|
||||
|
||||
<umb-button
|
||||
style="margin-right: 5px;"
|
||||
ng-if="vm.allowEnableUser"
|
||||
disabled="!vm.allowEnableUser"
|
||||
type="button"
|
||||
size="xs"
|
||||
button-style="outline"
|
||||
button-style="white"
|
||||
state="vm.enableUserButtonState"
|
||||
label-key="actions_enable"
|
||||
icon="icon-check"
|
||||
action="vm.enableUsers()">
|
||||
</umb-button>
|
||||
|
||||
|
||||
<umb-button
|
||||
style="margin-right: 5px;"
|
||||
ng-if="vm.allowUnlockUser"
|
||||
disabled="!vm.allowUnlockUser"
|
||||
type="button"
|
||||
size="xs"
|
||||
button-style="outline"
|
||||
button-style="white"
|
||||
state="vm.unlockUserButtonState"
|
||||
label-key="actions_unlock"
|
||||
icon="icon-unlocked"
|
||||
@@ -98,10 +97,10 @@
|
||||
</umb-button>
|
||||
|
||||
<umb-button
|
||||
ng-if="vm.allowDisableUser"
|
||||
disabled="!vm.allowDisableUser"
|
||||
type="button"
|
||||
size="xs"
|
||||
button-style="outline"
|
||||
button-style="white"
|
||||
state="vm.disableUserButtonState"
|
||||
label-key="actions_disable"
|
||||
icon="icon-block"
|
||||
@@ -124,7 +123,7 @@
|
||||
<!-- State filter -->
|
||||
<div style="position: relative;" ng-if="vm.userStatesFilter.length > 0">
|
||||
<a class="btn btn-link dropdown-toggle flex" href="" ng-click="vm.toggleFilter('state')">
|
||||
<span><localize key="general_status">Status</localize>:</span>
|
||||
<span><localize key="general_status">Status</localize>:</span>
|
||||
<span class="bold truncate dib" style="margin-left: 5px; margin-right: 3px; max-width: 150px;">{{ vm.getFilterName(vm.userStatesFilter) }}</span>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
@@ -168,7 +167,7 @@
|
||||
<!-- Order By -->
|
||||
<div style="position: relative;">
|
||||
<a class="btn btn-link dropdown-toggle flex" href="" ng-click="vm.toggleFilter('orderBy')">
|
||||
<span><localize key="general_orderBy">Order by</localize>:</span>
|
||||
<span><localize key="general_orderBy">Order by</localize>:</span>
|
||||
<span class="bold" style="margin-left: 2px;">{{ vm.getSortLabel(vm.usersOptions.orderBy, vm.usersOptions.orderDirection) }} </span>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
@@ -192,20 +191,18 @@
|
||||
|
||||
<!-- Layout: Cards -->
|
||||
<div class="umb-user-cards" ng-if="vm.activeLayout.path === '1' && vm.loading === false">
|
||||
<a href="" class="umb-user-card" ng-repeat="user in vm.users track by user.key" ng-click="vm.clickUser(user)">
|
||||
<div class="umb-user-card__content" ng-class="{'umb-user-card__content--selected': user.selected}">
|
||||
<umb-badge class="umb-user-card__badge" size="xs" ng-if="user.userDisplayState.key !== 'Active'" color="{{user.userDisplayState.color}}">
|
||||
{{ user.userDisplayState.name }}
|
||||
</umb-badge>
|
||||
<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 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__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>
|
||||
<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>
|
||||
<div class="umb-user-card__checkmark" ng-class="{'umb-user-card__checkmark--visible': user.selected || vm.selection.length > 0 }"
|
||||
ng-click="vm.selectUser(user, vm.selection, $event)">
|
||||
<umb-checkmark ng-if="!user.isCurrentUser" checked="user.selected" size="s"></umb-checkmark>
|
||||
</div>
|
||||
<div class="umb-user-card__name" href="">{{user.name}}</div>
|
||||
<div class="umb-user-card__group">
|
||||
<span ng-repeat="userGroup in user.userGroups">{{ userGroup.name }}<span ng-if="!$last">, </span></span>
|
||||
</div>
|
||||
@@ -223,13 +220,13 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Layout: Table -->
|
||||
<div ng-if="vm.activeLayout.path === '2'">
|
||||
|
||||
<table class="table table-hover">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="padding-left: 10px; width: 10px;">
|
||||
@@ -245,9 +242,14 @@
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr ng-repeat="user in vm.users track by user.key" ng-click="vm.clickUser(user)" style="cursor: pointer;" ng-mouseenter="user.hover = true" ng-mouseleave="user.hover = false">
|
||||
<tr 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;">
|
||||
<div ng-if="!user.isCurrentUser" ng-click="vm.selectUser(user, vm.selection, $event)">
|
||||
<div ng-if="!user.isCurrentUser">
|
||||
<umb-checkmark
|
||||
ng-if="vm.selection.length > 0 || user.hover"
|
||||
checked="user.selected"
|
||||
@@ -255,7 +257,7 @@
|
||||
</umb-checkmark>
|
||||
</div>
|
||||
</td>
|
||||
<td scope="row">
|
||||
<td scope="row" ng-click="vm.clickUser(user)">
|
||||
<umb-avatar
|
||||
size="xs"
|
||||
color="secondary"
|
||||
@@ -264,7 +266,7 @@
|
||||
img-srcset="{{user.avatars[1]}} 2x, {{user.avatars[2]}} 3x">
|
||||
</umb-avatar>
|
||||
</td>
|
||||
<td class="bold">{{user.name}}</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;">
|
||||
@@ -332,7 +334,7 @@
|
||||
<span class="help-inline" ng-message="required"><localize key="general_required">Required</localize></span>
|
||||
<span class="help-inline" ng-message="valServerField">{{addUserForm.name.errorMsg}}</span>
|
||||
</span>
|
||||
|
||||
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group label="@general_username" label-for="username" required="true" ng-if="!vm.usernameIsEmail">
|
||||
@@ -342,7 +344,7 @@
|
||||
<span class="help-inline" ng-message="required"><localize key="general_required">Required</localize></span>
|
||||
<span class="help-inline" ng-message="valServerField">{{addUserForm.username.errorMsg}}</span>
|
||||
</span>
|
||||
|
||||
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group label="@general_email" label-for="email" required="true">
|
||||
@@ -356,7 +358,7 @@
|
||||
</umb-control-group>
|
||||
|
||||
<umb-control-group label="@user_usergroup" description="@user_groupsHelp" required="true">
|
||||
|
||||
|
||||
<umb-user-group-preview
|
||||
ng-repeat="group in vm.newUser.userGroups"
|
||||
icon="group.icon"
|
||||
@@ -418,18 +420,18 @@
|
||||
|
||||
<!-- Create user success -->
|
||||
<div ng-if="vm.usersViewState === 'createUserSuccess'">
|
||||
|
||||
|
||||
<umb-editor-sub-header>
|
||||
<umb-editor-sub-header-content-left>
|
||||
<a class="umb-package-details__back-link" href="" ng-click="vm.setUsersViewState('overview');">← <localize key="user_backToUsers">Back to users</localize></a>
|
||||
</umb-editor-sub-header-content-left>
|
||||
</umb-editor-sub-header>
|
||||
|
||||
|
||||
<div class="flex justify-center">
|
||||
|
||||
<umb-box style="max-width: 500px;">
|
||||
<umb-box-content>
|
||||
|
||||
|
||||
<!-- Success text -->
|
||||
<div class="flex items-center" style="margin-bottom: 15px;">
|
||||
<umb-checkmark
|
||||
@@ -443,7 +445,7 @@
|
||||
</div>
|
||||
|
||||
<p style="line-height: 1.6em; margin-bottom: 20px;"><localize key="user_userCreatedSuccessHelp"></localize></p>
|
||||
|
||||
|
||||
<!-- New password -->
|
||||
<div>
|
||||
<label class="bold"><localize key="user_password">Password</localize></label>
|
||||
@@ -511,7 +513,7 @@
|
||||
|
||||
<umb-box style="max-width: 500px;">
|
||||
<umb-box-content>
|
||||
|
||||
|
||||
<!-- Success text -->
|
||||
<div class="flex items-center" style="margin-bottom: 15px;">
|
||||
<umb-checkmark
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
<PackageReference Include="CSharpTest.Net.Collections" Version="14.906.1403.1082" />
|
||||
<PackageReference Include="ClientDependency" Version="1.9.7" />
|
||||
<PackageReference Include="ClientDependency-Mvc5" Version="1.8.0.0" />
|
||||
<PackageReference Include="Examine" Version="1.0.0-beta078" />
|
||||
<PackageReference Include="Examine" Version="1.0.0-beta079" />
|
||||
<PackageReference Include="ImageProcessor.Web" Version="4.9.3.25" />
|
||||
<PackageReference Include="ImageProcessor.Web.Config" Version="2.4.1.19" />
|
||||
<PackageReference Include="Microsoft.AspNet.Identity.Owin" Version="2.2.2" />
|
||||
|
||||
@@ -1388,7 +1388,7 @@ To manage your website, simply open the Umbraco back office and start adding con
|
||||
<key alias="styles">Styles</key>
|
||||
<key alias="stylesHelp">The CSS that should be applied in the rich text editor, e.g. "color:red;"</key>
|
||||
<key alias="tabCode">Code</key>
|
||||
<key alias="tabRules">Rich Text Editor</key>
|
||||
<key alias="tabRules">Rich Text Editor</key>
|
||||
</area>
|
||||
<area alias="template">
|
||||
<key alias="deleteByIdFailed">Failed to delete template with ID %0%</key>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user