Compare commits

...

140 Commits

Author SHA1 Message Date
Shannon Deminick a60e15e771 Merge pull request #6072 from callumbwhyte/v8/feature/block-editor
WIP - block editor prototype
2019-08-09 17:05:21 +10:00
Shannon fec3d8b740 fix test 2019-08-09 17:02:46 +10:00
Shannon aed223c16d creates a proper component for the item list 2019-08-09 15:11:36 +10:00
Shannon 3dd5224ea3 Simplifies everything, no directives for now until this all makes sense and no directives that are coupled to the property editor, no ng-include 2019-08-09 13:07:19 +10:00
Shannon e940f6dfdc adds notes, starting to remove directives since these don't make sense in this context 2019-08-09 12:43:21 +10:00
Shannon 47a47292e8 adds the constant back 2019-08-09 12:08:41 +10:00
Shannon 277d5968a6 adds the constant back 2019-08-09 12:06:55 +10:00
Shannon 22eef489e0 Moves and renames angular files to where they are supposed to be 2019-08-09 12:05:19 +10:00
Shannon 5386fabf3c Removes refs to SimpleGrid, adds fixme and other notes 2019-08-09 11:52:43 +10:00
Shannon 1c141f1f02 reverts whitespaces changes 2019-08-09 11:25:16 +10:00
Shannon f2908211db reverts whitespaces changes 2019-08-09 11:24:30 +10:00
Shannon 11d18a6446 reverts whitespaces changes 2019-08-09 11:23:20 +10:00
Shannon cce8017155 reverts whitespaces changes, grid changes, thumbnail changes 2019-08-09 11:21:44 +10:00
Shannon a6afa4bb36 one more revert 2019-08-08 19:48:10 +10:00
Shannon 3b6c99a05d Revert "update models to make thumbnail get-only, and map to file"
This reverts commit 8279e6208b.
2019-08-08 19:46:35 +10:00
Shannon b27e10c207 reverting thumbnail changes 2019-08-08 19:45:19 +10:00
Shannon 0c83c3a9a9 Revert thumbnail changes 2019-08-08 19:02:55 +10:00
Shannon 79e033e194 Merge remote-tracking branch 'umbraco/v8/feature/block-editor' into v8/feature/block-editor 2019-08-08 18:30:59 +10:00
Shannon e422ac3d52 Merge branch 'v8/dev' into v8/feature/block-editor 2019-08-08 18:29:42 +10:00
Shannon 8b11792df4 Merge remote-tracking branch 'umbraco/v8/dev' into v8/feature/block-editor 2019-08-08 18:21:51 +10:00
Kenn Jacobsen 57e58c6cf7 Fix broken button to open content type from create dialog 2019-08-08 10:03:47 +02:00
leekelleher 34e45abcc7 Added constants for Property Editor Groups 2019-08-07 20:59:03 +02:00
Kenn Jacobsen b3497011e8 Make content types with description look ok in the create dialog (#5752) 2019-08-07 20:49:14 +02:00
Søren Gregersen a398881fa1 fix: spelling error in comment :)
infinie error(s) fixed
2019-08-07 20:38:37 +02:00
Sebastiaan Janssen 2cf3a7831c Merge pull request #5999 from kjac/v8-fix-allow-remove-user-start-nodes
V8: Allow removing user start nodes
2019-08-07 20:19:48 +02:00
Gopakumar R 0138091a6c Fix for issue #5816 (#5836) 2019-08-07 20:16:18 +02:00
Kenn Jacobsen 6c0fb2f849 Fix the create context menu overflows introduced with 405e9a79 (#5754) 2019-08-07 19:56:30 +02:00
Benjamin Carleski e495faf83c Fix FIPS compliance, add FIPS tests (#5978) 2019-08-07 19:31:08 +02:00
Sebastiaan Janssen 8721423f40 Merge pull request #6016 from umbraco/v8/fix/5906-support-stored-absolute-media-url
Fix exception when stored media url is already absolute
2019-07-29 14:30:03 +02:00
Rasmus John Pedersen 49b3351c72 Fix exception when stored media url is already absolute 2019-07-29 12:59:29 +02:00
Shannon Deminick faef449750 Merge pull request #6009 from bielu/v8/dev
V8: Value Set builder shouldn't stop indexing when one field is empty in …
2019-07-29 11:36:01 +10:00
arkadiuszbiel 4a24064783 Value Set builder shouldn't stop indexing when one field is empty in value sets 2019-07-27 20:41:15 +01:00
Kenn Jacobsen 0ab84fc443 Allow removing user start nodes 2019-07-25 10:28:16 +02:00
Bjarke Berg fca74ad8d7 Merge pull request #5862 from umbraco/v8/bugfix/5789-PublishedContentQuery-Search
Fixes #5789 - PublishedContentQuery Search always searches on culture
2019-07-24 14:16:32 +02:00
Shannon 7bc7dba86d fixes timing issue 2019-07-24 21:46:19 +10:00
Sebastiaan Janssen ca75a25802 Makes checks a little more robust 2019-07-24 11:33:12 +02:00
Shannon ece31733a9 Merge branch 'v8/dev' of https://github.com/umbraco/Umbraco-CMS into v8/dev 2019-07-24 19:25:48 +10:00
Shannon 28a8027179 removes reference to old packages.umbraco.org 2019-07-24 19:25:32 +10:00
Steve Megson a97604d6c4 Handle CSV values in TagsPropertyEditor 2019-07-24 11:14:00 +02:00
Bjarke Berg 308f929f7b Refactored tests to avoid duplicate code 2019-07-24 11:13:21 +02:00
Shannon c8d7df1515 Merge branch 'v8/bugfix/5789-PublishedContentQuery-Search' of https://github.com/umbraco/Umbraco-CMS into v8/bugfix/5789-PublishedContentQuery-Search 2019-07-24 18:46:48 +10:00
Shannon 2c795662d2 Adds tests for PublishedContentQuery search 2019-07-24 18:46:14 +10:00
Kenn Jacobsen 8a43e3a87e Make sure save options are up to date with the content state 2019-07-24 10:46:00 +02:00
Bjarke Berg 210e43fcb0 Fix for build 2019-07-24 09:53:51 +02:00
Shannon Deminick beb8c7ac7c Update src/Umbraco.Web/PublishedContentQuery.cs
Co-Authored-By: Bjarke Berg <mail@bergmania.dk>
2019-07-24 17:30:29 +10:00
Shannon Deminick 2f8979bbc3 Update src/Umbraco.Web/PublishedContentQuery.cs
Co-Authored-By: Bjarke Berg <mail@bergmania.dk>
2019-07-24 17:29:00 +10:00
Shannon a8ed7f2c17 adds new method 2019-07-23 22:11:02 +10:00
Frans de Jong 1c6bf55e5d GetCurrentLoginStatus()
In the summary of MembershipHelper.GetCurrentLoginStatus() it states that null will be returned when no member is logged in but that isn't the case (anymore?).
2019-07-23 13:02:11 +02:00
Bjarke Berg c246044ac7 Merge pull request #5972 from stevemegson/v8/temp-checkboxlist
Content migration - Include CheckBoxList in ValueListPreValueMigrator
2019-07-23 12:47:13 +02:00
Shannon 5126521d37 Fixes #5789 2019-07-23 19:09:15 +10:00
Shannon 27223738c6 Merge branch 'v8/8.1' into v8/dev
# Conflicts:
#	src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs
2019-07-23 19:05:06 +10:00
Steve Megson 968463912a Include CheckBoxList in ValueListPreValueMigrator 2019-07-21 14:47:37 +01:00
Shannon Deminick 05c6b856f9 Merge pull request #5897 from kjac/v8-fix-media-type-add-property
V8: Fix YSOD when editing media types
2019-07-19 15:57:01 +10:00
Shannon 6fe3089207 Merge branch 'v8/8.1' into v8/dev
# Conflicts:
#	src/SolutionInfo.cs
#	src/Umbraco.Web/HtmlHelperRenderExtensions.cs
#	src/Umbraco.Web/Mvc/HttpUmbracoFormRouteStringException.cs
#	src/Umbraco.Web/Mvc/ValidateUmbracoFormRouteStringAttribute.cs
2019-07-17 22:31:54 +10:00
Shannon Deminick 06b136fdf6 Merge pull request #5895 from ronaldbarendse/v8/feature/validate-umbracoformroutestring
Added attribute to validate Umbraco form route strings (ufprt)
2019-07-16 22:01:32 +10:00
Bjarke Berg c6246b5404 Merge remote-tracking branch 'origin/v8/dev' into v8/dev 2019-07-16 13:46:07 +02:00
Bjarke Berg 3062f40ef5 Missing file in project file 2019-07-16 13:43:10 +02:00
Bjarke Berg dcd0d38419 Merge remote-tracking branch 'origin/v8/8.1' into v8/dev 2019-07-16 13:41:30 +02:00
Bjarke Berg c01a8f8f13 Merge pull request #5887 from stevemegson/temp-content-migration
PR fixes 7 -> 8 migration bugs for #5852 and #5864
2019-07-16 13:37:08 +02:00
Kenn Jacobsen da71a94c39 Use IsCollectionEmpty() as per review 2019-07-16 12:45:27 +02:00
Shannon Deminick f6413af3f4 Merge pull request #5885 from hifi-phil/v8/dev
Change PropertyType.Alias to virtual
2019-07-16 20:31:58 +10:00
Bjarke Berg 440e649d6d Merge pull request #5861 from umbraco/v8/bugfix/cdf-upgrade-bug
Fixes issue during upgrade where umbraco can't clear cdf log files
2019-07-15 14:32:19 +02:00
Warren Buckley 47dcd37d1d Merge pull request #5784 from nathanwoulfe/5768-log-viewer-chart-naming
V8: Make log naming and colors consistent between Log Search and Log Overview
2019-07-15 11:47:20 +01:00
Kenn Jacobsen d60fc63e78 Fix YSOD when editing media types 2019-07-15 12:23:09 +02:00
Ronald Barendse b0c4042e87 Removed UmbracoAntiForgeryAdditionalDataProvider 2019-07-15 10:16:09 +02:00
Shannon da525513a3 Merge remote-tracking branch 'origin/v7/dev' into v8/dev
# Conflicts:
#	build/NuSpecs/tools/Web.config.install.xdt
#	src/Umbraco.Web.UI.Client/src/views/common/infiniteeditors/linkpicker/linkpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/member/member.edit.controller.js
#	src/Umbraco.Web/Editors/EntityController.cs
#	src/Umbraco.Web/UmbracoHelper.cs
2019-07-15 16:18:04 +10:00
Shannon Deminick 2ac5e61e44 Merge pull request #5881 from bjarnef/dev-v7-link-picker-url-anchors
v7: Fix link picker url and anchors
2019-07-15 13:02:47 +10:00
Ronald Barendse 101a8b6c78 Added ValidateUmbracoFormRouteStringAttribute to public controllers 2019-07-14 23:18:21 +02:00
Ronald Barendse f7a10e3a15 Added attribute to validate Umbraco form route strings (ufprt) 2019-07-14 23:18:06 +02:00
Steve Megson 4e0dd728a8 Fixes #5864 - migrate prevalues for Umbraco.DropDown.Flexible 2019-07-14 16:48:33 +01:00
Steve Megson 320ccf8105 Fixes #5852 - TablesForScheduledPublishing 2019-07-14 16:46:01 +01:00
hifi-phil 62f924a757 Change PropertyType.Alias to virtual
When unit testing PropertyType.Alias needs to be virtual to make it mockable. The underlying code on the set triggers IOC logic and makes it hard to test anything that uses Property Types.
2019-07-14 09:45:12 +01:00
Bjarne Fyrstenborg c47a08b553 Add overload for NiceUrl 2019-07-13 16:40:01 +02:00
Bjarne Fyrstenborg de9241bcf5 Add UmbracoHelper overload methods to get url by guid 2019-07-13 14:50:25 +02:00
Bjarne Fyrstenborg 7c03fe3c1f Adjust parameter 2019-07-13 14:49:35 +02:00
Bjarne Fyrstenborg 82eb241119 Add overload method for Udi 2019-07-13 14:49:05 +02:00
Bjarne Fyrstenborg 1073e6257c Adjust comments 2019-07-13 14:48:35 +02:00
Nathan Woulfe bc3e4847fe Merge branch '5768-log-viewer-chart-naming' of https://github.com/nathanwoulfe/umbraco-cms into 5768-log-viewer-chart-naming 2019-07-13 13:50:21 +10:00
Nathan Woulfe 1a7251909c fix empty array - was checking index against empty array, so condition was never met 2019-07-13 13:45:13 +10:00
Warren Buckley 61a18297d9 Make v8/dev now 8.2.0 2019-07-12 13:03:20 +01:00
Warren Buckley bdd413f9ee Merge branch 'v8/dev' into 5768-log-viewer-chart-naming 2019-07-12 12:30:32 +01:00
Bjarke Berg fd8ca35e63 Merge pull request #5869 from umbraco/v8/bugfix/logviewer-error-count
V8: Fixes LogViewer Error Count search result click
2019-07-12 12:56:08 +02:00
Warren Buckley fdd9aee773 Fixes LogViewer Error Count search result clickthrough to include errors & fatal without exception as well 2019-07-12 11:07:15 +01:00
Nathan Woulfe 3c2a92d3b6 map log values into logtypedata array - removes need to add these in the correct order. 2019-07-12 14:21:28 +10:00
Nathan Woulfe cf49e6160a critical => fatal 2019-07-12 14:20:28 +10:00
Shannon ec93030e21 Merge branch 'v8/dev' of https://github.com/umbraco/Umbraco-CMS into v8/dev 2019-07-12 11:23:51 +10:00
Shannon 1d49c8626e Revert "V8: Don't show multiple open menus (take two) (#5609)"
This reverts commit 9ce996cbba.
2019-07-12 11:23:36 +10:00
Shannon 89bb94aa1a Fixes issue during upgrade where umbraco can't clear cdf log files 2019-07-12 10:57:26 +10:00
Warren Buckley 03a4b75176 Ran .\build SetUmbracoVersion 8.1.1 to bump version 2019-07-11 15:11:37 +01:00
Sebastiaan Janssen 943b54dcf7 Update 1_Bug.md 2019-07-11 11:55:01 +02:00
Warren Buckley 39bd18ec1a At some point we have upgraded Serilog.Filters.Expressions package & the signature/method name got changed to ByIncludingOnly() 2019-07-11 10:45:41 +01:00
Shannon e93ddff46b Merge branch 'nathanwoulfe-temp-5147-grid-reorder' into v8/dev 2019-07-09 11:01:11 +10:00
Nathan Woulfe 3144b51c91 fix behaviour on page load - don't add active class if sticky-bar is in viewport 2019-07-09 10:49:34 +10:00
Nathan Woulfe e92f68d040 improve variable naming 2019-07-09 10:46:29 +10:00
Nathan Woulfe 469054e9b3 No longer need scrollable-container attribute 2019-07-09 10:46:29 +10:00
Nathan Woulfe d17022d87d make it look pretty 2019-07-09 10:46:29 +10:00
Nathan Woulfe 6865629090 use position:sticky and IntersectionObserver instead of element cloning and position:fixed - much simpler. 2019-07-09 10:46:29 +10:00
Shannon a4749f201d Ensures luceneIndexer.WaitForIndexQueueOnShutdown is called even when not in MainDom 2019-07-08 23:03:20 +10:00
Shannon Deminick ad90264ef1 Merge pull request #5695 from linuselander/issue/5218
Enable removal of unpublished content from ExternalIndex
2019-07-08 19:34:25 +10:00
Shannon Deminick 9ba7e7742a Merge pull request #5801 from bielu/v8/dev
Remove last casting to LuceneIndex
2019-07-08 18:39:40 +10:00
arkadiuszbiel 6473f600c7 Remove last casting to LucenIndex 2019-07-08 08:48:49 +01:00
Nathan Woulfe 6329dfa629 Merge Andy's changes 2019-07-06 07:28:32 +10:00
Andy Butland 2cd0173534 Fixed incorrect label for "Fatal" errors on the log viewer pie chart.
Made the log viewer title variable so it either says "Log Overview For Today" or "Log Overview For Selected Time Period" (previously it said the former even if you'd adjusted the dates you were looking at.
Fixed up the selected date period display so the conjunction "to" is used between the dates when the selected time period is changed and querystring is updated.
Minor code tidy-up.
2019-07-04 14:35:06 +02:00
Nathan Woulfe a0bcfeddcc fix date range formatting on flatpickr - 'to' wasnt displayed after choosing a range 2019-07-04 11:48:02 +10:00
Nathan Woulfe c4b5483d8c make log naming and colors consistent between views 2019-07-04 11:19:10 +10:00
Linus Elander 7557c584d8 Adjusts conditions for which indexes should be affected when a node is unpublished 2019-06-19 21:41:47 +02:00
Kenn Jacobsen 97896e96af Optionally pass block view from editor view + enforce editor view + rename simplelist block view 2019-05-27 21:22:43 +02:00
Nathan Woulfe 5c7a519372 Welcome to hell. This is a set of UI wire up changes, some of which might be a bit opinionated based on my opinion (ie I'm rendering the add content button on the base directive so it's not required to be re-implemented on different implementations). Adds settings for managing alt views too 2019-05-21 22:43:53 +10:00
Nathan Woulfe ae5d82da12 resolve merge conflicts 2019-05-21 02:44:26 +10:00
Nathan Woulfe 6529f472ab wip - will be merge issues with this. 2019-05-21 02:37:56 +10:00
Kenn Jacobsen bfd038f623 Merge branch 'v8/feature/block-editor' of https://github.com/callumbwhyte/Umbraco-CMS into v8/feature/block-editor 2019-05-20 18:37:31 +02:00
Kenn Jacobsen e2b0053d31 Rename default view to simple list 2019-05-20 18:37:12 +02:00
Callum Whyte 6c2401fa27 Ensuring blocks are persisted when settings are saved 2019-05-20 17:24:37 +01:00
Kenn Jacobsen 4b36c72105 Merge branch 'v8/feature/block-editor' of https://github.com/callumbwhyte/Umbraco-CMS into v8/feature/block-editor 2019-05-20 18:19:19 +02:00
Callum Whyte 663228c33b Updating block settings editor 2019-05-20 17:18:51 +01:00
Kenn Jacobsen 36616fb9d1 Split into SimpleGrid 2019-05-20 18:17:57 +02:00
Kenn Jacobsen d71b2a07c4 Refactor block view specification in the block directive 2019-05-20 18:03:21 +02:00
Kenn Jacobsen 7ce4fbe44c Refactor to make it reusable across implementations 2019-05-20 17:40:38 +02:00
Nathan Woulfe f17cd844ff wire up all the ui stuff for previews in pickers, showing name in button when one option exists, proper picker for blocks 2019-05-21 00:35:21 +10:00
Nathan Woulfe f657c635ef remove old thumbnail/icon stuff 2019-05-21 00:33:52 +10:00
Nathan Woulfe 22141af54c thumbnail is get-only and convention-mapped 2019-05-21 00:32:36 +10:00
Nathan Woulfe 1eb1d4dc63 path to thumbnail folder 2019-05-21 00:31:55 +10:00
Nathan Woulfe 8279e6208b update models to make thumbnail get-only, and map to file 2019-05-21 00:31:39 +10:00
Kenn Jacobsen c494ad0adc Fake settings + ability to swap editor and block views 2019-05-20 15:36:57 +02:00
Kenn Jacobsen 53007f4e8b Merge branch 'v8/feature/block-editor' of https://github.com/callumbwhyte/Umbraco-CMS into v8/feature/block-editor 2019-05-20 11:06:55 +02:00
Callum Whyte 8636b5124e Copying add property functionality from doctype builder into block editor 2019-05-20 11:05:18 +01:00
Callum Whyte c2a57a1770 UI for picking block editor element types 2019-05-20 10:43:11 +01:00
Kenn Jacobsen 62e19279a4 Split things into directives 2019-05-20 11:06:38 +02:00
Kenn Jacobsen e41e458322 Rename editblock to editcontent 2019-05-20 10:28:29 +02:00
Kenn Jacobsen acd329381c Plumbing for editing settings 2019-05-20 08:29:08 +02:00
Kenn Jacobsen b064566f9e Store content and settings separately + actually make it work when saving 2019-05-20 07:16:15 +02:00
Kenn Jacobsen 89f93aa81d Bit of work on internal data format 2019-05-19 18:27:02 +02:00
Kenn Jacobsen 013bd2c424 Editor for content editing 2019-05-19 17:48:10 +02:00
Callum Whyte 5cb847930d Ensuring block editor settings JSON properties are lowercased 2019-05-19 14:05:14 +01:00
Callum Whyte ab5e7aa1e8 Primative add-block functionality in block editor settings 2019-05-19 14:04:23 +01:00
Callum Whyte e7303602d2 Listing available element types in block editor settings 2019-05-19 13:08:07 +01:00
Kenn Jacobsen 202302e003 Plumbing going on here 2019-05-19 12:20:46 +02:00
Kenn Jacobsen 174af027e9 Block editor config first stab 2019-05-19 11:59:24 +02:00
Kenn Jacobsen 1a4c45dbdf Add block editor config and config editor 2019-05-19 11:25:29 +02:00
Callum Whyte 2455e2bed9 Adding initial block editor property editor 2019-05-19 10:17:32 +01:00
131 changed files with 1949 additions and 2562 deletions
+1 -1
View File
@@ -12,7 +12,7 @@ thoroughly. Then, proceed by filling out the rest of the details in the issue
template below. The more details you can give us, the easier it will be for us
to determine the cause of a problem.
See: https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/.github/CONTRIBUTING.md
See: https://github.com/umbraco/Umbraco-CMS/blob/v8/dev/.github/CONTRIBUTING.md
-->
+2 -2
View File
@@ -18,5 +18,5 @@ using System.Resources;
[assembly: AssemblyVersion("8.0.0")]
// these are FYI and changed automatically
[assembly: AssemblyFileVersion("8.1.1")]
[assembly: AssemblyInformationalVersion("8.1.1")]
[assembly: AssemblyFileVersion("8.2.0")]
[assembly: AssemblyInformationalVersion("8.2.0")]
@@ -36,6 +36,11 @@ namespace Umbraco.Core
/// </summary>
public static class Aliases
{
/// <summary>
/// Block Editor.
/// </summary>
public const string BlockEditor = "Umbraco.BlockEditor";
/// <summary>
/// CheckBox List.
/// </summary>
@@ -203,6 +208,24 @@ namespace Umbraco.Core
/// <remarks>Must be a valid <see cref="ValueTypes"/> value.</remarks>
public const string DataValueType = "umbracoDataValueType";
}
/// <summary>
/// Defines Umbraco's built-in property editor groups.
/// </summary>
public static class Groups
{
public const string Common = "Common";
public const string Lists = "Lists";
public const string Media = "Media";
public const string People = "People";
public const string Pickers = "Pickers";
public const string RichContent = "Rich Content";
}
}
}
}
@@ -0,0 +1,32 @@
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
{
class DropDownFlexiblePreValueMigrator : IPreValueMigrator
{
public bool CanMigrate(string editorAlias)
=> editorAlias == "Umbraco.DropDown.Flexible";
public virtual string GetNewAlias(string editorAlias)
=> null;
public object GetConfiguration(int dataTypeId, string editorAlias, Dictionary<string, PreValueDto> preValues)
{
var config = new DropDownFlexibleConfiguration();
foreach (var preValue in preValues.Values)
{
if (preValue.Alias == "multiple")
{
config.Multiple = (preValue.Value == "1");
}
else
{
config.Items.Add(new ValueListConfiguration.ValueListItem { Id = preValue.Id, Value = preValue.Value });
}
}
return config;
}
}
}
@@ -19,6 +19,7 @@ public class PreValueMigratorComposer : ICoreComposer
.Append<NestedContentPreValueMigrator>()
.Append<DecimalPreValueMigrator>()
.Append<ListViewPreValueMigrator>()
.Append<DropDownFlexiblePreValueMigrator>()
.Append<ValueListPreValueMigrator>();
}
}
@@ -9,6 +9,7 @@ namespace Umbraco.Core.Migrations.Upgrade.V_8_0_0.DataTypes
private readonly string[] _editors =
{
"Umbraco.RadioButtonList",
"Umbraco.CheckBoxList",
"Umbraco.DropDown",
"Umbraco.DropdownlistPublishingKeys",
"Umbraco.DropDownMultiple",
+1 -1
View File
@@ -114,7 +114,7 @@ namespace Umbraco.Core.Models
/// Gets of sets the alias of the property type.
/// </summary>
[DataMember]
public string Alias
public virtual string Alias
{
get => _alias;
set => SetPropertyValueAndDetectChanges(SanitizeAlias(value), ref _alias, nameof(Alias));
@@ -30,7 +30,7 @@ namespace Umbraco.Core.PropertyEditors
// defaults
Type = type;
Icon = Constants.Icons.PropertyEditor;
Group = "common";
Group = Constants.PropertyEditors.Groups.Common;
// assign properties based on the attribute, if it is found
Attribute = GetType().GetCustomAttribute<DataEditorAttribute>(false);
@@ -121,7 +121,7 @@ namespace Umbraco.Core.PropertyEditors
/// Gets or sets an optional group.
/// </summary>
/// <remarks>The group can be used for example to group the editors by category.</remarks>
public string Group { get; set; } = "common";
public string Group { get; set; } = Constants.PropertyEditors.Groups.Common;
/// <summary>
/// Gets or sets a value indicating whether the value editor is deprecated.
@@ -5,7 +5,11 @@ namespace Umbraco.Core.PropertyEditors
/// <summary>
/// Represents a property editor for label properties.
/// </summary>
[DataEditor(Constants.PropertyEditors.Aliases.Label, "Label", "readonlyvalue", Icon = "icon-readonly")]
[DataEditor(
Constants.PropertyEditors.Aliases.Label,
"Label",
"readonlyvalue",
Icon = "icon-readonly")]
public class LabelPropertyEditor : DataEditor
{
/// <summary>
+1
View File
@@ -241,6 +241,7 @@
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\DefaultPreValueMigrator.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\RenamingPreValueMigrator.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\RichTextPreValueMigrator.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\DropDownFlexiblePreValueMigrator.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\MergeDateAndDateTimePropertyEditor.cs" />
<Compile Include="Models\Entities\EntityExtensions.cs" />
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\PreValueMigratorBase.cs" />
+1 -1
View File
@@ -45,7 +45,7 @@ namespace Umbraco.Examine
continue;
case string strVal:
{
if (strVal.IsNullOrWhiteSpace()) return;
if (strVal.IsNullOrWhiteSpace()) continue;
var key = $"{keyVal.Key}{cultureSuffix}";
if (values.TryGetValue(key, out var v))
values[key] = new List<object>(v) { val }.ToArray();
+28 -1
View File
@@ -48,6 +48,31 @@ namespace Umbraco.Examine
}
}
/// <summary>
/// Returns all index fields that are culture specific (suffixed) or invariant
/// </summary>
/// <param name="index"></param>
/// <param name="culture"></param>
/// <returns></returns>
public static IEnumerable<string> GetCultureAndInvariantFields(this IUmbracoIndex index, string culture)
{
var allFields = index.GetFields();
// ReSharper disable once LoopCanBeConvertedToQuery
foreach (var field in allFields)
{
var match = CultureIsoCodeFieldNameMatchExpression.Match(field);
if (match.Success && match.Groups.Count == 3 && culture.InvariantEquals(match.Groups[2].Value))
{
yield return field; //matches this culture field
}
else if (!match.Success)
{
yield return field; //matches no culture field (invariant)
}
}
}
internal static bool TryParseLuceneQuery(string query)
{
// TODO: I'd assume there would be a more strict way to parse the query but not that i can find yet, for now we'll
@@ -77,7 +102,7 @@ namespace Umbraco.Examine
/// <remarks>
/// This is not thread safe, use with care
/// </remarks>
internal static void UnlockLuceneIndexes(this IExamineManager examineManager, ILogger logger)
internal static void ConfigureLuceneIndexes(this IExamineManager examineManager, ILogger logger, bool disableExamineIndexing)
{
foreach (var luceneIndexer in examineManager.Indexes.OfType<LuceneIndex>())
{
@@ -86,6 +111,8 @@ namespace Umbraco.Examine
//that could end up halting shutdown for a very long time causing overlapping appdomains and many other problems.
luceneIndexer.WaitForIndexQueueOnShutdown = false;
if (disableExamineIndexing) continue; //exit if not enabled, we don't need to unlock them if we're not maindom
//we should check if the index is locked ... it shouldn't be! We are using simple fs lock now and we are also ensuring that
//the indexes are not operational unless MainDom is true
var dir = luceneIndexer.GetLuceneDirectory();
@@ -268,7 +268,7 @@ AnotherContentFinder
public void GetDataEditors()
{
var types = _typeLoader.GetDataEditors();
Assert.AreEqual(38, types.Count());
Assert.AreEqual(39, types.Count());
}
/// <summary>
@@ -81,6 +81,19 @@ namespace Umbraco.Tests.Routing
Assert.AreEqual(expected, resolvedUrl);
}
[Test]
public void Get_Media_Url_Returns_Absolute_Url_If_Stored_Url_Is_Absolute()
{
const string expected = "http://localhost/media/rfeiw584/test.jpg";
var umbracoContext = GetUmbracoContext("http://localhost", mediaUrlProviders: new[] { _mediaUrlProvider });
var publishedContent = CreatePublishedContent(Constants.PropertyEditors.Aliases.UploadField, expected, null);
var resolvedUrl = umbracoContext.UrlProvider.GetMediaUrl(publishedContent, UrlMode.Relative);
Assert.AreEqual(expected, resolvedUrl);
}
[Test]
public void Get_Media_Url_Returns_Empty_String_When_PropertyType_Is_Not_Supported()
{
@@ -25,19 +25,23 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting
public async Task<Tuple<HttpResponseMessage, string>> Execute(string controllerName, string actionName, HttpMethod method,
HttpContent content = null,
MediaTypeWithQualityHeaderValue mediaTypeHeader = null,
bool assertOkResponse = true)
bool assertOkResponse = true, object routeDefaults = null, string url = null)
{
if (mediaTypeHeader == null)
{
mediaTypeHeader = new MediaTypeWithQualityHeaderValue("application/json");
}
if (routeDefaults == null)
{
routeDefaults = new { controller = controllerName, action = actionName, id = RouteParameter.Optional };
}
var startup = new TestStartup(
configuration =>
{
configuration.Routes.MapHttpRoute("Default",
routeTemplate: "{controller}/{action}/{id}",
defaults: new { controller = controllerName, action = actionName, id = RouteParameter.Optional });
defaults: routeDefaults);
},
_controllerFactory);
@@ -45,7 +49,7 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting
{
var request = new HttpRequestMessage
{
RequestUri = new Uri("https://testserver/"),
RequestUri = new Uri("https://testserver/" + (url ?? "")),
Method = method
};
@@ -0,0 +1,22 @@
using Lucene.Net.Store;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Umbraco.Tests.TestHelpers
{
/// <summary>
/// Used for tests with Lucene so that each RAM directory is unique
/// </summary>
public class RandomIdRAMDirectory : RAMDirectory
{
private readonly string _lockId = Guid.NewGuid().ToString();
public override string GetLockId()
{
return _lockId;
}
}
}
+3
View File
@@ -157,6 +157,7 @@
<Compile Include="Services\MemberGroupServiceTests.cs" />
<Compile Include="Services\MediaTypeServiceTests.cs" />
<Compile Include="Services\PropertyValidationServiceTests.cs" />
<Compile Include="TestHelpers\RandomIdRamDirectory.cs" />
<Compile Include="Testing\Objects\TestDataSource.cs" />
<Compile Include="Published\PublishedSnapshotTestObjects.cs" />
<Compile Include="Published\ModelTypeTests.cs" />
@@ -242,6 +243,7 @@
<Compile Include="Cache\FullDataSetCachePolicyTests.cs" />
<Compile Include="Cache\SingleItemsOnlyCachePolicyTests.cs" />
<Compile Include="Collections\DeepCloneableListTests.cs" />
<Compile Include="Web\Controllers\AuthenticationControllerTests.cs" />
<Compile Include="Web\Controllers\BackOfficeControllerUnitTests.cs" />
<Compile Include="CoreThings\DelegateExtensionsTests.cs" />
<Compile Include="Web\Controllers\ContentControllerTests.cs" />
@@ -268,6 +270,7 @@
<Compile Include="Strings\StylesheetHelperTests.cs" />
<Compile Include="Strings\StringValidationTests.cs" />
<Compile Include="Web\Mvc\ValidateUmbracoFormRouteStringAttributeTests.cs" />
<Compile Include="Web\PublishedContentQueryTests.cs" />
<Compile Include="Web\UmbracoHelperTests.cs" />
<Compile Include="Membership\MembershipProviderBaseTests.cs" />
<Compile Include="Membership\UmbracoServiceMembershipProviderTests.cs" />
@@ -0,0 +1,139 @@
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Reflection;
using System.Security.Cryptography;
using System.Threading;
using System.Web;
using System.Web.Hosting;
using System.Web.Http;
using Moq;
using Newtonsoft.Json;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Composing;
using Umbraco.Core.Configuration;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Mappers;
using Umbraco.Core.Persistence.Querying;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Core.Services;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.TestHelpers.ControllerTesting;
using Umbraco.Tests.Testing;
using Umbraco.Web;
using Umbraco.Web.Editors;
using Umbraco.Web.Features;
using Umbraco.Web.Models.ContentEditing;
using IUser = Umbraco.Core.Models.Membership.IUser;
namespace Umbraco.Tests.Web.Controllers
{
[TestFixture]
[UmbracoTest(Database = UmbracoTestOptions.Database.None)]
public class AuthenticationControllerTests : TestWithDatabaseBase
{
protected override void ComposeApplication(bool withApplication)
{
base.ComposeApplication(withApplication);
//if (!withApplication) return;
// replace the true IUserService implementation with a mock
// so that each test can configure the service to their liking
Composition.RegisterUnique(f => Mock.Of<IUserService>());
// kill the true IEntityService too
Composition.RegisterUnique(f => Mock.Of<IEntityService>());
Composition.RegisterUnique<UmbracoFeatures>();
}
[Test]
public async System.Threading.Tasks.Task GetCurrentUser_Fips()
{
ApiController CtrlFactory(HttpRequestMessage message, IUmbracoContextAccessor umbracoContextAccessor, UmbracoHelper helper)
{
//setup some mocks
var userServiceMock = Mock.Get(Current.Services.UserService);
userServiceMock.Setup(service => service.GetUserById(It.IsAny<int>()))
.Returns(() => null);
if (Thread.GetDomain().GetData(".appPath") != null)
{
HttpContext.Current = new HttpContext(new SimpleWorkerRequest("", "", new StringWriter()));
}
else
{
var baseDir = IOHelper.MapPath("", false).TrimEnd(IOHelper.DirSepChar);
HttpContext.Current = new HttpContext(new SimpleWorkerRequest("/", baseDir, "", "", new StringWriter()));
}
IOHelper.ForceNotHosted = true;
var usersController = new AuthenticationController(
Factory.GetInstance<IGlobalSettings>(),
umbracoContextAccessor,
Factory.GetInstance<ISqlContext>(),
Factory.GetInstance<ServiceContext>(),
Factory.GetInstance<AppCaches>(),
Factory.GetInstance<IProfilingLogger>(),
Factory.GetInstance<IRuntimeState>(),
helper);
return usersController;
}
Mock.Get(Current.SqlContext)
.Setup(x => x.Query<IUser>())
.Returns(new Query<IUser>(Current.SqlContext));
var syntax = new SqlCeSyntaxProvider();
Mock.Get(Current.SqlContext)
.Setup(x => x.SqlSyntax)
.Returns(syntax);
var mappers = new MapperCollection(new[]
{
new UserMapper(new Lazy<ISqlContext>(() => Current.SqlContext), new ConcurrentDictionary<Type, ConcurrentDictionary<string, string>>())
});
Mock.Get(Current.SqlContext)
.Setup(x => x.Mappers)
.Returns(mappers);
// Testing what happens if the system were configured to only use FIPS-compliant algorithms
var typ = typeof(CryptoConfig);
var flds = typ.GetFields(BindingFlags.Static | BindingFlags.NonPublic);
var haveFld = flds.FirstOrDefault(f => f.Name == "s_haveFipsAlgorithmPolicy");
var isFld = flds.FirstOrDefault(f => f.Name == "s_fipsAlgorithmPolicy");
var originalFipsValue = CryptoConfig.AllowOnlyFipsAlgorithms;
try
{
if (!originalFipsValue)
{
haveFld.SetValue(null, true);
isFld.SetValue(null, true);
}
var runner = new TestRunner(CtrlFactory);
var response = await runner.Execute("Authentication", "GetCurrentUser", HttpMethod.Get);
var obj = JsonConvert.DeserializeObject<UserDetail>(response.Item2);
Assert.AreEqual(-1, obj.UserId);
}
finally
{
if (!originalFipsValue)
{
haveFld.SetValue(null, false);
isFld.SetValue(null, false);
}
}
}
}
}
@@ -4,6 +4,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Reflection;
using System.Security.Cryptography;
using System.Web.Http;
using Moq;
using Newtonsoft.Json;
@@ -155,7 +157,7 @@ namespace Umbraco.Tests.Web.Controllers
var runner = new TestRunner(CtrlFactory);
var response = await runner.Execute("Users", "GetPagedUsers", HttpMethod.Get);
var obj = JsonConvert.DeserializeObject<PagedResult<UserDisplay>>(response.Item2);
var obj = JsonConvert.DeserializeObject<PagedResult<UserBasic>>(response.Item2);
Assert.AreEqual(0, obj.TotalItems);
}
@@ -190,9 +192,100 @@ namespace Umbraco.Tests.Web.Controllers
var runner = new TestRunner(CtrlFactory);
var response = await runner.Execute("Users", "GetPagedUsers", HttpMethod.Get);
var obj = JsonConvert.DeserializeObject<PagedResult<UserDisplay>>(response.Item2);
var obj = JsonConvert.DeserializeObject<PagedResult<UserBasic>>(response.Item2);
Assert.AreEqual(10, obj.TotalItems);
Assert.AreEqual(10, obj.Items.Count());
}
[Test]
public async System.Threading.Tasks.Task GetPagedUsers_Fips()
{
await RunFipsTest("GetPagedUsers", mock =>
{
var users = MockedUser.CreateMulipleUsers(10);
long outVal = 10;
mock.Setup(service => service.GetAll(
It.IsAny<long>(), It.IsAny<int>(), out outVal, It.IsAny<string>(), It.IsAny<Direction>(),
It.IsAny<UserState[]>(), It.IsAny<string[]>(), It.IsAny<string[]>(), It.IsAny<IQuery<IUser>>()))
.Returns(() => users);
}, response =>
{
var obj = JsonConvert.DeserializeObject<PagedResult<UserBasic>>(response.Item2);
Assert.AreEqual(10, obj.TotalItems);
Assert.AreEqual(10, obj.Items.Count());
});
}
[Test]
public async System.Threading.Tasks.Task GetById_Fips()
{
const int mockUserId = 1234;
var user = MockedUser.CreateUser();
await RunFipsTest("GetById", mock =>
{
mock.Setup(service => service.GetUserById(1234))
.Returns((int i) => i == mockUserId ? user : null);
}, response =>
{
var obj = JsonConvert.DeserializeObject<UserDisplay>(response.Item2);
Assert.AreEqual(user.Username, obj.Username);
Assert.AreEqual(user.Email, obj.Email);
}, new { controller = "Users", action = "GetById" }, $"Users/GetById/{mockUserId}");
}
private async System.Threading.Tasks.Task RunFipsTest(string action, Action<Mock<IUserService>> userServiceSetup,
Action<Tuple<HttpResponseMessage, string>> verification,
object routeDefaults = null, string url = null)
{
ApiController CtrlFactory(HttpRequestMessage message, IUmbracoContextAccessor umbracoContextAccessor, UmbracoHelper helper)
{
//setup some mocks
var userServiceMock = Mock.Get(Current.Services.UserService);
userServiceSetup(userServiceMock);
var usersController = new UsersController(
Factory.GetInstance<IGlobalSettings>(),
umbracoContextAccessor,
Factory.GetInstance<ISqlContext>(),
Factory.GetInstance<ServiceContext>(),
Factory.GetInstance<AppCaches>(),
Factory.GetInstance<IProfilingLogger>(),
Factory.GetInstance<IRuntimeState>(),
helper);
return usersController;
}
// Testing what happens if the system were configured to only use FIPS-compliant algorithms
var typ = typeof(CryptoConfig);
var flds = typ.GetFields(BindingFlags.Static | BindingFlags.NonPublic);
var haveFld = flds.FirstOrDefault(f => f.Name == "s_haveFipsAlgorithmPolicy");
var isFld = flds.FirstOrDefault(f => f.Name == "s_fipsAlgorithmPolicy");
var originalFipsValue = CryptoConfig.AllowOnlyFipsAlgorithms;
try
{
if (!originalFipsValue)
{
haveFld.SetValue(null, true);
isFld.SetValue(null, true);
}
MockForGetPagedUsers();
var runner = new TestRunner(CtrlFactory);
var response = await runner.Execute("Users", action, HttpMethod.Get, routeDefaults: routeDefaults, url: url);
verification(response);
}
finally
{
if (!originalFipsValue)
{
haveFld.SetValue(null, false);
isFld.SetValue(null, false);
}
}
}
}
}
@@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Examine;
using Examine.LuceneEngine.Providers;
using Lucene.Net.Store;
using Moq;
using NUnit.Framework;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Examine;
using Umbraco.Tests.TestHelpers;
using Umbraco.Web;
using Umbraco.Web.PublishedCache;
namespace Umbraco.Tests.Web
{
[TestFixture]
public class PublishedContentQueryTests
{
private class TestIndex : LuceneIndex, IUmbracoIndex
{
private readonly string[] _fieldNames;
public TestIndex(string name, Directory luceneDirectory, string[] fieldNames)
: base(name, luceneDirectory, null, null, null, null)
{
_fieldNames = fieldNames;
}
public bool EnableDefaultEventHandler => throw new NotImplementedException();
public bool PublishedValuesOnly => throw new NotImplementedException();
public IEnumerable<string> GetFields() => _fieldNames;
}
private TestIndex CreateTestIndex(Directory luceneDirectory, string[] fieldNames)
{
var indexer = new TestIndex("TestIndex", luceneDirectory, fieldNames);
using (indexer.ProcessNonAsync())
{
//populate with some test data
indexer.IndexItem(new ValueSet("1", "content", new Dictionary<string, object>
{
[fieldNames[0]] = "Hello world, there are products here",
[UmbracoContentIndex.VariesByCultureFieldName] = "n"
}));
indexer.IndexItem(new ValueSet("2", "content", new Dictionary<string, object>
{
[fieldNames[1]] = "Hello world, there are products here",
[UmbracoContentIndex.VariesByCultureFieldName] = "y"
}));
indexer.IndexItem(new ValueSet("3", "content", new Dictionary<string, object>
{
[fieldNames[2]] = "Hello world, there are products here",
[UmbracoContentIndex.VariesByCultureFieldName] = "y"
}));
}
return indexer;
}
private PublishedContentQuery CreatePublishedContentQuery(IIndex indexer)
{
var examineManager = new Mock<IExamineManager>();
IIndex outarg = indexer;
examineManager.Setup(x => x.TryGetIndex("TestIndex", out outarg)).Returns(true);
var contentCache = new Mock<IPublishedContentCache>();
contentCache.Setup(x => x.GetById(It.IsAny<int>())).Returns((int intId) => Mock.Of<IPublishedContent>(x => x.Id == intId));
var snapshot = Mock.Of<IPublishedSnapshot>(x => x.Content == contentCache.Object);
var variationContext = new VariationContext();
var variationContextAccessor = Mock.Of<IVariationContextAccessor>(x => x.VariationContext == variationContext);
return new PublishedContentQuery(snapshot, variationContextAccessor, examineManager.Object);
}
[TestCase("fr-fr", ExpectedResult = "1, 3", TestName = "Search Culture: fr-fr. Must return both fr-fr and invariant results")]
[TestCase("en-us", ExpectedResult = "1, 2", TestName = "Search Culture: en-us. Must return both en-us and invariant results")]
[TestCase("*", ExpectedResult = "1, 2, 3", TestName = "Search Culture: *. Must return all cultures and all invariant results")]
[TestCase(null, ExpectedResult = "1", TestName = "Search Culture: null. Must return only invariant results")]
public string Search(string culture)
{
using (var luceneDir = new RandomIdRAMDirectory())
{
var fieldNames = new[] { "title", "title_en-us", "title_fr-fr" };
using (var indexer = CreateTestIndex(luceneDir, fieldNames))
{
var pcq = CreatePublishedContentQuery(indexer);
var results = pcq.Search("Products", culture, "TestIndex");
var ids = results.Select(x => x.Content.Id).ToArray();
return string.Join(", ", ids);
}
}
}
}
}
+7 -3
View File
@@ -1,5 +1,8 @@
using System;
using System.Text;
using Examine.LuceneEngine;
using Lucene.Net.Analysis;
using Lucene.Net.Analysis.Standard;
using Moq;
using NUnit.Framework;
using Umbraco.Core;
@@ -13,18 +16,19 @@ using Umbraco.Web;
namespace Umbraco.Tests.Web
{
[TestFixture]
public class UmbracoHelperTests
{
{
[TearDown]
public void TearDown()
{
Current.Reset();
}
// ------- Int32 conversion tests
[Test]
public static void Converting_Boxed_34_To_An_Int_Returns_34()
@@ -23,7 +23,7 @@ module.exports = function(files, out) {
// sort files in stream by path or any custom sort comparator
task = task.pipe(babel())
.pipe(sort())
.pipe(embedTemplates({ basePath: "./src/" }))
.pipe(embedTemplates({ basePath: "./src/", minimize:{ loose: true } }))
.pipe(concat(out))
.pipe(wrap('(function(){\n%= body %\n})();'))
.pipe(gulp.dest(config.root + config.targets.js));
+25 -44
View File
@@ -1222,7 +1222,7 @@
"arraybuffer.slice": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
"integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==",
"integrity": "sha1-O7xCdd1YTMGxCAm4nU6LY6aednU=",
"dev": true
},
"asap": {
@@ -1284,7 +1284,7 @@
"async-limiter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==",
"integrity": "sha1-ePrtjD0HSrgfIrTphdeehzj3IPg=",
"dev": true
},
"asynckit": {
@@ -1535,7 +1535,7 @@
},
"bl": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
"resolved": "http://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
"integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==",
"dev": true,
"requires": {
@@ -2516,7 +2516,7 @@
"content-type": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
"integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=",
"dev": true
},
"continuable-cache": {
@@ -4045,7 +4045,7 @@
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
"dev": true,
"requires": {
"ms": "2.0.0"
@@ -4081,7 +4081,7 @@
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
"dev": true,
"requires": {
"ms": "2.0.0"
@@ -4476,7 +4476,7 @@
"eventemitter3": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz",
"integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==",
"integrity": "sha1-CQtNbNvWRe0Qv3UNS1QHlC17oWM=",
"dev": true
},
"exec-buffer": {
@@ -5309,8 +5309,7 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"aproba": {
"version": "1.2.0",
@@ -5331,14 +5330,12 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -5353,20 +5350,17 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"core-util-is": {
"version": "1.0.2",
@@ -5483,8 +5477,7 @@
"inherits": {
"version": "2.0.3",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"ini": {
"version": "1.3.5",
@@ -5496,7 +5489,6 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -5511,7 +5503,6 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@@ -5519,14 +5510,12 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"minipass": {
"version": "2.2.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.1",
"yallist": "^3.0.0"
@@ -5545,7 +5534,6 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@@ -5626,8 +5614,7 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"object-assign": {
"version": "4.1.1",
@@ -5639,7 +5626,6 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@@ -5725,8 +5711,7 @@
"safe-buffer": {
"version": "5.1.1",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"safer-buffer": {
"version": "2.1.2",
@@ -5762,7 +5747,6 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@@ -5782,7 +5766,6 @@
"version": "3.0.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@@ -5826,14 +5809,12 @@
"wrappy": {
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true
"dev": true
},
"yallist": {
"version": "3.0.2",
"bundled": true,
"dev": true,
"optional": true
"dev": true
}
}
},
@@ -7575,7 +7556,7 @@
"has-binary2": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz",
"integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==",
"integrity": "sha1-d3asYn8+p3JQz8My2rfd9eT10R0=",
"dev": true,
"requires": {
"isarray": "2.0.1"
@@ -7778,7 +7759,7 @@
"http-proxy": {
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz",
"integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==",
"integrity": "sha1-etOElGWPhGBeL220Q230EPTlvpo=",
"dev": true,
"requires": {
"eventemitter3": "^3.0.0",
@@ -13616,7 +13597,7 @@
"qjobs": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz",
"integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==",
"integrity": "sha1-xF6cYYAL0IfviNfiVkI73Unl0HE=",
"dev": true
},
"qs": {
@@ -14787,7 +14768,7 @@
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
"dev": true,
"requires": {
"ms": "2.0.0"
@@ -15860,7 +15841,7 @@
"type-is": {
"version": "1.6.16",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz",
"integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==",
"integrity": "sha1-+JzjQVQcZysl7nrjxz3uOyvlAZQ=",
"dev": true,
"requires": {
"media-typer": "0.3.0",
@@ -15902,7 +15883,7 @@
"ultron": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz",
"integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==",
"integrity": "sha1-n+FTahCmZKZSZqHjzPhf02MCvJw=",
"dev": true
},
"unc-path-regex": {
@@ -16505,7 +16486,7 @@
"ws": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz",
"integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==",
"integrity": "sha1-8c+E/i1ekB686U767OeF8YeiKPI=",
"dev": true,
"requires": {
"async-limiter": "~1.0.0",
@@ -0,0 +1,65 @@
(function () {
"use strict";
/**
* A component used to render a list of blocks
*/
var umbBlockList = {
templateUrl: 'views/components/blockeditor/umb-block-list.html',
bindings: {
blocks: "<",
config: "<",
scaffolds: "<",
onEdit: "&",
onRemove: "&",
onSettings: "&",
onSort: "&?"
},
controllerAs: 'vm',
controller: umbBlockListController
};
function umbBlockListController() {
var vm = this;
vm.sortableOptions = {
axis: "y",
cursor: "move",
handle: ".handle",
tolerance: 'pointer',
update: function (e, ui) {
if (vm.onSort) {
vm.onSort({ e: e, ui: ui });
}
}
};
vm.editContent = function (block) {
var scaffold = _.findWhere(vm.scaffolds, {
udi: block.udi
});
var element = angular.copy(scaffold);
_.each(element.variants[0].tabs, function (tab) {
_.each(tab.properties, function (property) {
if (block.content[property.alias]) {
property.value = block.content[property.alias];
}
});
});
vm.onEdit({ element: element, block: block });
}
vm.remove = function (block) {
// this should be replaced by a custom dialog (pending some PRs)
if (confirm("TODO: Are you sure?")) {
vm.onRemove({ block: block });
}
}
}
angular.module('umbraco').component('umbBlockList', umbBlockList);
})();
@@ -94,6 +94,10 @@
content.apps[0].active = true;
$scope.appChanged(content.apps[0]);
}
// otherwise make sure the save options are up to date with the current content state
else {
createButtons($scope.content);
}
editorState.set(content);
@@ -101,14 +101,14 @@ angular.module('umbraco.directives')
var eventBindings = [];
function oneTimeClick(event) {
// ignore clicks on button groups toggles (i.e. the save and publish button)
var parents = $(event.target).closest("[data-element='button-group-toggle']");
if (parents.length > 0) {
return;
}
var el = event.target.nodeName;
//ignore link and button clicks
var els = ["INPUT", "A", "BUTTON"];
if (els.indexOf(el) >= 0) { return; }
// ignore clicks on new overlay
parents = $(event.target).parents(".umb-overlay,.umb-tour");
var parents = $(event.target).parents("a,button,.umb-overlay,.umb-tour");
if (parents.length > 0) {
return;
}
@@ -131,12 +131,6 @@ angular.module('umbraco.directives')
return;
}
// ignore clicks on dialog actions
var actions = $(event.target).parents(".umb-action");
if (actions.length === 1) {
return;
}
//ignore clicks inside this element
if ($(element).has($(event.target)).length > 0) {
return;
@@ -4,7 +4,7 @@
@restrict A
@description
Use this directive make an element sticky and follow the page when scrolling.
Use this directive make an element sticky and follow the page when scrolling. `umb-sticky-bar--active` class is applied when the element is stuck
<h3>Markup example</h3>
<pre>
@@ -12,140 +12,102 @@ Use this directive make an element sticky and follow the page when scrolling.
<div
class="my-sticky-bar"
umb-sticky-bar
scrollable-container=".container">
umb-sticky-bar>
</div>
</div>
</pre>
<h3>CSS example</h3>
<pre>
.my-sticky-bar {
padding: 15px 0;
background: #000000;
position: relative;
top: 0;
}
.my-sticky-bar.-umb-sticky-bar {
top: 100px;
}
</pre>
@param {string} scrollableContainer Set the class (".element") or the id ("#element") of the scrollable container element.
**/
(function () {
'use strict';
function StickyBarDirective($rootScope) {
function StickyBarDirective() {
/**
On initial load, the intersector fires if the grid editor is in the viewport
This flag is used to suppress the setClass behaviour on the initial load
**/
var initial = true;
/**
Toggle `umb-sticky-bar--active` class on the sticky-bar element
**/
function setClass(addClass, current) {
if (!initial) {
current.classList.toggle('umb-sticky-bar--active', addClass);
} else {
initial = false;
}
}
/**
Inserts two elements in the umbStickyBar parent element
These are used by the IntersectionObserve to calculate scroll position
**/
function addSentinels(current) {
['-top', '-bottom'].forEach(s => {
const sentinel = document.createElement('div');
sentinel.classList.add('umb-sticky-sentinel', s);
current.parentElement.appendChild(sentinel);
});
}
/**
Calls into setClass when the footer sentinel enters/exits the bottom of the container
Container is the parent element of the umbStickyBar element
**/
function observeFooter(current, container) {
const observer = new IntersectionObserver((records, observer) => {
let [target, rootBounds, intersected] = [records[0].boundingClientRect, records[0].rootBounds, records[0].intersectionRatio === 1];
if (target.bottom > rootBounds.top && intersected) {
setClass(true, current);
}
if (target.top < rootBounds.top && target.bottom < rootBounds.bottom) {
setClass(false, current);
}
}, {
threshold: [1],
root: container
});
observer.observe(current.parentElement.querySelector('.umb-sticky-sentinel.-bottom'));
}
/**
Calls into setClass when the header sentinel enters/exits the top of the container
Container is the parent element of the umbStickyBar element
**/
function observeHeader(current, container) {
const observer = new IntersectionObserver((records, observer) => {
let [target, rootBounds] = [records[0].boundingClientRect, records[0].rootBounds];
if (target.bottom < rootBounds.top) {
setClass(true, current);
}
if (target.bottom >= rootBounds.top && target.bottom < rootBounds.bottom) {
setClass(false, current);
}
}, {
threshold: [0],
root: container
});
observer.observe(current.parentElement.querySelector('.umb-sticky-sentinel.-top'));
}
function link(scope, el, attr, ctrl) {
var bar = $(el);
var scrollableContainer = null;
var clonedBar = null;
var cloneIsMade = false;
let current = el[0];
let container = current.closest('[data-element="editor-container"]');
function activate() {
if (bar.parents(".umb-property").length > 1) {
bar.addClass("nested");
return;
}
if (attr.scrollableContainer) {
scrollableContainer = bar.closest(attr.scrollableContainer);
} else {
scrollableContainer = $(window);
}
scrollableContainer.on('scroll.umbStickyBar', determineVisibility).trigger("scroll");
$(window).on('resize.umbStickyBar', determineVisibility);
scope.$on('$destroy', function () {
scrollableContainer.off('.umbStickyBar');
$(window).off('.umbStickyBar');
});
}
function determineVisibility() {
var barTop = bar[0].offsetTop;
var scrollTop = scrollableContainer.scrollTop();
if (scrollTop > barTop) {
if (!cloneIsMade) {
createClone();
clonedBar.css({
'visibility': 'visible'
});
} else {
calculateSize();
}
} else {
if (cloneIsMade) {
//remove cloned element (switched places with original on creation)
bar.remove();
bar = clonedBar;
clonedBar = null;
bar.removeClass('-umb-sticky-bar');
bar.css({
position: 'relative',
'width': 'auto',
'height': 'auto',
'z-index': 'auto',
'visibility': 'visible'
});
cloneIsMade = false;
}
}
}
function calculateSize() {
var width = bar.innerWidth();
clonedBar.css({
width: width + 10 // + 10 (5*2) because we need to add border to avoid seeing the shadow beneath. Look at the CSS.
});
}
function createClone() {
//switch place with cloned element, to keep binding intact
clonedBar = bar;
bar = clonedBar.clone();
clonedBar.after(bar);
clonedBar.addClass('-umb-sticky-bar');
clonedBar.css({
'position': 'fixed',
// if you change this z-index value, make sure the sticky editor sub headers do not
// clash with umb-dropdown (e.g. the content actions dropdown in content list view)
'z-index': 99,
'visibility': 'hidden'
});
cloneIsMade = true;
calculateSize();
}
activate();
addSentinels(current);
observeHeader(current, container);
observeFooter(current, container);
}
var directive = {
@@ -509,6 +509,20 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
});
},
getScaffoldByUdi: function (parentId, udi) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"contentApiBaseUrl",
"GetEmpty",
[{ udi: udi }, { parentId: parentId }])),
'Failed to retrieve data for empty content item with udi ' + udi)
.then(function (result) {
return $q.when(umbDataFormatter.formatContentGetData(result));
});
},
getBlueprintScaffold: function (parentId, blueprintId) {
return umbRequestHelper.resourcePromise(
@@ -172,7 +172,7 @@ function entityResource($q, $http, umbRequestHelper) {
umbRequestHelper.getApiUrl(
"entityApiBaseUrl",
"GetUrlAndAnchors",
{ id: id })),
[{ id: id }])),
'Failed to retrieve url and anchors data for id ' + id);
},
@@ -261,7 +261,7 @@ When building a custom infinite editor view you can use the same components as a
*/
unbindKeyboardShortcuts();
// set flag so we know when the editor is open in "infinie mode"
// set flag so we know when the editor is open in "infinite mode"
editor.infiniteMode = true;
editors.push(editor);
@@ -32,15 +32,32 @@
border-radius: 3px;
}
.umb-editor-sub-header.-umb-sticky-bar {
box-shadow: 0 6px 3px -3px rgba(0,0,0,.16);
[umb-sticky-bar] {
transition: box-shadow 240ms;
margin-top: 0;
margin-top: 0;
margin-bottom: 0;
top: calc(@appHeaderHeight + @editorHeaderHeight);
position:sticky;
z-index: 99;
.umb-editor--infinityMode & {
top: calc(@editorHeaderHeight);
&.umb-sticky-bar--active {
box-shadow: 0 6px 3px -3px rgba(0,0,0,.16);
}
}
.umb-sticky-sentinel {
position: absolute;
left: 0;
width: 100%;
pointer-events: none;
&.-top {
top:0px;
height:1px;
}
&.-bottom {
bottom:50px;
height:10px;
}
}
@@ -132,6 +132,10 @@
&.umb-overlay--medium {
width: 480px;
}
&.umb-overlay--large {
width:640px;
}
}
.umb-overlay.umb-overlay-target .umb-overlay-header {
@@ -94,6 +94,7 @@
font-size: 14px;
color: @black;
margin-left: 10px;
text-align: left;
}
small {
@@ -5,6 +5,7 @@
// --------------------------------------------------
.umb-property-editor {
width: 100%;
position:relative;
}
.umb-property-editor-tiny {
@@ -165,8 +166,6 @@
.sp-replacer {
display: inline-flex;
margin-right: 18px;
border: solid 1px @gray-8;
border-radius: 3px;
}
label {
@@ -59,10 +59,10 @@ angular.module("umbraco").controller("Umbraco.Editors.LinkPickerController",
if (dialogOptions.currentTarget) {
// clone the current target so we don't accidentally update the caller's model while manipulating $scope.model.target
$scope.model.target = angular.copy(dialogOptions.currentTarget);
//if we have a node ID, we fetch the current node to build the form data
// if we have a node ID, we fetch the current node to build the form data
if ($scope.model.target.id || $scope.model.target.udi) {
//will be either a udi or an int
// will be either a udi or an int
var id = $scope.model.target.udi ? $scope.model.target.udi : $scope.model.target.id;
if ($scope.model.target.udi) {
@@ -0,0 +1,18 @@
<ul class="unstyled" ui-sortable="vm.sortableOptions" ng-model="vm.blocks">
<li ng-repeat="block in vm.blocks">
<div class="handle">
<div class="umb-node-preview umb-node-preview--sortable">
<i ng-if="block.icon" class="umb-node-preview__icon {{ block.icon }}"></i>
<div class="umb-node-preview__content">
<div class="umb-node-preview__name" ng-attr-title="{{block.alias}}">TODO: Figure out how to name a block</div>
<div class="umb-node-preview__description" ng-if="block.description">{{ block.description }}</div>
</div>
<div class="umb-node-preview__actions">
<a class="umb-node-preview__action" title="Edit" href="" ng-click="vm.editContent(block)"><localize key="general_edit">Edit</localize></a>
<a class="umb-node-preview__action" title="Settings" href="" ng-click="vm.onSettings({block: block})"><localize key="general_settings">Settings</localize></a>
<a class="umb-node-preview__action umb-node-preview__action--red" title="Remove" ng-href="" ng-click="vm.remove(block)"><localize key="general_remove">Remove</localize></a>
</div>
</div>
</div>
</li>
</ul>
@@ -1,6 +1,5 @@
<div
class="umb-editor-sub-header umb-editor-sub-header--{{appearance}}"
umb-sticky-bar
scrollable-container=".umb-editor-container"
ng-transclude>
</div>
@@ -32,7 +32,7 @@
</div>
<div class="text-center" ng-if="(availableItems | compareArrays:selectedItems:'alias').length === 0">
<small><localize key="general_all">Akk</localize> {{itemLabel}}s <localize key="grid_areAdded">are added</localize></small>
<small><localize key="general_all">All</localize> {{itemLabel}}s <localize key="grid_areAdded">are added</localize></small>
</div>
</div>
@@ -94,6 +94,11 @@ function contentCreateController($scope,
navigationService.hideDialog(showMenu);
};
$scope.editContentType = function() {
$location.path("/settings/documenttypes/edit/" + $scope.contentTypeId).search("view", "permissions");
close();
}
$scope.createBlank = createBlank;
$scope.createOrSelectBlueprintIfAny = createOrSelectBlueprintIfAny;
$scope.createFromBlueprint = createFromBlueprint;
@@ -10,7 +10,7 @@
<p class="abstract" ng-if="!hasSettingsAccess"><localize key="create_noDocumentTypesWithNoSettingsAccess"/></p>
<div ng-if="hasSettingsAccess">
<p class="abstract"><localize key="create_noDocumentTypes" /></p>
<button class="btn umb-outline" href="#settings/documentTypes/edit/{{contentTypeId}}?view=permissions" ng-click="close()">
<button class="btn umb-outline" ng-click="editContentType()">
<localize key="create_noDocumentTypesEditPermissions"/>
</button>
</div>
@@ -11,7 +11,7 @@
<ul class="umb-actions umb-actions-child">
<li class="umb-action" ng-repeat="documentType in vm.documentTypes | orderBy:'name':false">
<a href="" class="umb-action-link" ng-click="vm.createBlueprint(documentType)" prevent-default>
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.createBlueprint(documentType)" prevent-default>
<i class="large icon {{documentType.icon}}"></i>
<span class="menu-label">
{{documentType.name}}
@@ -19,7 +19,7 @@
{{documentType.description}}
</small>
</span>
</a>
</button>
</li>
</ul>
@@ -6,20 +6,20 @@
<ul class="umb-actions umb-actions-child">
<li data-element="action-data-type" class="umb-action">
<a href="" class="umb-action-link" ng-click="createDataType()" umb-auto-focus>
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="createDataType()" umb-auto-focus>
<i class="large icon icon-autofill"></i>
<span class="menu-label">
<localize key="create_newDataType">New data type</localize>
</span>
</a>
</button>
</li>
<li data-element="action-folder" class="umb-action">
<a href="" class="umb-action-link" ng-click="showCreateFolder()">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="showCreateFolder()">
<i class="large icon icon-folder"></i>
<span class="menu-label">
<localize key="create_newFolder">New folder</localize>...
</span>
</a>
</button>
</li>
</ul>
</div>
@@ -7,36 +7,36 @@
<ul class="umb-actions umb-actions-child">
<li data-element="action-documentType" class="umb-action" ng-hide="model.disableTemplates">
<a href="" ng-click="createDocType()" class="umb-action-link" umb-auto-focus>
<button href="" ng-click="createDocType()" class="umb-action-link umb-outline btn-reset" umb-auto-focus>
<i class="large icon icon-item-arrangement"></i>
<span class="menu-label">
<localize key="content_documentType">Document type</localize>
</span>
</a>
</button>
</li>
<li data-element="action-documentTypeWithoutTemplate" class="umb-action">
<a href="" ng-click="createComponent()" class="umb-action-link">
<button href="" ng-click="createComponent()" class="umb-action-link umb-outline btn-reset">
<i class="large icon icon-item-arrangement"></i>
<span class="menu-label">
<localize ng-if="model.disableTemplates === false" key="create_documentTypeWithoutTemplate"></localize>
<localize ng-if="model.disableTemplates === true" key="content_documentType">Document type></localize>
</span>
</a>
</button>
</li>
<li data-element="action-documentTypeCollection" class="umb-action">
<a href="" ng-click="showCreateDocTypeCollection()" class="umb-action-link">
<button href="" ng-click="showCreateDocTypeCollection()" class="umb-action-link umb-outline btn-reset">
<i class="large icon icon-thumbnail-list"></i>
<span class="menu-label">
Document Type Collection...
<!-- <localize key="content_documentType_collection">Document Type Collection</localize>-->
</span>
</a>
</button>
</li>
<li data-element="action-folder" ng-if="model.allowCreateFolder" class="umb-action">
<a href="" ng-click="showCreateFolder()" class="umb-action-link">
<button href="" ng-click="showCreateFolder()" class="umb-action-link umb-outline btn-reset">
<i class="large icon icon-folder"></i>
<span class="menu-label"><localize key="general_folder"></localize>...</span>
</a>
</button>
</li>
</ul>
</div>
@@ -10,11 +10,12 @@
vm.numberOfErrors = 0;
vm.commonLogMessages = [];
vm.commonLogMessagesCount = 10;
vm.dateRangeLabel = "";
// ChartJS Options - for count/overview of log distribution
vm.logTypeLabels = ["Info", "Debug", "Warning", "Error", "Critical"];
vm.logTypeLabels = ["Debug", "Info", "Warning", "Error", "Fatal"];
vm.logTypeData = [0, 0, 0, 0, 0];
vm.logTypeColors = [ '#dcdcdc', '#97bbcd', '#46bfbd', '#fdb45c', '#f7464a'];
vm.logTypeColors = ['#eaddd5', '#2bc37c', '#3544b1', '#ff9412', '#d42054'];
vm.chartOptions = {
legend: {
display: true,
@@ -23,35 +24,42 @@
};
let querystring = $location.search();
if(querystring.startDate){
if (querystring.startDate) {
vm.startDate = querystring.startDate;
}else{
vm.dateRangeLabel = getDateRangeLabel("Selected Time Period");
} else {
vm.startDate = new Date(Date.now());
vm.startDate.setDate(vm.startDate.getDate()-1);
vm.startDate.setDate(vm.startDate.getDate() - 1);
vm.startDate = vm.startDate.toIsoDateString();
vm.dateRangeLabel = getDateRangeLabel("Today");
}
if(querystring.endDate){
if (querystring.endDate) {
vm.endDate = querystring.endDate;
}else{
if (querystring.endDate === querystring.startDate) {
vm.dateRangeLabel = getDateRangeLabel("Selected Date");
}
} else {
vm.endDate = new Date(Date.now()).toIsoDateString();
}
vm.period = [vm.startDate, vm.endDate];
vm.period = [vm.startDate, vm.endDate];
//functions
vm.searchLogQuery = searchLogQuery;
vm.findMessageTemplate = findMessageTemplate;
vm.searchErrors = searchErrors;
function preFlightCheck(){
vm.loading = true;
//Do our pre-flight check (to see if we can view logs)
//IE the log file is NOT too big such as 1GB & crash the site
logViewerResource.canViewLogs(vm.startDate, vm.endDate).then(function(result){
logViewerResource.canViewLogs(vm.startDate, vm.endDate).then(function (result) {
vm.loading = false;
vm.canLoadLogs = result;
if(result){
if (result) {
//Can view logs - so initalise
init();
}
@@ -62,39 +70,39 @@
function init() {
vm.loading = true;
var savedSearches = logViewerResource.getSavedSearches().then(function (data) {
vm.searches = data;
},
// fallback to some defaults if error from API response
function () {
vm.searches = [
{
"name": "Find all logs where the Level is NOT Verbose and NOT Debug",
"query": "Not(@Level='Verbose') and Not(@Level='Debug')"
vm.searches = data;
},
// fallback to some defaults if error from API response
function () {
vm.searches = [
{
"name": "Find all logs where the Level is NOT Verbose and NOT Debug",
"query": "Not(@Level='Verbose') and Not(@Level='Debug')"
},
{
"name": "Find all logs that has an exception property (Warning, Error & Critical with Exceptions)",
"query": "Has(@Exception)"
{
"name": "Find all logs that has an exception property (Warning, Error & Fatal with Exceptions)",
"query": "Has(@Exception)"
},
{
"name": "Find all logs that have the property 'Duration'",
"query": "Has(Duration)"
{
"name": "Find all logs that have the property 'Duration'",
"query": "Has(Duration)"
},
{
"name": "Find all logs that have the property 'Duration' and the duration is greater than 1000ms",
"query": "Has(Duration) and Duration > 1000"
{
"name": "Find all logs that have the property 'Duration' and the duration is greater than 1000ms",
"query": "Has(Duration) and Duration > 1000"
},
{
"name": "Find all logs that are from the namespace 'Umbraco.Core'",
"query": "StartsWith(SourceContext, 'Umbraco.Core')"
{
"name": "Find all logs that are from the namespace 'Umbraco.Core'",
"query": "StartsWith(SourceContext, 'Umbraco.Core')"
},
{
"name": "Find all logs that use a specific log message template",
"query": "@MessageTemplate = '[Timing {TimingId}] {EndMessage} ({TimingDuration}ms)'"
{
"name": "Find all logs that use a specific log message template",
"query": "@MessageTemplate = '[Timing {TimingId}] {EndMessage} ({TimingDuration}ms)'"
}
]
});
});
var numOfErrors = logViewerResource.getNumberOfErrors(vm.startDate, vm.endDate).then(function (data) {
vm.numberOfErrors = data;
@@ -102,41 +110,56 @@
var logCounts = logViewerResource.getLogLevelCounts(vm.startDate, vm.endDate).then(function (data) {
vm.logTypeData = [];
vm.logTypeData.push(data.Information);
vm.logTypeData.push(data.Debug);
vm.logTypeData.push(data.Warning);
vm.logTypeData.push(data.Error);
vm.logTypeData.push(data.Fatal);
for (let [key, value] of Object.entries(data)) {
const index = vm.logTypeLabels.findIndex(x => key.startsWith(x));
if (index > -1) {
vm.logTypeData[index] = value;
}
}
});
var commonMsgs = logViewerResource.getMessageTemplates(vm.startDate, vm.endDate).then(function(data){
var commonMsgs = logViewerResource.getMessageTemplates(vm.startDate, vm.endDate).then(function (data) {
vm.commonLogMessages = data;
});
//Set loading indicatior to false when these 3 queries complete
$q.all([savedSearches, numOfErrors, logCounts, commonMsgs]).then(function(data) {
//Set loading indicator to false when these 3 queries complete
$q.all([savedSearches, numOfErrors, logCounts, commonMsgs]).then(function () {
vm.loading = false;
});
$timeout(function () {
navigationService.syncTree({ tree: "logViewer", path: "-1" });
navigationService.syncTree({
tree: "logViewer",
path: "-1"
});
});
}
function searchLogQuery(logQuery){
$location.path("/settings/logViewer/search").search({lq: logQuery, startDate: vm.startDate, endDate: vm.endDate});
function searchLogQuery(logQuery) {
$location.path("/settings/logViewer/search").search({
lq: logQuery,
startDate: vm.startDate,
endDate: vm.endDate
});
}
function findMessageTemplate(template){
function findMessageTemplate(template) {
var logQuery = "@MessageTemplate='" + template.MessageTemplate + "'";
searchLogQuery(logQuery);
}
function getDateRangeLabel(suffix) {
return "Log Overview for " + suffix;
}
function searchErrors(){
var logQuery = "@Level='Fatal' or @Level='Error' or Has(@Exception)";
searchLogQuery(logQuery);
}
preFlightCheck();
/////////////////////
vm.config = {
@@ -147,20 +170,21 @@
maxDate: "today",
conjunction: " to "
};
vm.dateRangeChange = function(selectedDates, dateStr, instance) {
if(selectedDates.length > 0){
vm.startDate = selectedDates[0].toIsoDateString();
vm.endDate = selectedDates[selectedDates.length-1].toIsoDateString(); // Take the last date as end
if(vm.startDate === vm.endDate){
vm.period = [vm.startDate];
}else{
vm.period = [vm.startDate, vm.endDate];
}
preFlightCheck();
vm.dateRangeChange = function (selectedDates, dateStr, instance) {
if (selectedDates.length > 0) {
// Update view by re-requesting route with updated querystring.
// By doing this we make sure the URL matches the selected time period, aiding sharing the link.
// Also resolves a minor layout issue where the " to " conjunction between the selected dates
// is collapsed to a comma.
const startDate = selectedDates[0].toIsoDateString();
const endDate = selectedDates[selectedDates.length - 1].toIsoDateString(); // Take the last date as end
$location.path("/settings/logViewer/overview").search({
startDate: startDate,
endDate: endDate
});
}
}
@@ -3,7 +3,7 @@
<umb-editor-view footer="false">
<umb-editor-header
name="'Log Overview for Today'"
name="vm.dateRangeLabel"
name-locked="true"
hide-icon="true"
hide-description="true"
@@ -74,17 +74,16 @@
<umb-box>
<umb-box-header title="Time Period"></umb-box-header>
<umb-flatpickr
class="datepicker"
ng-model="vm.period"
options="vm.config"
on-close="vm.dateRangeChange(selectedDates, dateStr, instance)">
<umb-flatpickr class="datepicker"
ng-model="vm.period"
options="vm.config"
on-close="vm.dateRangeChange(selectedDates, dateStr, instance)">
</umb-flatpickr>
</umb-box>
<div ng-show=" vm.canLoadLogs">
<!-- No of Errors -->
<umb-box ng-click="vm.searchLogQuery('Has(@Exception)')" style="cursor:pointer;">
<umb-box ng-click="vm.searchErrors()" style="cursor:pointer;">
<umb-box-header title="Number of Errors"></umb-box-header>
<umb-box-content class="block-form" style="font-size: 40px; font-weight:900; text-align:center; color:#fe6561;">
{{ vm.numberOfErrors }}
@@ -11,26 +11,28 @@
vm.showBackButton = true;
vm.page = {};
// this array is also used to map the logTypeColor param onto the log items
// in setLogTypeColors()
vm.logLevels = [
{
name: 'Verbose',
logTypeColor: 'gray'
logTypeColor: ''
},
{
name: 'Debug',
logTypeColor: 'secondary'
logTypeColor: 'gray'
},
{
name: 'Information',
logTypeColor: 'primary'
logTypeColor: 'success'
},
{
name: 'Warning',
logTypeColor: 'warning'
logTypeColor: 'primary'
},
{
name: 'Error',
logTypeColor: 'danger'
logTypeColor: 'warning'
},
{
name: 'Fatal',
@@ -118,7 +120,7 @@
"query": "Not(@Level='Verbose') and Not(@Level='Debug')"
},
{
"name": "Find all logs that has an exception property (Warning, Error & Critical with Exceptions)",
"name": "Find all logs that has an exception property (Warning, Error & Fatal with Exceptions)",
"query": "Has(@Exception)"
},
{
@@ -173,25 +175,8 @@
}
function setLogTypeColor(logItems) {
angular.forEach(logItems, function (log) {
switch (log.Level) {
case "Information":
log.logTypeColor = "primary";
break;
case "Debug":
log.logTypeColor = "secondary";
break;
case "Warning":
log.logTypeColor = "warning";
break;
case "Fatal":
case "Error":
log.logTypeColor = "danger";
break;
default:
log.logTypeColor = "gray";
}
});
logItems.forEach(logItem =>
logItem.logTypeColor = vm.logLevels.find(x => x.name === logItem.Level).logTypeColor);
}
function getFilterName(array) {
@@ -17,13 +17,13 @@
<ul class="umb-actions umb-actions-child">
<li data-element="action-{{docType.alias}}" class="umb-action" ng-repeat="docType in allowedTypes">
<a ng-href="" ng-click="createMediaItem(docType)" class="umb-action-link" prevent-default>
<button ng-click="createMediaItem(docType)" class="umb-action-link umb-outline btn-reset" prevent-default>
<i class="large icon {{docType.icon}}"></i>
<span class="menu-label">
{{docType.name}}
<small>{{docType.description}}</small>
</span>
</a>
</button>
</li>
<!--
<li class="add">
@@ -7,19 +7,19 @@
<ul class="umb-actions umb-actions-child">
<li class="umb-action">
<a href="" class="umb-action-link" ng-click="createMediaType()" umb-auto-focus>
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="createMediaType()" umb-auto-focus>
<i class="large icon icon-item-arrangement"></i>
<span class="menu-label">
<localize key="general_new">New</localize>
<localize key="content_mediatype">Media type</localize>
</span>
</a>
</button>
</li>
<li class="umb-action">
<a href="" class="umb-action-link" ng-click="showCreateFolder()">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="showCreateFolder()">
<i class="large icon icon-folder"></i>
<span class="menu-label"><localize key="general_folder"></localize>...</span>
</a>
</button>
</li>
</ul>
</div>
@@ -6,13 +6,13 @@
<ul class="umb-actions umb-actions-child">
<li class="umb-action" ng-repeat="docType in allowedTypes">
<a class="umb-action-link" href="#member/member/edit/{{currentNode.id}}?doctype={{docType.alias}}&create=true" ng-click="hideActions()">
<button class="umb-action-link umb-outline btn-reset" href="#member/member/edit/{{currentNode.id}}?doctype={{docType.alias}}&create=true" ng-click="hideActions()">
<i class="large icon {{docType.icon}}"></i>
<span class="menu-label">
{{docType.name}}
<small>{{docType.description}}</small>
</span>
</a>
</button>
</li>
</ul>
@@ -5,13 +5,13 @@
<ul class="umb-actions umb-actions-child">
<li class="umb-action">
<a href="" class="umb-action-link" ng-click="showCreateFolder()">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="showCreateFolder()">
<i class="large icon icon-folder"></i>
<span class="menu-label"><localize key="general_folder"></localize></span>
</a>
</button>
</li>
<li class="umb-action">
<a href="" class="umb-action-link" ng-click="createMemberType()">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="createMemberType()">
<i class="large icon icon-item-arrangement"></i>
@@ -20,7 +20,7 @@
<localize key="content_memberType">Member type</localize>
</span>
</a>
</button>
</li>
</ul>
</div>
@@ -11,28 +11,28 @@
<ul class="umb-actions umb-actions-child">
<li class="umb-action">
<a href="" class="umb-action-link" ng-click="vm.createFile()" umb-auto-focus>
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.createFile()" umb-auto-focus>
<i class="large icon-article"></i>
<span class="menu-label"><localize key="create_newPartialViewMacro">New partial view macro</localize></span>
</a>
</button>
</li>
<li class="umb-action">
<a href="" class="umb-action-link" ng-click="vm.createFileWithoutMacro()">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.createFileWithoutMacro()">
<i class="large icon icon-article"></i>
<span class="menu-label"><localize key="create_newPartialViewMacroNoMacro">New partial view macro (without macro)</localize></span>
</a>
</button>
</li>
<li class="umb-action">
<a href="" class="umb-action-link" ng-click="vm.showCreateFromSnippet()">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.showCreateFromSnippet()">
<i class="large icon icon-article"></i>
<span class="menu-label"><localize key="create_newPartialViewMacroFromSnippet">>New partial view macro from snippet</localize>...</span>
</a>
</button>
</li>
<li class="umb-action">
<a href="" class="umb-action-link" ng-click="vm.showCreateFolder()">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.showCreateFolder()">
<i class="large icon icon-folder"></i>
<span class="menu-label"><localize key="general_folder"></localize>...</span>
</a>
</button>
</li>
</ul>
</div>
@@ -44,10 +44,10 @@
<ul class="umb-actions umb-actions-child">
<li class="umb-action" ng-repeat="snippet in vm.snippets">
<a href="" class="umb-action-link" ng-click="vm.createFileFromSnippet(snippet)" style="padding-top: 6px; padding-bottom: 6px;">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.createFileFromSnippet(snippet)" style="padding-top: 6px; padding-bottom: 6px;">
<i class="icon-article icon" style="font-size: 20px;"></i>
<span class="menu-label" style="margin-left: 0; padding-left: 5px;">{{ snippet.name }}</span>
</a>
</button>
</li>
</ul>
</div>
@@ -10,22 +10,22 @@
<div ng-if="!vm.showSnippets">
<ul class="umb-actions umb-actions-child">
<li class="umb-action">
<a href="" class="umb-action-link" ng-click="vm.createPartialView()" umb-auto-focus>
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.createPartialView()" umb-auto-focus>
<i class="large icon icon-article"></i>
<span class="menu-label"><localize key="create_newEmptyPartialView">New empty partial view</localize></span>
</a>
</button>
</li>
<li class="umb-action">
<a href="" class="umb-action-link" ng-click="vm.showCreateFromSnippet()">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.showCreateFromSnippet()">
<i class="large icon icon-article"></i>
<span class="menu-label"><localize key="create_newPartialViewFromSnippet">New partial view from snippet</localize>...</span>
</a>
</button>
</li>
<li class="umb-action">
<a href="" class="umb-action-link" ng-click="vm.showCreateFolder()">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.showCreateFolder()">
<i class="large icon icon-folder"></i>
<span class="menu-label"><localize key="general_folder"></localize>...</span>
</a>
</button>
</li>
</ul>
</div>
@@ -34,10 +34,10 @@
<div ng-if="vm.showSnippets">
<ul class="umb-actions umb-actions-child">
<li class="umb-action" ng-repeat="snippet in vm.snippets">
<a href="" class="umb-action-link" ng-click="vm.createPartialView(snippet)" style="padding-top: 6px; padding-bottom: 6px;">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.createPartialView(snippet)" style="padding-top: 6px; padding-bottom: 6px;">
<i class="icon-article icon" style="font-size: 20px;"></i>
<span class="menu-label" style="margin-left: 0; padding-left: 5px;">{{ snippet.name }}</span>
</a>
</button>
</li>
</ul>
</div>
@@ -0,0 +1,90 @@
<div>
<umb-editor-view>
<umb-editor-header name="model.title"
name-locked="true"
hide-alias="true"
hide-icon="true"
hide-description="true">
</umb-editor-header>
<umb-editor-container class="block-form">
<umb-box>
<umb-box-content>
<div class="content-type-editor-dialog edit-property-settings">
<div class="umb-control-group" ng-if="!model.property.locked">
<div class="control-group">
<textarea class="editor-label"
data-element="property-name"
name="propertyLabel"
ng-model="model.property.label"
localize="placeholder"
placeholder="@placeholders_entername"
umb-auto-focus
focus-on-filled="true"
umb-auto-resize
required
ng-keypress="submitOnEnter($event)">
</textarea>
</div>
<div class="control-group -no-margin">
<umb-generate-alias enable-lock="true" alias-from="model.property.label" alias="model.property.alias"></umb-generate-alias>
</div>
</div>
<div class="editor-wrapper umb-control-group control-group" ng-model="model.property.editor" val-require-component ng-if="!model.property.locked">
<a data-element="editor-add" href="" ng-if="!model.property.editor" class="editor-placeholder" hotkey="alt+shift+e" ng-click="openDataTypePicker(model.property)">
<localize key="shortcuts_addEditor"></localize>
</a>
<div class="editor clearfix" ng-if="model.property.editor">
<a href="" class="editor-icon-wrapper" ng-click="openDataTypePicker(model.property)">
<i class="icon {{ model.property.dataTypeIcon }}" ng-class="{'icon-autofill': model.property.dataTypeIcon == null}"></i>
</a>
<div class="editor-details">
<a href="" class="editor-name" ng-click="openDataTypePicker(model.property)" ng-bind="model.property.dataTypeName"></a>
<a href="" class="editor-editor" ng-click="openDataTypePicker(model.property)" ng-bind="model.property.editor"></a>
</div>
<a href class="editor-settings-icon pull-right"
ng-click="vm.openDataTypeSettings(model.property)"
hotkey="alt+shift+d"
ng-if="model.property.editor">
<i class="icon icon-settings"></i>
</a>
</div>
</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-button type="button"
button-style="success"
label-key="general_submit"
state="saveButtonState"
action="submit(model)">
</umb-button>
</umb-editor-footer-content-right>
</umb-editor-footer>
</umb-editor-view>
</div>
@@ -0,0 +1,204 @@
(function () {
"use strict";
function BlockEditorController($scope, contentResource, editorService, iconHelper, clipboardService) {
var vm = this;
vm.scaffolds = [];
vm.loading = true;
let allowedElements = [];
// it would be awesome if we could load all scaffolds in one go... however we need to have an eye out for performance,
// oddly enough it's been shown to actually be slower to load them all at once instead of one at a time
var scaffoldsLoaded = 0;
function init() {
_.each($scope.model.config.blocks, function (config) {
contentResource.getScaffoldByUdi(-20, config.elementType).then(function (scaffold) {
if (scaffold.isElement) {
// the scaffold udi is not the same as the element type udi, but we need it to be for comparison
scaffold.udi = config.elementType;
vm.scaffolds.push(scaffold);
}
scaffoldsLoaded++;
initIfAllScaffoldsHaveLoaded();
}, function (error) {
scaffoldsLoaded++;
initIfAllScaffoldsHaveLoaded();
});
});
}
function initIfAllScaffoldsHaveLoaded() {
// Initialize when all scaffolds have loaded
if ($scope.model.config.blocks.length === scaffoldsLoaded) {
vm.scaffolds = _.sortBy(vm.scaffolds, function (scaffold) {
return _.findIndex($scope.model.config.blocks, function (blockConfig) {
return blockConfig.elementType === scaffold.udi;
});
});
_.each($scope.model.value, function (block) {
applyFakeSettings(block);
});
allowedElements = vm.scaffolds.map(x => x.contentTypeAlias);
vm.loading = false;
}
}
vm.openNodeTypePicker = function ($event) {
vm.overlayMenu = {
show: false,
style: {},
filter: vm.scaffolds.length > 12 ? true : false,
orderBy: "$index",
view: "itempicker",
event: $event,
clickPasteItem: function (item) {
vm.pasteFromClipboard(item.data);
vm.overlayMenu.show = false;
vm.overlayMenu = null;
},
submit: function (model) {
if (model && model.selectedItem) {
vm.add(vm.scaffolds.filter(x => x.contentTypeAlias === model.selectedItem.alias)[0]);
}
vm.overlayMenu.show = false;
vm.overlayMenu = null;
},
close: function () {
vm.overlayMenu.show = false;
vm.overlayMenu = null;
}
};
// this could be used for future limiting on node types
vm.overlayMenu.availableItems = [];
vm.scaffolds.forEach(function (scaffold) {
vm.overlayMenu.availableItems.push({
alias: scaffold.contentTypeAlias,
name: scaffold.contentTypeName,
icon: iconHelper.convertFromLegacyIcon(scaffold.icon),
description: scaffold.documentType.description
});
});
if (vm.overlayMenu.availableItems.length === 0) {
return;
}
//TODO: If we support larger thumbnails of some sort one day, this could be large
vm.overlayMenu.size = vm.overlayMenu.availableItems.length > 6 ? "medium" : "small";
vm.overlayMenu.pasteItems = [];
var availableNodesForPaste = clipboardService.retriveDataOfType("elementType", allowedElements);
availableNodesForPaste.forEach(function (node) {
vm.overlayMenu.pasteItems.push({
alias: node.contentTypeAlias,
name: node.name, //contentTypeName
data: node,
icon: iconHelper.convertFromLegacyIcon(node.icon)
});
});
vm.overlayMenu.clickClearPaste = function ($event) {
$event.stopPropagation();
$event.preventDefault();
clipboardService.clearEntriesOfType("elementType", allowedElements);
vm.overlayMenu.pasteItems = []; // This dialog is not connected via the clipboardService events, so we need to update manually.
};
if (vm.overlayMenu.availableItems.length === 1 && vm.overlayMenu.pasteItems.length === 0) {
// only one scaffold type - no need to display the picker
vm.add(vm.scaffolds[0]);
return;
}
vm.overlayMenu.show = true;
}
vm.add = function (scaffold) {
var element = angular.copy(scaffold);
var block = {
udi: element.udi,
icon: element.icon,
description: element.documentType.description, // probably don't want to persist these.
content: {},
settings: {
view: 'views/propertyeditors/blockeditor/blockeditor.block.html'
}
};
openContent(element, block);
}
vm.editSettings = function (block) {
var options = {
settings: block.settings,
title: "Edit settings",
view: "views/propertyeditors/blockeditor/blockeditor.editsettings.html",
size: "small",
submit: function (model) {
editorService.close();
},
close: function () {
editorService.close();
}
};
editorService.open(options);
}
vm.onRemove = function (block) {
$scope.model.value.splice($scope.model.value.indexOf(block), 1);
}
vm.onEdit = function (element, block) {
openContent(element, block);
}
function openContent(element, block) {
var options = {
element: element,
title: 'Edit block',
//fixme: This isn't really a component if its strongly tied to views in the property editor :/
view: "views/propertyeditors/blockeditor/blockeditor.editcontent.html",
submit: function (model) {
_.each(element.variants[0].tabs, function (tab) {
_.each(tab.properties, function (property) {
block.content[property.alias] = property.value;
});
});
if ($scope.model.value.indexOf(block) < 0) {
$scope.model.value.push(block);
applyFakeSettings(block);
}
editorService.close();
},
close: function () {
editorService.close();
}
};
editorService.open(options);
}
// TODO: remove this (only for testing)
// currently pushes random values for setting a css grid location
function applyFakeSettings(block) {
block.settings["col"] = 1 + Math.floor(Math.random() * 7);
block.settings["row"] = 1 + Math.floor(Math.random() * 7);
block.settings["w"] = 1 + Math.floor(Math.random() * 3);
block.settings["h"] = 1 + Math.floor(Math.random() * 3);
}
init();
}
angular.module("umbraco").controller("Umbraco.PropertyEditors.BlockEditorController", BlockEditorController);
})();
@@ -0,0 +1,34 @@
/**
* @ngdoc controller
* @name Umbraco.PropertyEditors.BlockEditor.EditContentController
* @function
*
* @description
* The controller for editing content with the block editor
*/
function BlockEditorEditContentController($scope) {
var vm = this;
vm.submit = submit;
vm.close = close;
vm.content = $scope.model.element.variants[0];
function init() {
}
function submit() {
if($scope.model.submit) {
$scope.model.submit($scope.model);
}
}
function close() {
if($scope.model.close) {
$scope.model.close();
}
}
init();
}
angular.module("umbraco").controller("Umbraco.PropertyEditors.BlockEditor.EditContentController", BlockEditorEditContentController);
@@ -0,0 +1,38 @@
<div ng-controller="Umbraco.PropertyEditors.BlockEditor.EditContentController as vm">
<umb-editor-view>
<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-load-indicator ng-if="vm.loading" />
<div ng-if="!loading">
<ng-form name="editBlockForm" val-form-manager>
<umb-tabbed-content content="vm.content" />
</ng-form>
</div>
</umb-editor-container>
<umb-editor-footer>
<umb-editor-footer-content-right>
<umb-button type="button"
button-style="link"
label-key="general_cancel"
shortcut="esc"
action="vm.close()">
</umb-button>
<umb-button type="button"
button-style="success"
label-key="general_ok"
action="vm.submit()">
</umb-button>
</umb-editor-footer-content-right>
</umb-editor-footer>
</umb-editor-view>
</div>
@@ -0,0 +1,26 @@
/**
* @ngdoc controller
* @name Umbraco.PropertyEditors.BlockEditor.EditSettingsController
* @function
*
* @description
* The controller for editing the configuration of an individual block
*/
//fixme: Need to figure out the name of a block settings, is it block config or block settings?
function BlockEditorEditSettingsController($scope) {
this.submit = () => {
if($scope.model.submit) {
$scope.model.submit($scope.model);
}
}
this.close = () => {
if($scope.model.close) {
$scope.model.close();
}
}
}
angular.module("umbraco")
.controller("Umbraco.PropertyEditors.BlockEditor.EditSettingsController", ['$scope', BlockEditorEditSettingsController]);
@@ -0,0 +1,44 @@
<div ng-controller="Umbraco.PropertyEditors.BlockEditor.EditSettingsController as vm">
<umb-editor-view>
<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-load-indicator ng-if="vm.loading" />
<div ng-if="!loading">
<umb-box>
<umb-box-content>
<ng-form name="editBlockForm" class="form-horizontal" val-form-manager>
<umb-control-group label="{{key}}" description="" ng-repeat="(key, value) in model.settings">
<input type="text" ng-model="model.settings[key]" ng-model-options="{ debounce: 5000 }"/>
</umb-control-group>
</ng-form>
</umb-box-content>
</umb-box>
</div>
</umb-editor-container>
<umb-editor-footer>
<umb-editor-footer-content-right>
<umb-button type="button"
button-style="link"
label-key="general_cancel"
shortcut="esc"
action="vm.close()">
</umb-button>
<umb-button type="button"
button-style="success"
label-key="general_ok"
action="vm.submit()">
</umb-button>
</umb-editor-footer-content-right>
</umb-editor-footer>
</umb-editor-view>
</div>
@@ -0,0 +1,31 @@
<div ng-controller="Umbraco.PropertyEditors.BlockEditorController as vm">
<div style="position:relative" ng-if="vm.loading">
<umb-load-indicator />
</div>
<div ng-if="!vm.loading">
<umb-block-list blocks="model.value"
config="model.config.blocks"
scaffolds="vm.scaffolds"
on-edit="vm.onEdit(element, block)"
on-remove="vm.onRemove(element, block)"
on-settings="vm.editSettings(block)">
</umb-block-list>
</div>
<div ng-if="!vm.loading" class="umb-nested-content__footer-bar">
<a href class="umb-nested-content__add-content" ng-class="{ '--disabled': !vm.scaffolds.length }" ng-click="vm.openNodeTypePicker($event)" prevent-default>
<localize key="grid_addElement" ng-if="vm.scaffolds.length > 1"></localize>
<span ng-if="vm.scaffolds.length === 1">
<localize key="general_add"></localize> {{ vm.scaffolds[0].contentTypeName }}
</span>
</a>
</div>
<umb-overlay ng-if="vm.overlayMenu.show"
position="target"
size="vm.overlayMenu.size"
view="vm.overlayMenu.view"
model="vm.overlayMenu">
</umb-overlay>
</div>
@@ -0,0 +1,96 @@
/**
* @ngdoc controller
* @name Umbraco.PropertyEditors.BlockEditor.SettingsController
* @function
*
* @description
* The controller for the block editor's data type configuration
*/
//fixme: Rename this! it shouldn't be called Settings, it should be called Configuration because that is what we call pre-values in v8 (data type config)
angular.module("umbraco")
.controller("Umbraco.PropertyEditors.BlockEditor.SettingsController", [
"$scope",
"contentTypeResource",
"editorService",
function ($scope, contentTypeResource, editorService) {
$scope.blocks = [];
$scope.elementTypes = [];
if ($scope.model.value) {
$scope.blocks = $scope.model.value;
} else {
$scope.model.value = [];
}
contentTypeResource.getAll()
.then(function (contentType) {
$scope.elementTypes.push(contentType);
});
$scope.$on("formSubmitting", function () {
$scope.model.value = $scope.blocks;
});
//fixme: This shouldn't be a method, using methods to return values in angular is a performance issue
$scope.getBlockName = function(udi) {
return 'TODO: Get block name from somewhere...';
}
$scope.addBlock = function () {
var block = {};
var pickerOptions = {
title: "Pick an element type",
view: "views/common/infiniteeditors/treepicker/treepicker.html",
size: "small",
multiPicker: false,
section: "settings",
treeAlias: "documentTypes",
entityType: "documentType",
submit: function (model) {
_.each(model.selection, function (elementType) {
block.elementType = elementType.udi;
block.settings = {
view: 'views/propertyeditors/blockeditor/blockeditor.block.html'
}
$scope.model.value.push(block);
});
editorService.close();
},
close: function () {
editorService.close();
}
};
editorService.open(pickerOptions);
}
$scope.removeBlock = function (index) {
$scope.model.value.splice(index, 1);
};
//fixme: This currently doesn't work or do anything
$scope.editSettings = function (block) {
var pickerOptions = {
title: "Block settings",
//fixme: This file needs to be renamed since it's inconsistent with other blockeditor file names, probably blockeditor.blocksettings.html
view: "views/propertyeditors/blockeditor/block.settings.html",
size: "small",
submit: function (model) {
block.settings = model;
editorService.close();
},
close: function () {
editorService.close();
}
};
editorService.open(pickerOptions);
}
}
]);
@@ -0,0 +1,20 @@
<div ng-controller="Umbraco.PropertyEditors.BlockEditor.SettingsController">
<umb-node-preview ng-repeat="block in blocks"
name="getBlockName(block)"
alias="block.elementType"
icon="icon-folder"
allow-edit="true"
on-edit="editSettings(block)"
allow-remove="true"
on-remove="removeBlock($index)">
</umb-node-preview>
<a href="" class="umb-node-preview-add" ng-click="addBlock()">
<localize key="general_add">Add</localize>
</a>
<hr />
<pre>{{model.value | json}}</pre>
</div>
@@ -0,0 +1,9 @@
function BlockEditorSimpleListController($scope) {
$scope.sortableOptions = {
axis: "y",
cursor: "move",
handle: ".handle",
tolerance: 'pointer'
};
}
angular.module("umbraco").controller("Umbraco.PropertyEditors.BlockEditor.SimpleListController", ['$scope', BlockEditorSimpleListController]);
@@ -307,22 +307,22 @@ angular.module("umbraco")
$scope.openEditorOverlay = function (event, area, index, key) {
var title = "";
localizationService.localize("grid_insertControl").then(function (value) {
title = value;
$scope.editorOverlay = {
view: "itempicker",
filter: area.$allowedEditors.length > 15,
title: title,
availableItems: area.$allowedEditors,
event: event,
show: true,
submit: function (model) {
if (model.selectedItem) {
$scope.addControl(model.selectedItem, area, index);
$scope.editorOverlay.show = false;
$scope.editorOverlay = null;
title = value;
$scope.editorOverlay = {
view: "itempicker",
filter: area.$allowedEditors.length > 15,
title: title,
availableItems: area.$allowedEditors,
event: event,
show: true,
submit: function (model) {
if (model.selectedItem) {
$scope.addControl(model.selectedItem, area, index);
$scope.editorOverlay.show = false;
$scope.editorOverlay = null;
}
}
}
};
};
});
};
@@ -18,7 +18,7 @@
$scope.remove = function (index) {
$scope.model.value.splice(index, 1);
}
$scope.sortableOptions = {
axis: "y",
cursor: "move",
@@ -184,7 +184,8 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
$scope.overlayMenu.availableItems.push({
alias: scaffold.contentTypeAlias,
name: scaffold.contentTypeName,
icon: iconHelper.convertFromLegacyIcon(scaffold.icon)
icon: iconHelper.convertFromLegacyIcon(scaffold.icon),
description: scaffold.documentType.description
});
});
@@ -192,7 +193,7 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.NestedContent.Prop
return;
}
$scope.overlayMenu.size = $scope.overlayMenu.availableItems.length > 6 ? "medium" : "small";
$scope.overlayMenu.size = $scope.overlayMenu.availableItems.length > 6 ? "medium" : "small";
$scope.overlayMenu.pasteItems = [];
var availableNodesForPaste = clipboardService.retriveDataOfType("elementType", contentTypeAliases);
@@ -40,7 +40,8 @@
<div class="umb-nested-content__footer-bar" ng-hide="hasContentTypes === false || nodes.length >= maxItems">
<a href class="umb-nested-content__add-content" ng-class="{ '--disabled': !scaffolds.length }" ng-click="openNodeTypePicker($event)" prevent-default>
<localize key="grid_addElement"></localize>
<localize key="grid_addElement" ng-if="scaffolds.length > 1"></localize>
<span ng-if="scaffolds.length === 1"><localize key="general_add"></localize> {{ scaffolds[0].contentTypeName }}</span>
</a>
</div>
@@ -7,16 +7,16 @@
<ul class="umb-actions umb-actions-child">
<li class="umb-action">
<a href="" class="umb-action-link" umb-auto-focus ng-click="vm.createFile()">
<button href="" class="umb-action-link umb-outline btn-reset" umb-auto-focus ng-click="vm.createFile()">
<i class="large icon icon-script"></i>
<span class="menu-label"><localize key="create_newJavascriptFile">New javascript file</localize></span>
</a>
</button>
</li>
<li class="umb-action">
<a href="" class="umb-action-link" ng-click="vm.showCreateFolder()">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.showCreateFolder()">
<i class="large icon icon-folder"></i>
<span class="menu-label"><localize key="general_folder"></localize>...</span>
</a>
</button>
</li>
</ul>
@@ -7,22 +7,22 @@
<ul class="umb-actions umb-actions-child">
<li class="umb-action">
<a href="" class="umb-action-link" umb-auto-focus ng-click="vm.createFile()">
<button href="" class="umb-action-link umb-outline btn-reset" umb-auto-focus ng-click="vm.createFile()">
<i class="large icon icon-script"></i>
<span class="menu-label"><localize key="create_newStyleSheetFile">New style sheet file</localize></span>
</a>
</button>
</li>
<li class="umb-action">
<a href="" ng-click="vm.createRichtextStyle()" class="umb-action-link">
<button href="" ng-click="vm.createRichtextStyle()" class="umb-action-link umb-outline btn-reset">
<i class="large icon icon-script"></i>
<span class="menu-label"><localize key="create_newRteStyleSheetFile">New richtext style sheet file</localize></span>
</a>
</button>
</li>
<li class="umb-action">
<a href="" class="umb-action-link" ng-click="vm.showCreateFolder()">
<button href="" class="umb-action-link umb-outline btn-reset" ng-click="vm.showCreateFolder()">
<i class="large icon icon-folder"></i>
<span class="menu-label"><localize key="general_folder"></localize>...</span>
</a>
</button>
</li>
</ul>
@@ -90,6 +90,7 @@
ng-repeat="node in model.user.startContentIds"
icon="node.icon"
name="node.name"
allow-remove="true"
on-remove="model.removeSelectedItem($index, model.user.startContentIds)">
</umb-node-preview>
@@ -114,6 +115,7 @@
ng-repeat="node in model.user.startMediaIds"
icon="node.icon"
name="node.name"
allow-remove="true"
on-remove="model.removeSelectedItem($index, model.user.startMediaIds)">
</umb-node-preview>
+2 -2
View File
@@ -345,9 +345,9 @@
<WebProjectProperties>
<UseIIS>False</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>8110</DevelopmentServerPort>
<DevelopmentServerPort>8200</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:8110</IISUrl>
<IISUrl>http://localhost:8200</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
@@ -4,7 +4,7 @@
"query": "Not(@Level='Verbose') and Not(@Level='Debug')"
},
{
"name": "Find all logs that has an exception property (Warning, Error & Critical with Exceptions)",
"name": "Find all logs that has an exception property (Warning, Error & Fatal with Exceptions)",
"query": "Has(@Exception)"
},
{
@@ -26,12 +26,13 @@
<add key="serilog:write-to:File.restrictedToMinimumLevel" value="Debug" />
<add key="serilog:write-to:File.retainedFileCountLimit" value="32" />--> <!-- Number of log files to keep (or remove value to keep all files) -->
<!--<add key="serilog:write-to:File.rollingInterval" value="Day" />--> <!-- Create a new log file every Minute/Hour/Day/Month/Year/infinite -->
<!--<add key="serilog:write-to:File.outputTemplate" value="{Timestamp:yyyy-MM-dd HH:mm:ss,fff} [P{ProcessId}/D{AppDomainId}/T{ThreadId}] {Log4NetLevel} {SourceContext} - {Message:lj}{NewLine}{Exception}" /> -->
<!-- Filters all above sink's to use this expression -->
<!-- Common use case is to include SourceType starting with your own namespace -->
<!--
<add key="serilog:using:FilterExpressions" value="Serilog.Filters.Expressions" />
<add key="serilog:filter:ByIncluding.expression" value="StartsWith(SourceContext, 'Umbraco.Core')" />
<add key="serilog:filter:ByIncludingOnly.expression" value="StartsWith(SourceContext, 'Umbraco.Core')" />
-->
</appSettings>
@@ -60,7 +60,7 @@
<security>
<!-- set to true to auto update login interval (and there by disabling the lock screen -->
<keepUserLoggedIn>false</keepUserLoggedIn>
<keepUserLoggedIn>true</keepUserLoggedIn>
<!-- by default this is true and if not specified in config will be true. set to false to always show a separate username field in the back office user editor -->
<usernameIsEmail>true</usernameIsEmail>
<!-- change in 4.8: Disabled users are now showed dimmed and last in the tree. If you prefer not to display them set this to true -->
+23 -1
View File
@@ -354,12 +354,34 @@ namespace Umbraco.Web.Editors
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return EmptyContent(parentId, contentType);
}
/// <summary>
/// Gets an empty content item for the
/// </summary>
/// <param name="udi"></param>
/// <param name="parentId"></param>
[OutgoingEditorModelEvent]
public ContentItemDisplay GetEmpty(GuidUdi udi, int parentId)
{
var contentType = Services.ContentTypeService.Get(udi.Guid);
if(contentType == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return EmptyContent(parentId, contentType);
}
private ContentItemDisplay EmptyContent(int parentId, IContentType contentType)
{
var emptyContent = Services.ContentService.Create("", parentId, contentType.Alias, Security.GetUserId().ResultOr(0));
var mapped = MapToDisplay(emptyContent);
// translate the content type name if applicable
mapped.ContentTypeName = Services.TextService.UmbracoDictionaryTranslate(mapped.ContentTypeName);
// if your user type doesn't have access to the Settings section it would not get this property mapped
if (mapped.DocumentType != null)
if(mapped.DocumentType != null)
mapped.DocumentType.Name = Services.TextService.UmbracoDictionaryTranslate(mapped.DocumentType.Name);
//remove the listview app if it exists
+11 -1
View File
@@ -74,6 +74,7 @@ namespace Umbraco.Web.Editors
//id is passed in eventually we'll probably want to support GUID + Udi too
new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetPagedChildren", "id", typeof(int), typeof(string)),
new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetPath", "id", typeof(int), typeof(Guid), typeof(Udi)),
new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetUrlAndAnchors", "id", typeof(int), typeof(Guid), typeof(Udi)),
new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetById", "id", typeof(int), typeof(Guid), typeof(Udi)),
new ParameterSwapControllerActionSelector.ParameterSwapInfo("GetByIds", "ids", typeof(int[]), typeof(Guid[]), typeof(Udi[]))));
}
@@ -288,7 +289,16 @@ namespace Umbraco.Web.Editors
}
[HttpGet]
public UrlAndAnchors GetUrlAndAnchors([FromUri]int id, [FromUri]string culture = "*")
public UrlAndAnchors GetUrlAndAnchors(Udi id, string culture = "*")
{
var intId = Services.EntityService.GetId(id);
if (!intId.Success)
throw new HttpResponseException(HttpStatusCode.NotFound);
return GetUrlAndAnchors(intId.Result, culture);
}
[HttpGet]
public UrlAndAnchors GetUrlAndAnchors(int id, string culture = "*")
{
var url = UmbracoContext.UrlProvider.GetUrl(id);
var anchorValues = Services.ContentService.GetAnchorValuesFromRTEs(id, culture);
@@ -85,7 +85,7 @@ namespace Umbraco.Web.Editors
};
}
/// <summary>
/// Check if the index has been rebuilt
@@ -250,7 +250,7 @@ namespace Umbraco.Web.Editors
private void Indexer_IndexOperationComplete(object sender, EventArgs e)
{
var indexer = (LuceneIndex)sender;
var indexer = (IIndex)sender;
_logger.Debug<ExamineManagementController>("Logging operation completed for index {IndexName}", indexer.Name);
@@ -259,7 +259,7 @@ namespace Umbraco.Web.Editors
_logger
.Info<ExamineManagementController
>($"Rebuilding index '{indexer.Name}' done, {indexer.CommitCount} items committed (can differ from the number of items in the index)");
>($"Rebuilding index '{indexer.Name}' done.");
var cacheKey = "temp_indexing_op_" + indexer.Name;
_runtimeCache.Clear(cacheKey);
@@ -15,11 +15,11 @@ namespace Umbraco.Web.Editors
[PluginController("UmbracoApi")]
public class LogViewerController : UmbracoAuthorizedJsonController
{
private ILogViewer _logViewer;
private readonly ILogViewer _logViewer;
public LogViewerController(ILogViewer logViewer)
{
_logViewer = logViewer;
_logViewer = logViewer ?? throw new ArgumentNullException(nameof(logViewer));
}
private bool CanViewLogs(LogTimePeriod logTimePeriod)
@@ -91,8 +91,6 @@ namespace Umbraco.Web.Editors
var direction = orderDirection == "Descending" ? Direction.Descending : Direction.Ascending;
return _logViewer.GetLogs(logTimePeriod, filterExpression: filterExpression, pageNumber: pageNumber, orderDirection: direction, logLevels: logLevels);
}
@@ -223,7 +223,6 @@ namespace Umbraco.Web
_method = method;
_controllerName = controllerName;
_encryptedString = UrlHelperRenderExtensions.CreateEncryptedRouteString(controllerName, controllerAction, area, additionalRouteVals);
}
+12 -4
View File
@@ -39,10 +39,14 @@ namespace Umbraco.Web
/// <param name="culture">Optional culture.</param>
/// <param name="indexName">Optional index name.</param>
/// <remarks>
/// <para>When the <paramref name="culture"/> is not specified, all cultures are searched.</para>
/// <para>
/// When the <paramref name="culture"/> is not specified or is *, all cultures are searched.
/// To search for only invariant documents and fields use null.
/// When searching on a specific culture, all culture specific fields are searched for the provided culture and all invariant fields for all documents.
/// </para>
/// <para>While enumerating results, the ambient culture is changed to be the searched culture.</para>
/// </remarks>
IEnumerable<PublishedSearchResult> Search(string term, string culture = null, string indexName = null);
IEnumerable<PublishedSearchResult> Search(string term, string culture = "*", string indexName = null);
/// <summary>
/// Searches content.
@@ -54,10 +58,14 @@ namespace Umbraco.Web
/// <param name="culture">Optional culture.</param>
/// <param name="indexName">Optional index name.</param>
/// <remarks>
/// <para>When the <paramref name="culture"/> is not specified, all cultures are searched.</para>
/// <para>
/// When the <paramref name="culture"/> is not specified or is *, all cultures are searched.
/// To search for only invariant documents and fields use null.
/// When searching on a specific culture, all culture specific fields are searched for the provided culture and all invariant fields for all documents.
/// </para>
/// <para>While enumerating results, the ambient culture is changed to be the searched culture.</para>
/// </remarks>
IEnumerable<PublishedSearchResult> Search(string term, int skip, int take, out long totalRecords, string culture = null, string indexName = null);
IEnumerable<PublishedSearchResult> Search(string term, int skip, int take, out long totalRecords, string culture = "*", string indexName = null);
/// <summary>
/// Executes the query and converts the results to PublishedSearchResult.
@@ -301,7 +301,7 @@ namespace Umbraco.Web.Models.Mapping
target.Avatars = source.GetUserAvatarUrls(_appCaches.RuntimeCache);
target.Culture = source.GetUserCulture(_textService, _globalSettings).ToString();
target.Email = source.Email;
target.EmailHash = source.Email.ToLowerInvariant().Trim().ToMd5();
target.EmailHash = source.Email.ToLowerInvariant().Trim().GenerateHash();
target.Id = source.Id;
target.Key = source.Key;
target.LastLoginDate = source.LastLoginDate == default ? null : (DateTime?) source.LastLoginDate;
+1 -11
View File
@@ -12,7 +12,7 @@ namespace Umbraco.Web.Properties {
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.7.0.0")]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.2.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
@@ -50,15 +50,5 @@ namespace Umbraco.Web.Properties {
return ((string)(this["test"]));
}
}
[global::System.Configuration.ApplicationScopedSettingAttribute()]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Configuration.SpecialSettingAttribute(global::System.Configuration.SpecialSetting.WebServiceUrl)]
[global::System.Configuration.DefaultSettingValueAttribute("https://our.umbraco.com/umbraco/webservices/api/repository.asmx")]
public string umbraco_org_umbraco_our_Repository {
get {
return ((string)(this["umbraco_org_umbraco_our_Repository"]));
}
}
}
}
@@ -11,8 +11,5 @@
<Setting Name="test" Type="System.String" Scope="Application">
<Value Profile="(Default)">Something</Value>
</Setting>
<Setting Name="umbraco_org_umbraco_our_Repository" Type="(Web Service URL)" Scope="Application">
<Value Profile="(Default)">https://our.umbraco.com/umbraco/webservices/api/repository.asmx</Value>
</Setting>
</Settings>
</SettingsFile>
@@ -0,0 +1,36 @@
using Newtonsoft.Json;
using Umbraco.Core;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PropertyEditors
{
public class BlockEditorConfiguration
{
[ConfigurationField("blocks", "Blocks", "views/propertyeditors/blockeditor/blockeditor.settings.html")]
public Block[] Blocks { get; set; }
[ConfigurationField("view", "View", "textstring", Description = "The path to a custom view for rendering the editor")]
public string View { get; set; }
public class Block
{
[JsonProperty("elementType")]
public Udi ElementType { get; set; }
[JsonProperty("settings")]
public BlockSetting Settings { get; set; }
}
public class BlockSetting
{
[JsonProperty("label")]
public string Label { get; set; }
[JsonProperty("alias")]
public string Alias { get; set; }
[JsonProperty("dataType")]
public Udi DataType { get; set; }
}
}
}
@@ -0,0 +1,9 @@
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PropertyEditors
{
public class BlockEditorConfigurationEditor : ConfigurationEditor<BlockEditorConfiguration>
{
}
}
@@ -0,0 +1,18 @@
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PropertyEditors
{
[DataEditor(Constants.PropertyEditors.Aliases.BlockEditor, EditorType.PropertyValue , "Block Editor", "blockeditor", ValueType = ValueTypes.Json, Group="rich content", Icon="icon-application-window-alt")]
public class BlockEditorPropertyEditor : DataEditor
{
public BlockEditorPropertyEditor(ILogger logger)
: base(logger)
{ }
protected override IConfigurationEditor CreateConfigurationEditor() => new BlockEditorConfigurationEditor();
protected override IDataValueEditor CreateValueEditor() => base.CreateValueEditor();
}
}
@@ -8,7 +8,12 @@ namespace Umbraco.Web.PropertyEditors
/// <summary>
/// A property editor to allow multiple checkbox selection of pre-defined items.
/// </summary>
[DataEditor(Constants.PropertyEditors.Aliases.CheckBoxList, "Checkbox list", "checkboxlist", Icon="icon-bulleted-list", Group="lists")]
[DataEditor(
Constants.PropertyEditors.Aliases.CheckBoxList,
"Checkbox list",
"checkboxlist",
Icon = "icon-bulleted-list",
Group = Constants.PropertyEditors.Groups.Lists)]
public class CheckBoxListPropertyEditor : DataEditor
{
private readonly ILocalizedTextService _textService;
@@ -4,7 +4,12 @@ using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PropertyEditors
{
[DataEditor(Constants.PropertyEditors.Aliases.ColorPicker, "Color Picker", "colorpicker", Icon="icon-colorpicker", Group="Pickers")]
[DataEditor(
Constants.PropertyEditors.Aliases.ColorPicker,
"Color Picker",
"colorpicker",
Icon = "icon-colorpicker",
Group = Constants.PropertyEditors.Groups.Pickers)]
public class ColorPickerPropertyEditor : DataEditor
{
public ColorPickerPropertyEditor(ILogger logger)
@@ -8,7 +8,13 @@ namespace Umbraco.Web.PropertyEditors
/// <summary>
/// Content property editor that stores UDI
/// </summary>
[DataEditor(Constants.PropertyEditors.Aliases.ContentPicker, EditorType.PropertyValue | EditorType.MacroParameter, "Content Picker", "contentpicker", ValueType = ValueTypes.String, Group = "Pickers")]
[DataEditor(
Constants.PropertyEditors.Aliases.ContentPicker,
EditorType.PropertyValue | EditorType.MacroParameter,
"Content Picker",
"contentpicker",
ValueType = ValueTypes.String,
Group = Constants.PropertyEditors.Groups.Pickers)]
public class ContentPickerPropertyEditor : DataEditor
{
public ContentPickerPropertyEditor(ILogger logger)
@@ -7,7 +7,12 @@ namespace Umbraco.Web.PropertyEditors
/// <summary>
/// Represents a date and time property editor.
/// </summary>
[DataEditor(Constants.PropertyEditors.Aliases.DateTime, "Date/Time", "datepicker", ValueType = ValueTypes.DateTime, Icon="icon-time")]
[DataEditor(
Constants.PropertyEditors.Aliases.DateTime,
"Date/Time",
"datepicker",
ValueType = ValueTypes.DateTime,
Icon = "icon-time")]
public class DateTimePropertyEditor : DataEditor
{
/// <summary>
@@ -8,7 +8,12 @@ namespace Umbraco.Web.PropertyEditors
/// <summary>
/// Represents a decimal property and parameter editor.
/// </summary>
[DataEditor(Constants.PropertyEditors.Aliases.Decimal, EditorType.PropertyValue | EditorType.MacroParameter, "Decimal", "decimal", ValueType = ValueTypes.Decimal)]
[DataEditor(
Constants.PropertyEditors.Aliases.Decimal,
EditorType.PropertyValue | EditorType.MacroParameter,
"Decimal",
"decimal",
ValueType = ValueTypes.Decimal)]
public class DecimalPropertyEditor : DataEditor
{
/// <summary>
@@ -5,7 +5,12 @@ using Umbraco.Core.Services;
namespace Umbraco.Web.PropertyEditors
{
[DataEditor(Constants.PropertyEditors.Aliases.DropDownListFlexible, "Dropdown", "dropdownFlexible", Group = "lists", Icon = "icon-indent")]
[DataEditor(
Constants.PropertyEditors.Aliases.DropDownListFlexible,
"Dropdown",
"dropdownFlexible",
Group = Constants.PropertyEditors.Groups.Lists,
Icon = "icon-indent")]
public class DropDownFlexiblePropertyEditor : DataEditor
{
private readonly ILocalizedTextService _textService;
@@ -5,7 +5,12 @@ using Umbraco.Core.PropertyEditors.Validators;
namespace Umbraco.Web.PropertyEditors
{
[DataEditor(Constants.PropertyEditors.Aliases.EmailAddress, EditorType.PropertyValue | EditorType.MacroParameter, "Email address", "email", Icon="icon-message")]
[DataEditor(
Constants.PropertyEditors.Aliases.EmailAddress,
EditorType.PropertyValue | EditorType.MacroParameter,
"Email address",
"email",
Icon = "icon-message")]
public class EmailAddressPropertyEditor : DataEditor
{
/// <summary>
@@ -12,7 +12,12 @@ using Umbraco.Web.Media;
namespace Umbraco.Web.PropertyEditors
{
[DataEditor(Constants.PropertyEditors.Aliases.UploadField, "File upload", "fileupload", Icon = "icon-download-alt", Group = "media")]
[DataEditor(
Constants.PropertyEditors.Aliases.UploadField,
"File upload",
"fileupload",
Group = Constants.PropertyEditors.Groups.Media,
Icon = "icon-download-alt")]
public class FileUploadPropertyEditor : DataEditor
{
private readonly IMediaFileSystem _mediaFileSystem;
@@ -12,7 +12,14 @@ namespace Umbraco.Web.PropertyEditors
/// <summary>
/// Represents a grid property and parameter editor.
/// </summary>
[DataEditor(Constants.PropertyEditors.Aliases.Grid, "Grid layout", "grid", HideLabel = true, ValueType = ValueTypes.Json, Group="rich content", Icon="icon-layout")]
[DataEditor(
Constants.PropertyEditors.Aliases.Grid,
"Grid layout",
"grid",
HideLabel = true,
ValueType = ValueTypes.Json,
Icon = "icon-layout",
Group = Constants.PropertyEditors.Groups.RichContent)]
public class GridPropertyEditor : DataEditor
{
public GridPropertyEditor(ILogger logger)
@@ -19,7 +19,14 @@ namespace Umbraco.Web.PropertyEditors
/// <summary>
/// Represents an image cropper property editor.
/// </summary>
[DataEditor(Constants.PropertyEditors.Aliases.ImageCropper, "Image Cropper", "imagecropper", ValueType = ValueTypes.Json, HideLabel = false, Group="media", Icon="icon-crop")]
[DataEditor(
Constants.PropertyEditors.Aliases.ImageCropper,
"Image Cropper",
"imagecropper",
ValueType = ValueTypes.Json,
HideLabel = false,
Group = Constants.PropertyEditors.Groups.Media,
Icon = "icon-crop")]
public class ImageCropperPropertyEditor : DataEditor
{
private readonly IMediaFileSystem _mediaFileSystem;
@@ -8,7 +8,12 @@ namespace Umbraco.Web.PropertyEditors
/// <summary>
/// Represents an integer property and parameter editor.
/// </summary>
[DataEditor(Constants.PropertyEditors.Aliases.Integer, EditorType.PropertyValue | EditorType.MacroParameter, "Numeric", "integer", ValueType = ValueTypes.Integer)]
[DataEditor(
Constants.PropertyEditors.Aliases.Integer,
EditorType.PropertyValue | EditorType.MacroParameter,
"Numeric",
"integer",
ValueType = ValueTypes.Integer)]
public class IntegerPropertyEditor : DataEditor
{
public IntegerPropertyEditor(ILogger logger)
@@ -8,7 +8,13 @@ namespace Umbraco.Web.PropertyEditors
/// <summary>
/// Represents a list-view editor.
/// </summary>
[DataEditor(Constants.PropertyEditors.Aliases.ListView, "List view", "listview", HideLabel = true, Group = "lists", Icon = Constants.Icons.ListView)]
[DataEditor(
Constants.PropertyEditors.Aliases.ListView,
"List view",
"listview",
HideLabel = true,
Group = Constants.PropertyEditors.Groups.Lists,
Icon = Constants.Icons.ListView)]
public class ListViewPropertyEditor : DataEditor
{
/// <summary>
@@ -5,7 +5,14 @@ using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PropertyEditors
{
// TODO: MacroContainerPropertyEditor is deprecated, but what's the alternative?
[DataEditor(Constants.PropertyEditors.Aliases.MacroContainer, "(Obsolete) Macro Picker", "macrocontainer", ValueType = ValueTypes.Text, Group = "rich content", Icon = Constants.Icons.Macro, IsDeprecated = true)]
[DataEditor(
Constants.PropertyEditors.Aliases.MacroContainer,
"(Obsolete) Macro Picker",
"macrocontainer",
ValueType = ValueTypes.Text,
Group = Constants.PropertyEditors.Groups.RichContent,
Icon = Constants.Icons.Macro,
IsDeprecated = true)]
public class MacroContainerPropertyEditor : DataEditor
{
public MacroContainerPropertyEditor(ILogger logger)
@@ -7,7 +7,13 @@ namespace Umbraco.Web.PropertyEditors
/// <summary>
/// Represents a markdown editor.
/// </summary>
[DataEditor(Constants.PropertyEditors.Aliases.MarkdownEditor, "Markdown editor", "markdowneditor", ValueType = ValueTypes.Text, Icon="icon-code", Group="rich content")]
[DataEditor(
Constants.PropertyEditors.Aliases.MarkdownEditor,
"Markdown editor",
"markdowneditor",
ValueType = ValueTypes.Text,
Group = Constants.PropertyEditors.Groups.RichContent,
Icon = "icon-code")]
public class MarkdownPropertyEditor : DataEditor
{
/// <summary>
@@ -7,8 +7,14 @@ namespace Umbraco.Web.PropertyEditors
/// <summary>
/// Represents a media picker property editor.
/// </summary>
[DataEditor(Constants.PropertyEditors.Aliases.MediaPicker, EditorType.PropertyValue | EditorType.MacroParameter,
"Media Picker", "mediapicker", ValueType = ValueTypes.Text, Group = "media", Icon = Constants.Icons.MediaImage)]
[DataEditor(
Constants.PropertyEditors.Aliases.MediaPicker,
EditorType.PropertyValue | EditorType.MacroParameter,
"Media Picker",
"mediapicker",
ValueType = ValueTypes.Text,
Group = Constants.PropertyEditors.Groups.Media,
Icon = Constants.Icons.MediaImage)]
public class MediaPickerPropertyEditor : DataEditor
{
/// <summary>

Some files were not shown because too many files have changed in this diff Show More