From 1e501cc3c375427cc00ad22597b84a7972b50aa6 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 3 Oct 2018 11:27:15 +0200 Subject: [PATCH 01/44] wip schedule publish dialog --- .../components/content/edit.controller.js | 24 +++ .../src/less/components/overlays.less | 2 +- .../src/views/components/content/edit.html | 8 + .../content/overlays/schedule.controller.js | 139 ++++++++++++++++++ .../src/views/content/overlays/schedule.html | 85 +++++++++++ .../Umbraco/config/lang/en_us.xml | 1 + 6 files changed, 258 insertions(+), 1 deletion(-) create mode 100644 src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js create mode 100644 src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js index ed0259f78b..ef7702740a 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js @@ -536,6 +536,30 @@ }; + $scope.schedule = function() { + clearNotifications($scope.content); + //before we launch the dialog we want to execute all client side validations first + if (formHelper.submitForm({ scope: $scope, action: "schedule" })) { + + var dialog = { + parentScope: $scope, + view: "views/content/overlays/schedule.html", + variants: $scope.content.variants, //set a model property for the dialog + skipFormValidation: true, //when submitting the overlay form, skip any client side validation + submitButtonLabel: "Schedule", + submit: function (model) { + model.submitButtonState = "busy"; + clearNotifications($scope.content); + model.submitButtonState = "success"; + }, + close: function () { + overlayService.close(); + } + }; + overlayService.open(dialog); + } + }; + $scope.preview = function (content) { diff --git a/src/Umbraco.Web.UI.Client/src/less/components/overlays.less b/src/Umbraco.Web.UI.Client/src/less/components/overlays.less index 3fbe32134b..6538a751f9 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/overlays.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/overlays.less @@ -75,7 +75,7 @@ /* ---------- OVERLAY CENTER ---------- */ .umb-overlay.umb-overlay-center { position: absolute; - width: 500px; + width: 600px; height: auto; top: 50%; left: 50%; diff --git a/src/Umbraco.Web.UI.Client/src/views/components/content/edit.html b/src/Umbraco.Web.UI.Client/src/views/components/content/edit.html index d5ee000e87..1fb9d6691c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/content/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/content/edit.html @@ -28,6 +28,14 @@ + + + + +
+

+
+ +
+ +
+ +
+ +
+ + + +
+ +
+ +
+
Publish:
+ +
+ + +
+ {{variant.releaseDateFormatted}} +
+ + + Set date + + +
+ + + + +
+ +
Unpublish:
+ +
+ + +
+ {{variant.removeDateFormatted}} +
+ + + Set date + + +
+ + + + +
+ +
+ +
+
+ +
+
+
+
+ + \ No newline at end of file diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml index a6ccd30923..28d2f7700d 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -265,6 +265,7 @@ This value is hidden. What languages would you like to publish? What languages would you like to save? + What languages would you like to schedule? What languages would you like to send for approval? Published Languages Unmodified Languages From 739effba467fd0ee7ed3ee85a291f736c798302c Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 3 Oct 2018 14:51:20 +0200 Subject: [PATCH 02/44] add schedule publish to the publish combo button --- .../components/content/edit.controller.js | 3 ++- .../services/contenteditinghelper.service.js | 21 +++++++++++++++++-- .../src/views/components/content/edit.html | 8 ------- .../content/overlays/schedule.controller.js | 6 ------ .../src/views/content/overlays/schedule.html | 4 ++-- .../Umbraco/config/lang/en_us.xml | 1 + 6 files changed, 24 insertions(+), 19 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js index ef7702740a..73a62b2761 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js @@ -177,7 +177,8 @@ methods: { saveAndPublish: $scope.saveAndPublish, sendToPublish: $scope.sendToPublish, - unPublish: $scope.unPublish + unPublish: $scope.unPublish, + schedulePublish: $scope.schedule } }); diff --git a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js index a11c93c2da..6efdb7ffdc 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js @@ -146,7 +146,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica if (!args.methods) { throw "args.methods is not defined"; } - if (!args.methods.saveAndPublish || !args.methods.sendToPublish || !args.methods.unPublish) { + if (!args.methods.saveAndPublish || !args.methods.sendToPublish || !args.methods.unPublish || !args.methods.schedulePublish) { throw "args.methods does not contain all required defined methods"; } @@ -189,6 +189,16 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica hotKeyWhenHidden: true, alias: "unpublish" }; + case "SCHEDULE": + //schedule publish - schedule doesn't have a permission letter so + // the button letter is made unique so it doesn't collide with anything else + return { + letter: ch, + labelKey: "buttons_schedulePublish", + handler: args.methods.schedulePublish, + alias: "schedulePublish", + addEllipsis: args.content.variants && args.content.variants.length > 1 ? "true" : "false" + }; default: return null; } @@ -199,7 +209,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica //This is the ideal button order but depends on circumstance, we'll use this array to create the button list // Publish, SendToPublish - var buttonOrder = ["U", "H"]; + var buttonOrder = ["U", "H", "SCHEDULE"]; //Create the first button (primary button) //We cannot have the Save or SaveAndPublish buttons if they don't have create permissions when we are creating a new item. @@ -214,6 +224,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica break; } } + //Here's the special check, if the button still isn't set and we are creating and they have create access //we need to add the Save button if (!buttons.defaultButton && args.create && _.contains(args.content.allowedActions, "C")) { @@ -236,6 +247,12 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica } } + // if publishing is allowed also allow schedule publish + // we add this manually becuase it doesn't have a permission so it wont + // get picked up by the loop through permissions + if( _.contains(args.content.allowedActions, "U")) { + buttons.subButtons.push(createButtonDefinition("SCHEDULE")); + } // if we are not creating, then we should add unpublish too, // so long as it's already published and if the user has access to publish diff --git a/src/Umbraco.Web.UI.Client/src/views/components/content/edit.html b/src/Umbraco.Web.UI.Client/src/views/components/content/edit.html index 1fb9d6691c..d5ee000e87 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/content/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/content/edit.html @@ -28,14 +28,6 @@ - - - - + @@ -67,7 +67,7 @@ - + diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml index 28d2f7700d..16b595b9f5 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml @@ -131,6 +131,7 @@ Save and schedule Send for approval Save list view + Schedule publish Preview Preview is disabled because there's no template assigned Choose style From fbff56d911a2eaaa242db668508f0a4a6908cbdb Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 3 Oct 2018 14:57:45 +0200 Subject: [PATCH 03/44] change schedule flag to save flag --- .../src/views/content/overlays/schedule.controller.js | 2 +- .../src/views/content/overlays/schedule.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js index 87856c6c53..553aa77106 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js @@ -122,7 +122,7 @@ //when this dialog is closed, reset all 'save' flags $scope.$on('$destroy', function () { for (var i = 0; i < vm.variants.length; i++) { - vm.variants[i].schedule = false; + vm.variants[i].save = false; } }); diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html index eb45870425..b5961aaae4 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html @@ -13,7 +13,7 @@ id="{{variant.language.culture}}" name="saveVariantSelector" type="checkbox" - ng-model="variant.schedule" + ng-model="variant.save" ng-change="vm.changeSelection(variant)" style="margin-right: 8px;" />
From 0bbacf46ea3df71b62b7883357f01e71d42baf41 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 3 Oct 2018 16:41:56 +0200 Subject: [PATCH 04/44] add filters --- .../content/overlays/schedule.controller.js | 84 +++++++++++++++++++ .../src/views/content/overlays/schedule.html | 28 +++++-- 2 files changed, 107 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js index 553aa77106..fa835341e2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js @@ -8,6 +8,9 @@ vm.datePickerChange = datePickerChange; vm.clearPublishDate = clearPublishDate; vm.clearUnpublishDate = clearUnpublishDate; + vm.dirtyVariantFilter = dirtyVariantFilter; + vm.pristineVariantFilter = pristineVariantFilter; + vm.changeSelection = changeSelection; vm.currentUser = null; vm.datePickerConfig = { @@ -26,6 +29,7 @@ function onInit() { vm.variants = $scope.model.variants; + vm.hasPristineVariants = false; if(!$scope.model.title) { localizationService.localize("general_scheduledPublishing").then(function(value){ @@ -33,6 +37,40 @@ }); } + _.each(vm.variants, + function (variant) { + variant.compositeId = variant.language.culture + "_" + (variant.segment ? variant.segment : ""); + variant.htmlId = "_content_variant_" + variant.compositeId; + + //check for pristine variants + if (!vm.hasPristineVariants) { + vm.hasPristineVariants = pristineVariantFilter(variant); + } + }); + + if (vm.variants.length !== 0) { + //now sort it so that the current one is at the top + vm.variants = _.sortBy(vm.variants, function (v) { + return v.active ? 0 : 1; + }); + + var active = _.find(vm.variants, function (v) { + return v.active; + }); + + if (active) { + //ensure that the current one is selected + active.schedule = true; + active.save = true; + } + + //$scope.model.disableSubmitButton = !canPublish(); + + } else { + //disable Publish button if we have nothing to publish, should not happen + //$scope.model.disableSubmitButton = true; + } + // get current backoffice user and format dates userService.getCurrentUser().then(function (currentUser) { @@ -117,11 +155,57 @@ } + function changeSelection(variant) { + $scope.model.disableSubmitButton = !canSchedule(); + //need to set the Save state to true if publish is true + variant.save = variant.schedule; + } + + function dirtyVariantFilter(variant) { + //determine a variant is 'dirty' (meaning it will show up as publish-able) if it's + // * the active one + // * it's editor is in a $dirty state + // * it has pending saves + // * it is unpublished + // * it is in NotCreated state + return (variant.active || variant.isDirty || variant.state === "Draft" || variant.state === "PublishedPendingChanges" || variant.state === "NotCreated"); + } + + function pristineVariantFilter(variant) { + return !(dirtyVariantFilter(variant)); + } + + /** Returns true if publishing is possible based on if there are un-published mandatory languages */ + function canSchedule() { + var selected = []; + for (var i = 0; i < vm.variants.length; i++) { + var variant = vm.variants[i]; + + //if this variant will show up in the publish-able list + var publishable = dirtyVariantFilter(variant); + + if ((variant.language.isMandatory && (variant.state === "NotCreated" || variant.state === "Draft")) + && (!publishable || !variant.schedule)) { + //if a mandatory variant isn't published and it's not publishable or not selected to be published + //then we cannot publish anything + + //TODO: Show a message when this occurs + return false; + } + + if (variant.schedule) { + selected.push(variant.schedule); + } + } + return selected.length > 0; + } + onInit(); //when this dialog is closed, reset all 'save' flags $scope.$on('$destroy', function () { for (var i = 0; i < vm.variants.length; i++) { + vm.variants[i].schedule = false; vm.variants[i].save = false; } }); diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html index b5961aaae4..b12b697552 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html @@ -6,25 +6,25 @@
-
+
-
- +
+ + -
@@ -81,5 +81,23 @@

+ +
+
+

+
+ +
+
+
+ {{ variant.language.name }} +
+
+ + - +
+
+
+
\ No newline at end of file From 26759e97faabb065adfc998ad48e59ed0a10f4c4 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 3 Oct 2018 19:03:22 +0200 Subject: [PATCH 05/44] First iteration to populate property type changes when they are changed variant/invariant --- .../Components/RelateOnCopyComponent.cs | 2 + .../UpdateContentOnVariantChangesComponent.cs | 93 +++++++++++++++++++ src/Umbraco.Core/Models/ContentTypeBase.cs | 3 +- .../Models/ContentTypeBaseExtensions.cs | 49 +++++++++- .../Implement/ContentRepositoryBase.cs | 3 + .../Implement/ContentTypeRepositoryBase.cs | 4 +- .../Implement/LanguageRepository.cs | 23 +++-- .../ContentTypeServiceBaseOfTItemTService.cs | 6 +- ...peServiceBaseOfTRepositoryTItemTService.cs | 20 +++- src/Umbraco.Core/Umbraco.Core.csproj | 1 + .../Repositories/ContentTypeRepositoryTest.cs | 5 +- ...itoryTest.cs => DocumentRepositoryTest.cs} | 2 +- .../Services/ContentTypeServiceTests.cs | 49 ++++++++++ src/Umbraco.Tests/Umbraco.Tests.csproj | 2 +- .../NuCache/PublishedSnapshotService.cs | 15 +-- .../XmlPublishedCache/XmlStore.cs | 12 +-- 16 files changed, 253 insertions(+), 36 deletions(-) create mode 100644 src/Umbraco.Core/Components/UpdateContentOnVariantChangesComponent.cs rename src/Umbraco.Tests/Persistence/Repositories/{ContentRepositoryTest.cs => DocumentRepositoryTest.cs} (99%) diff --git a/src/Umbraco.Core/Components/RelateOnCopyComponent.cs b/src/Umbraco.Core/Components/RelateOnCopyComponent.cs index 4ebd309e9f..5356fa6e30 100644 --- a/src/Umbraco.Core/Components/RelateOnCopyComponent.cs +++ b/src/Umbraco.Core/Components/RelateOnCopyComponent.cs @@ -1,10 +1,12 @@ using Umbraco.Core.Composing; using Umbraco.Core.Models; +using Umbraco.Core.Persistence.Repositories.Implement; using Umbraco.Core.Services; using Umbraco.Core.Services.Implement; namespace Umbraco.Core.Components { + //TODO: This should just exist in the content service/repo! [RuntimeLevel(MinLevel = RuntimeLevel.Run)] public sealed class RelateOnCopyComponent : UmbracoComponentBase, IUmbracoCoreComponent diff --git a/src/Umbraco.Core/Components/UpdateContentOnVariantChangesComponent.cs b/src/Umbraco.Core/Components/UpdateContentOnVariantChangesComponent.cs new file mode 100644 index 0000000000..06d2b86166 --- /dev/null +++ b/src/Umbraco.Core/Components/UpdateContentOnVariantChangesComponent.cs @@ -0,0 +1,93 @@ +using System; +using System.Linq; +using Umbraco.Core.Models; +using Umbraco.Core.Models.Entities; +using Umbraco.Core.Services; +using Umbraco.Core.Services.Changes; +using Umbraco.Core.Services.Implement; + +namespace Umbraco.Core.Components +{ + /// + /// Manages data changes for when content/property types have variation changes + /// + [RuntimeLevel(MinLevel = RuntimeLevel.Run)] + public sealed class UpdateContentOnVariantChangesComponent : UmbracoComponentBase, IUmbracoCoreComponent + { + private IContentService _contentService; + private ILocalizationService _langService; + + public void Initialize(IContentService contentService, ILocalizationService langService) + { + _contentService = contentService; + _langService = langService; + ContentTypeService.ScopedRefreshedEntity += OnContentTypeRefreshedEntity; + } + + private void OnContentTypeRefreshedEntity(IContentTypeService sender, ContentTypeChange.EventArgs e) + { + var defaultLang = _langService.GetDefaultLanguageIsoCode(); //this will be cached + + foreach (var c in e.Changes) + { + // existing property alias change? + var hasAnyPropertyVariationChanged = c.Item.WasPropertyTypeVariationChanged(out var aliases); + if (hasAnyPropertyVariationChanged) + { + var contentOfType = _contentService.GetByType(c.Item.Id); + + foreach (var a in aliases) + { + var propType = c.Item.PropertyTypes.First(x => x.Alias == a); + + switch(propType.Variations) + { + case ContentVariation.Culture: + //if the current variation is culture it means that the previous was nothing + foreach (var content in contentOfType) + { + object invariantVal; + try + { + content.Properties[a].PropertyType.Variations = ContentVariation.Nothing; + //now get the culture val + invariantVal = content.GetValue(a); + } + finally + { + content.Properties[a].PropertyType.Variations = ContentVariation.Culture; + } + //set the invariant value + content.SetValue(a, invariantVal, defaultLang); + } + break; + case ContentVariation.Nothing: + //if the current variation is nothing it means that the previous was culture + foreach(var content in contentOfType) + { + object cultureVal; + try + { + content.Properties[a].PropertyType.Variations = ContentVariation.Culture; + //now get the culture val + cultureVal = content.GetValue(a, defaultLang); + } + finally + { + content.Properties[a].PropertyType.Variations = ContentVariation.Nothing; + } + //set the invariant value + content.SetValue(a, cultureVal); + } + break; + default: + throw new NotSupportedException("The variation change is not supported"); + } + } + + _contentService.Save(contentOfType); + } + } + } + } +} diff --git a/src/Umbraco.Core/Models/ContentTypeBase.cs b/src/Umbraco.Core/Models/ContentTypeBase.cs index 6f90b5201d..7467d83099 100644 --- a/src/Umbraco.Core/Models/ContentTypeBase.cs +++ b/src/Umbraco.Core/Models/ContentTypeBase.cs @@ -408,7 +408,8 @@ namespace Umbraco.Core.Models /// PropertyTypes that are not part of a PropertyGroup /// [IgnoreDataMember] - internal PropertyTypeCollection PropertyTypeCollection => _propertyTypes; + //fixme should we mark this as EditorBrowsable hidden since it really isn't ever used? + internal PropertyTypeCollection PropertyTypeCollection => _propertyTypes; /// /// Indicates whether a specific property on the current entity is dirty. diff --git a/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs b/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs index ef55f0d469..8af48bb881 100644 --- a/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs +++ b/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs @@ -1,4 +1,8 @@ -using Umbraco.Core.Models.PublishedContent; +using System; +using System.Collections.Generic; +using System.Linq; +using Umbraco.Core.Models.Entities; +using Umbraco.Core.Models.PublishedContent; namespace Umbraco.Core.Models { @@ -16,5 +20,48 @@ namespace Umbraco.Core.Models else if (typeof(IMemberType).IsAssignableFrom(type)) itemType = PublishedItemType.Member; return itemType; } + + /// + /// Used to check if any property type was changed between variant/invariant + /// + /// + /// + internal static bool WasPropertyTypeVariationChanged(this IContentTypeBase contentType) + { + return contentType.WasPropertyTypeVariationChanged(out var _); + } + + /// + /// Used to check if any property type was changed between variant/invariant + /// + /// + /// + internal static bool WasPropertyTypeVariationChanged(this IContentTypeBase contentType, out IReadOnlyCollection aliases) + { + var a = new List(); + + // property variation change? + var hasAnyPropertyVariationChanged = contentType.PropertyTypes.Any(propertyType => + { + if (!(propertyType is IRememberBeingDirty dirtyProperty)) + throw new Exception("oops"); + + // skip new properties + //TODO: This used to be WasPropertyDirty("HasIdentity") but i don't think that actually worked for detecting new entities this does seem to work properly + var isNewProperty = dirtyProperty.WasPropertyDirty("Id"); + if (isNewProperty) return false; + + // variation change? + var dirty = dirtyProperty.WasPropertyDirty("Variations"); + if (dirty) + a.Add(propertyType.Alias); + + return dirty; + + }); + + aliases = a; + return hasAnyPropertyVariationChanged; + } } } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs index 6ace73fbc3..c258a76b30 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentRepositoryBase.cs @@ -608,6 +608,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement #region UnitOfWork Events + //fixme: The reason these events are in the repository is for legacy, the events should exist at the service + // level now since we can fire these events within the transaction... so move the events to service level + public class ScopedEntityEventArgs : EventArgs { public ScopedEntityEventArgs(IScope scope, TEntity entity) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index 555fc56157..05b9bc8631 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -323,9 +323,7 @@ AND umbracoNode.id <> @id", }); } - // fixme below, manage the property type - - // delete ??? fixme wtf is this? + // delete property types // ... by excepting entries from db with entries from collections if (entity.IsPropertyDirty("PropertyTypes") || entity.PropertyTypes.Any(x => x.IsDirty())) { diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs index ae5d9ae8b8..2026daba74 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs @@ -30,7 +30,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement return new FullDataSetRepositoryCachePolicy(GlobalIsolatedCache, ScopeAccessor, GetEntityId, /*expires:*/ false); } - private FullDataSetRepositoryCachePolicy TypedCachePolicy => (FullDataSetRepositoryCachePolicy) CachePolicy; + private FullDataSetRepositoryCachePolicy TypedCachePolicy => CachePolicy as FullDataSetRepositoryCachePolicy; #region Overrides of RepositoryBase @@ -215,7 +215,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement public ILanguage GetByIsoCode(string isoCode) { - TypedCachePolicy.GetAllCached(PerformGetAll); // ensure cache is populated, in a non-expensive way + // ensure cache is populated, in a non-expensive way + if (TypedCachePolicy != null) + TypedCachePolicy.GetAllCached(PerformGetAll); + var id = GetIdByIsoCode(isoCode, throwOnNotFound: false); return id.HasValue ? Get(id.Value) : null; } @@ -228,7 +231,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { if (isoCode == null) return null; - TypedCachePolicy.GetAllCached(PerformGetAll); // ensure cache is populated, in a non-expensive way + // ensure cache is populated, in a non-expensive way + if (TypedCachePolicy != null) + TypedCachePolicy.GetAllCached(PerformGetAll); + lock (_codeIdMap) { if (_codeIdMap.TryGetValue(isoCode, out var id)) return id; @@ -246,7 +252,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { if (id == null) return null; - TypedCachePolicy.GetAllCached(PerformGetAll); // ensure cache is populated, in a non-expensive way + // ensure cache is populated, in a non-expensive way + if (TypedCachePolicy != null) + TypedCachePolicy.GetAllCached(PerformGetAll); + lock (_codeIdMap) // yes, we want to lock _codeIdMap { if (_idCodeMap.TryGetValue(id.Value, out var isoCode)) return isoCode; @@ -269,8 +278,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement // do NOT leak that language, it's not deep-cloned! private ILanguage GetDefault() { - // get all cached, non-cloned - var languages = TypedCachePolicy.GetAllCached(PerformGetAll).ToList(); + // get all cached + var languages = (TypedCachePolicy?.GetAllCached(PerformGetAll) //try to get all cached non-cloned if using the correct cache policy (not the case in unit tests) + ?? CachePolicy.GetAll(Array.Empty(), PerformGetAll)).ToList(); + var language = languages.FirstOrDefault(x => x.IsDefaultVariantLanguage); if (language != null) return language; diff --git a/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTItemTService.cs b/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTItemTService.cs index 9fa9a47003..33fb9a0894 100644 --- a/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTItemTService.cs +++ b/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTItemTService.cs @@ -20,12 +20,12 @@ namespace Umbraco.Core.Services.Implement internal static event TypedEventHandler.EventArgs> Changed; // that one is always immediate (transactional) - public static event TypedEventHandler.EventArgs> UowRefreshedEntity; + public static event TypedEventHandler.EventArgs> ScopedRefreshedEntity; // used by tests to clear events internal static void ClearScopeEvents() { - UowRefreshedEntity = null; + ScopedRefreshedEntity = null; } // these must be dispatched @@ -48,7 +48,7 @@ namespace Umbraco.Core.Services.Implement protected void OnUowRefreshedEntity(ContentTypeChange.EventArgs args) { // that one is always immediate (not dispatched, transactional) - UowRefreshedEntity.RaiseEvent(args, This); + ScopedRefreshedEntity.RaiseEvent(args, This); } protected bool OnSavingCancelled(IScope scope, SaveEventArgs args) diff --git a/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs b/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs index 8ed0a0f645..a3bc87315b 100644 --- a/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs +++ b/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs @@ -118,6 +118,8 @@ namespace Umbraco.Core.Services.Implement // - content type alias changed // - content type property removed, or alias changed // - content type composition removed (not testing if composition had properties...) + // - content type variation changed + // - property type variation changed // // because these are the changes that would impact the raw content data @@ -132,7 +134,8 @@ namespace Umbraco.Core.Services.Implement var dirty = (IRememberBeingDirty)contentType; // skip new content types - var isNewContentType = dirty.WasPropertyDirty("HasIdentity"); + //TODO: This used to be WasPropertyDirty("HasIdentity") but i don't think that actually worked for detecting new entities this does seem to work properly + var isNewContentType = dirty.WasPropertyDirty("Id"); if (isNewContentType) { AddChange(changes, contentType, ContentTypeChangeTypes.Create); @@ -149,12 +152,12 @@ namespace Umbraco.Core.Services.Implement throw new Exception("oops"); // skip new properties - var isNewProperty = dirtyProperty.WasPropertyDirty("HasIdentity"); + //TODO: This used to be WasPropertyDirty("HasIdentity") but i don't think that actually worked for detecting new entities this does seem to work properly + var isNewProperty = dirtyProperty.WasPropertyDirty("Id"); if (isNewProperty) return false; // alias change? - var hasPropertyAliasBeenChanged = dirtyProperty.WasPropertyDirty("Alias"); - return hasPropertyAliasBeenChanged; + return dirtyProperty.WasPropertyDirty("Alias"); }); // removed properties? @@ -163,8 +166,15 @@ namespace Umbraco.Core.Services.Implement // removed compositions? var hasAnyCompositionBeenRemoved = dirty.WasPropertyDirty("HasCompositionTypeBeenRemoved"); + // variation changed? + var hasContentTypeVariationChanged = dirty.WasPropertyDirty("Variations"); + + // property variation change? + var hasAnyPropertyVariationChanged = contentType.WasPropertyTypeVariationChanged(); + // main impact on properties? - var hasPropertyMainImpact = hasAnyCompositionBeenRemoved || hasAnyPropertyBeenRemoved || hasAnyPropertyChangedAlias; + var hasPropertyMainImpact = hasContentTypeVariationChanged || hasAnyPropertyVariationChanged + || hasAnyCompositionBeenRemoved || hasAnyPropertyBeenRemoved || hasAnyPropertyChangedAlias; if (hasAliasChanged || hasPropertyMainImpact) { diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 496a66137a..379d5ad48a 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -170,6 +170,7 @@ + diff --git a/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs index 31105aa28e..6087279285 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/ContentTypeRepositoryTest.cs @@ -63,8 +63,7 @@ namespace Umbraco.Tests.Persistence.Repositories } //TODO Add test to verify SetDefaultTemplates updates both AllowedTemplates and DefaultTemplate(id). - - + [Test] public void Maps_Templates_Correctly() { @@ -377,7 +376,7 @@ namespace Umbraco.Tests.Persistence.Repositories repository.Save(contentType); - var dirty = ((ICanBeDirty)contentType).IsDirty(); + var dirty = contentType.IsDirty(); // Assert Assert.That(contentType.HasIdentity, Is.True); diff --git a/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs similarity index 99% rename from src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs rename to src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs index 7ff7c0a2e4..68e29c4efe 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/DocumentRepositoryTest.cs @@ -25,7 +25,7 @@ namespace Umbraco.Tests.Persistence.Repositories { [TestFixture] [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest)] - public class ContentRepositoryTest : TestWithDatabaseBase + public class DocumentRepositoryTest : TestWithDatabaseBase { public override void SetUp() { diff --git a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs index be07dbdd23..8ece9621ce 100644 --- a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs @@ -15,6 +15,7 @@ using Umbraco.Core.Services.Implement; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.TestHelpers.Entities; using Umbraco.Tests.Testing; +using Umbraco.Core.Components; namespace Umbraco.Tests.Services { @@ -23,6 +24,54 @@ namespace Umbraco.Tests.Services [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true)] public class ContentTypeServiceTests : TestWithSomeContentBase { + [Test] + public void Change_Property_Type_From_Variant_Invariant() + { + //initialize the listener which is responsible for updating content based on variant/invariant changes + var listener = new UpdateContentOnVariantChangesComponent(); + listener.Initialize(ServiceContext.ContentService, ServiceContext.LocalizationService); + + //create content type with a property type that varies by culture + var contentType = MockedContentTypes.CreateBasicContentType(); + contentType.Variations = ContentVariation.Culture; + var contentCollection = new PropertyTypeCollection(true); + contentCollection.Add(new PropertyType("test", ValueStorageType.Ntext) + { + Alias = "title", + Name = "Title", + Description = "", + Mandatory = false, + SortOrder = 1, + DataTypeId = -88, + Variations = ContentVariation.Culture + }); + contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 }); + contentType.ResetDirtyProperties(false); + ServiceContext.ContentTypeService.Save(contentType); + + //create some content of this content type + IContent doc = MockedContent.CreateBasicContent(contentType); + doc.SetCultureName("Home", "en-US"); + doc.SetValue("title", "hello world", "en-US"); + ServiceContext.ContentService.Save(doc); + + Assert.AreEqual("hello world", doc.GetValue("title", "en-US")); + + //change the property type to be invariant + contentType.PropertyTypes.First().Variations = ContentVariation.Nothing; + ServiceContext.ContentTypeService.Save(contentType); + doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + + Assert.AreEqual("hello world", doc.GetValue("title")); + + //change back property type to be variant + contentType.PropertyTypes.First().Variations = ContentVariation.Culture; + ServiceContext.ContentTypeService.Save(contentType); + doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + + Assert.AreEqual("hello world", doc.GetValue("title", "en-US")); + } + [Test] public void Deleting_Media_Type_With_Hierarchy_Of_Media_Items_Moves_Orphaned_Media_To_Recycle_Bin() { diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index a3f02b2fdc..aac1f0b865 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -123,6 +123,7 @@ + @@ -393,7 +394,6 @@ - diff --git a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs index 8786753e4f..a9903669b9 100644 --- a/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs +++ b/src/Umbraco.Web/PublishedCache/NuCache/PublishedSnapshotService.cs @@ -198,6 +198,9 @@ namespace Umbraco.Web.PublishedCache.NuCache private void InitializeRepositoryEvents() { + //fixme: The reason these events are in the repository is for legacy, the events should exist at the service + // level now since we can fire these events within the transaction... so move the events to service level + // plug repository event handlers // these trigger within the transaction to ensure consistency // and are used to maintain the central, database-level XML cache @@ -212,9 +215,9 @@ namespace Umbraco.Web.PublishedCache.NuCache MemberRepository.ScopedEntityRefresh += OnMemberRefreshedEntity; // plug - ContentTypeService.UowRefreshedEntity += OnContentTypeRefreshedEntity; - MediaTypeService.UowRefreshedEntity += OnMediaTypeRefreshedEntity; - MemberTypeService.UowRefreshedEntity += OnMemberTypeRefreshedEntity; + ContentTypeService.ScopedRefreshedEntity += OnContentTypeRefreshedEntity; + MediaTypeService.ScopedRefreshedEntity += OnMediaTypeRefreshedEntity; + MemberTypeService.ScopedRefreshedEntity += OnMemberTypeRefreshedEntity; } private void TearDownRepositoryEvents() @@ -229,9 +232,9 @@ namespace Umbraco.Web.PublishedCache.NuCache //MemberRepository.RemovedVersion -= OnMemberRemovedVersion; MemberRepository.ScopedEntityRefresh -= OnMemberRefreshedEntity; - ContentTypeService.UowRefreshedEntity -= OnContentTypeRefreshedEntity; - MediaTypeService.UowRefreshedEntity -= OnMediaTypeRefreshedEntity; - MemberTypeService.UowRefreshedEntity -= OnMemberTypeRefreshedEntity; + ContentTypeService.ScopedRefreshedEntity -= OnContentTypeRefreshedEntity; + MediaTypeService.ScopedRefreshedEntity -= OnMediaTypeRefreshedEntity; + MemberTypeService.ScopedRefreshedEntity -= OnMemberTypeRefreshedEntity; } public override void Dispose() diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlStore.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlStore.cs index 5fa89e3f7b..5b816c2f26 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlStore.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlStore.cs @@ -194,9 +194,9 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache MemberRepository.ScopedEntityRefresh += OnMemberRefreshedEntity; // plug - ContentTypeService.UowRefreshedEntity += OnContentTypeRefreshedEntity; - MediaTypeService.UowRefreshedEntity += OnMediaTypeRefreshedEntity; - MemberTypeService.UowRefreshedEntity += OnMemberTypeRefreshedEntity; + ContentTypeService.ScopedRefreshedEntity += OnContentTypeRefreshedEntity; + MediaTypeService.ScopedRefreshedEntity += OnMediaTypeRefreshedEntity; + MemberTypeService.ScopedRefreshedEntity += OnMemberTypeRefreshedEntity; _withRepositoryEvents = true; } @@ -213,9 +213,9 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache MemberRepository.ScopeVersionRemove -= OnMemberRemovingVersion; MemberRepository.ScopedEntityRefresh -= OnMemberRefreshedEntity; - ContentTypeService.UowRefreshedEntity -= OnContentTypeRefreshedEntity; - MediaTypeService.UowRefreshedEntity -= OnMediaTypeRefreshedEntity; - MemberTypeService.UowRefreshedEntity -= OnMemberTypeRefreshedEntity; + ContentTypeService.ScopedRefreshedEntity -= OnContentTypeRefreshedEntity; + MediaTypeService.ScopedRefreshedEntity -= OnMediaTypeRefreshedEntity; + MemberTypeService.ScopedRefreshedEntity -= OnMemberTypeRefreshedEntity; _withRepositoryEvents = false; } From f76df08cd2df3c84453db4f16ba9b3d5ada697d0 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 3 Oct 2018 19:34:02 +0200 Subject: [PATCH 06/44] ensures that property type variations are set to nothing if the content type is updated to nothing --- .../UpdateContentOnVariantChangesComponent.cs | 7 +- .../Implement/ContentTypeRepositoryBase.cs | 9 ++ .../Services/ContentTypeServiceTests.cs | 99 +++++++++++++++++++ 3 files changed, 113 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Core/Components/UpdateContentOnVariantChangesComponent.cs b/src/Umbraco.Core/Components/UpdateContentOnVariantChangesComponent.cs index 06d2b86166..71fe4d46bd 100644 --- a/src/Umbraco.Core/Components/UpdateContentOnVariantChangesComponent.cs +++ b/src/Umbraco.Core/Components/UpdateContentOnVariantChangesComponent.cs @@ -12,6 +12,7 @@ namespace Umbraco.Core.Components /// Manages data changes for when content/property types have variation changes /// [RuntimeLevel(MinLevel = RuntimeLevel.Run)] + //fixme: this one MUST fire before any of the content cache ones public sealed class UpdateContentOnVariantChangesComponent : UmbracoComponentBase, IUmbracoCoreComponent { private IContentService _contentService; @@ -40,7 +41,9 @@ namespace Umbraco.Core.Components { var propType = c.Item.PropertyTypes.First(x => x.Alias == a); - switch(propType.Variations) + //fixme: this does not take into account segments, but how can we since we don't know what it changed from? + + switch (propType.Variations) { case ContentVariation.Culture: //if the current variation is culture it means that the previous was nothing @@ -50,7 +53,7 @@ namespace Umbraco.Core.Components try { content.Properties[a].PropertyType.Variations = ContentVariation.Nothing; - //now get the culture val + //now get the invariant val invariantVal = content.GetValue(a); } finally diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index 05b9bc8631..743b7c858e 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -402,10 +402,19 @@ AND umbracoNode.id <> @id", propertyType.PropertyGroupId = new Lazy(() => groupId); } + //check if the content type variation has been changed to Nothing since we will need to update + //all property types to Nothing as well if they aren't already + //fixme: this does not take into account segments, but how can we since we don't know what it changed from? + var ctVariationChangedToNothing = entity.IsPropertyDirty("Variations") && entity.Variations == ContentVariation.Nothing; + // insert or update properties // all of them, no-group and in-groups foreach (var propertyType in entity.PropertyTypes) { + //fixme: this does not take into account segments, but how can we since we don't know what it changed from? + if (ctVariationChangedToNothing && propertyType.Variations != ContentVariation.Nothing) + propertyType.Variations = ContentVariation.Nothing; + var groupId = propertyType.PropertyGroupId?.Value ?? default(int); // if the Id of the DataType is not set, we resolve it from the db by its PropertyEditorAlias if (propertyType.DataTypeId == 0 || propertyType.DataTypeId == default(int)) diff --git a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs index 8ece9621ce..ad16f4228a 100644 --- a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs @@ -24,6 +24,105 @@ namespace Umbraco.Tests.Services [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true)] public class ContentTypeServiceTests : TestWithSomeContentBase { + + //TODO: Then write the ones for content type changes + + [Test] + public void Change_Content_Type_From_Variant_Invariant() + { + //initialize the listener which is responsible for updating content based on variant/invariant changes + var listener = new UpdateContentOnVariantChangesComponent(); + listener.Initialize(ServiceContext.ContentService, ServiceContext.LocalizationService); + + //create content type with a property type that varies by culture + var contentType = MockedContentTypes.CreateBasicContentType(); + contentType.Variations = ContentVariation.Culture; + var contentCollection = new PropertyTypeCollection(true); + contentCollection.Add(new PropertyType("test", ValueStorageType.Ntext) + { + Alias = "title", + Name = "Title", + Description = "", + Mandatory = false, + SortOrder = 1, + DataTypeId = -88, + Variations = ContentVariation.Culture + }); + contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 }); + contentType.ResetDirtyProperties(false); + ServiceContext.ContentTypeService.Save(contentType); + + //create some content of this content type + IContent doc = MockedContent.CreateBasicContent(contentType); + doc.SetCultureName("Home", "en-US"); + doc.SetValue("title", "hello world", "en-US"); + ServiceContext.ContentService.Save(doc); + + Assert.AreEqual("hello world", doc.GetValue("title", "en-US")); + + //change the content type to be invariant + contentType.Variations = ContentVariation.Nothing; + ServiceContext.ContentTypeService.Save(contentType); + doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + + Assert.AreEqual("hello world", doc.GetValue("title")); + + //change back property type to be variant + contentType.Variations = ContentVariation.Culture; + ServiceContext.ContentTypeService.Save(contentType); + doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + + Assert.AreEqual("hello world", doc.GetValue("title", "en-US")); + } + + [Test] + public void Change_Property_Type_From_Invariant_Variant() + { + //initialize the listener which is responsible for updating content based on variant/invariant changes + var listener = new UpdateContentOnVariantChangesComponent(); + listener.Initialize(ServiceContext.ContentService, ServiceContext.LocalizationService); + + //create content type with a property type that varies by culture + var contentType = MockedContentTypes.CreateBasicContentType(); + contentType.Variations = ContentVariation.Culture; + var contentCollection = new PropertyTypeCollection(true); + contentCollection.Add(new PropertyType("test", ValueStorageType.Ntext) + { + Alias = "title", + Name = "Title", + Description = "", + Mandatory = false, + SortOrder = 1, + DataTypeId = -88, + Variations = ContentVariation.Nothing + }); + contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 }); + contentType.ResetDirtyProperties(false); + ServiceContext.ContentTypeService.Save(contentType); + + //create some content of this content type + IContent doc = MockedContent.CreateBasicContent(contentType); + doc.SetCultureName("Home", "en-US"); + doc.SetValue("title", "hello world"); + ServiceContext.ContentService.Save(doc); + + Assert.AreEqual("hello world", doc.GetValue("title")); + + //change the property type to be variant + contentType.PropertyTypes.First().Variations = ContentVariation.Culture; + ServiceContext.ContentTypeService.Save(contentType); + doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + + Assert.AreEqual("hello world", doc.GetValue("title", "en-US")); + + //change back property type to be invariant + contentType.PropertyTypes.First().Variations = ContentVariation.Nothing; + ServiceContext.ContentTypeService.Save(contentType); + doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + + Assert.AreEqual("hello world", doc.GetValue("title")); + } + [Test] public void Change_Property_Type_From_Variant_Invariant() { From 7b41730b6061227253e949a77da0720d9b8b4924 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 4 Oct 2018 14:15:54 +0200 Subject: [PATCH 07/44] Changes how variant property data is updated with bulk SQL and gets tests working --- .../UpdateContentOnVariantChangesComponent.cs | 96 --------- src/Umbraco.Core/Models/ContentTypeBase.cs | 16 +- .../Persistence/Dtos/PropertyDataDto.cs | 2 +- .../Persistence/NPocoSqlExtensions.cs | 8 +- .../Implement/ContentTypeRepositoryBase.cs | 185 +++++++++++++++++- src/Umbraco.Core/Umbraco.Core.csproj | 1 - .../Services/ContentTypeServiceTests.cs | 23 ++- 7 files changed, 207 insertions(+), 124 deletions(-) delete mode 100644 src/Umbraco.Core/Components/UpdateContentOnVariantChangesComponent.cs diff --git a/src/Umbraco.Core/Components/UpdateContentOnVariantChangesComponent.cs b/src/Umbraco.Core/Components/UpdateContentOnVariantChangesComponent.cs deleted file mode 100644 index 71fe4d46bd..0000000000 --- a/src/Umbraco.Core/Components/UpdateContentOnVariantChangesComponent.cs +++ /dev/null @@ -1,96 +0,0 @@ -using System; -using System.Linq; -using Umbraco.Core.Models; -using Umbraco.Core.Models.Entities; -using Umbraco.Core.Services; -using Umbraco.Core.Services.Changes; -using Umbraco.Core.Services.Implement; - -namespace Umbraco.Core.Components -{ - /// - /// Manages data changes for when content/property types have variation changes - /// - [RuntimeLevel(MinLevel = RuntimeLevel.Run)] - //fixme: this one MUST fire before any of the content cache ones - public sealed class UpdateContentOnVariantChangesComponent : UmbracoComponentBase, IUmbracoCoreComponent - { - private IContentService _contentService; - private ILocalizationService _langService; - - public void Initialize(IContentService contentService, ILocalizationService langService) - { - _contentService = contentService; - _langService = langService; - ContentTypeService.ScopedRefreshedEntity += OnContentTypeRefreshedEntity; - } - - private void OnContentTypeRefreshedEntity(IContentTypeService sender, ContentTypeChange.EventArgs e) - { - var defaultLang = _langService.GetDefaultLanguageIsoCode(); //this will be cached - - foreach (var c in e.Changes) - { - // existing property alias change? - var hasAnyPropertyVariationChanged = c.Item.WasPropertyTypeVariationChanged(out var aliases); - if (hasAnyPropertyVariationChanged) - { - var contentOfType = _contentService.GetByType(c.Item.Id); - - foreach (var a in aliases) - { - var propType = c.Item.PropertyTypes.First(x => x.Alias == a); - - //fixme: this does not take into account segments, but how can we since we don't know what it changed from? - - switch (propType.Variations) - { - case ContentVariation.Culture: - //if the current variation is culture it means that the previous was nothing - foreach (var content in contentOfType) - { - object invariantVal; - try - { - content.Properties[a].PropertyType.Variations = ContentVariation.Nothing; - //now get the invariant val - invariantVal = content.GetValue(a); - } - finally - { - content.Properties[a].PropertyType.Variations = ContentVariation.Culture; - } - //set the invariant value - content.SetValue(a, invariantVal, defaultLang); - } - break; - case ContentVariation.Nothing: - //if the current variation is nothing it means that the previous was culture - foreach(var content in contentOfType) - { - object cultureVal; - try - { - content.Properties[a].PropertyType.Variations = ContentVariation.Culture; - //now get the culture val - cultureVal = content.GetValue(a, defaultLang); - } - finally - { - content.Properties[a].PropertyType.Variations = ContentVariation.Nothing; - } - //set the invariant value - content.SetValue(a, cultureVal); - } - break; - default: - throw new NotSupportedException("The variation change is not supported"); - } - } - - _contentService.Save(contentOfType); - } - } - } - } -} diff --git a/src/Umbraco.Core/Models/ContentTypeBase.cs b/src/Umbraco.Core/Models/ContentTypeBase.cs index 7467d83099..41d3419f98 100644 --- a/src/Umbraco.Core/Models/ContentTypeBase.cs +++ b/src/Umbraco.Core/Models/ContentTypeBase.cs @@ -409,7 +409,7 @@ namespace Umbraco.Core.Models /// [IgnoreDataMember] //fixme should we mark this as EditorBrowsable hidden since it really isn't ever used? - internal PropertyTypeCollection PropertyTypeCollection => _propertyTypes; + internal PropertyTypeCollection PropertyTypeCollection => _propertyTypes; /// /// Indicates whether a specific property on the current entity is dirty. @@ -418,12 +418,18 @@ namespace Umbraco.Core.Models /// True if Property is dirty, otherwise False public override bool IsPropertyDirty(string propertyName) { - bool existsInEntity = base.IsPropertyDirty(propertyName); + var existsInEntity = base.IsPropertyDirty(propertyName); + if (existsInEntity) return true; - bool anyDirtyGroups = PropertyGroups.Any(x => x.IsPropertyDirty(propertyName)); - bool anyDirtyTypes = PropertyTypes.Any(x => x.IsPropertyDirty(propertyName)); + //check properties types for this alias if it exists + if (PropertyTypeExists(propertyName)) + return PropertyTypes.Any(x => x.IsPropertyDirty(propertyName)); - return existsInEntity || anyDirtyGroups || anyDirtyTypes; + //check property groups for this alias if it exists + if (PropertyGroups.Contains(propertyName)) + return PropertyGroups.Any(x => x.IsPropertyDirty(propertyName)); + + return false; } /// diff --git a/src/Umbraco.Core/Persistence/Dtos/PropertyDataDto.cs b/src/Umbraco.Core/Persistence/Dtos/PropertyDataDto.cs index cb47784d92..a3b28b5b54 100644 --- a/src/Umbraco.Core/Persistence/Dtos/PropertyDataDto.cs +++ b/src/Umbraco.Core/Persistence/Dtos/PropertyDataDto.cs @@ -9,7 +9,7 @@ namespace Umbraco.Core.Persistence.Dtos [ExplicitColumns] internal class PropertyDataDto { - private const string TableName = Constants.DatabaseSchema.Tables.PropertyData; + public const string TableName = Constants.DatabaseSchema.Tables.PropertyData; public const int VarcharLength = 512; public const int SegmentLength = 256; diff --git a/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs b/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs index d97c748b6f..4fdc72f52f 100644 --- a/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs +++ b/src/Umbraco.Core/Persistence/NPocoSqlExtensions.cs @@ -1036,7 +1036,7 @@ namespace Umbraco.Core.Persistence { var pd = sql.SqlContext.PocoDataFactory.ForType(typeof (TDto)); var tableName = tableAlias ?? pd.TableInfo.TableName; - var queryColumns = pd.QueryColumns; + var queryColumns = pd.QueryColumns.ToList(); Dictionary aliases = null; @@ -1056,7 +1056,11 @@ namespace Umbraco.Core.Persistence return fieldName; }).ToArray(); - queryColumns = queryColumns.Where(x => names.Contains(x.Key)).ToArray(); + //only get the columns that exist in the selected names + queryColumns = queryColumns.Where(x => names.Contains(x.Key)).ToList(); + + //ensure the order of the columns in the expressions is the order in the result + queryColumns.Sort((a, b) => names.IndexOf(a.Key).CompareTo(names.IndexOf(b.Key))); } string GetAlias(PocoColumn column) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index 743b7c858e..13317e7b20 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -402,18 +402,44 @@ AND umbracoNode.id <> @id", propertyType.PropertyGroupId = new Lazy(() => groupId); } - //check if the content type variation has been changed to Nothing since we will need to update - //all property types to Nothing as well if they aren't already - //fixme: this does not take into account segments, but how can we since we don't know what it changed from? - var ctVariationChangedToNothing = entity.IsPropertyDirty("Variations") && entity.Variations == ContentVariation.Nothing; + //check if the content type variation has been changed + var ctVariationChanging = entity.IsPropertyDirty("Variations"); + if (ctVariationChanging) + { + //we've already looked up the previous version of the content type so we know it's previous variation state + MoveVariantData(entity, (ContentVariation)dtoPk.Variations, entity.Variations); + } + + //track any property types that are changing variation + var propertyTypeVariationChanges = new Dictionary(); // insert or update properties // all of them, no-group and in-groups foreach (var propertyType in entity.PropertyTypes) { - //fixme: this does not take into account segments, but how can we since we don't know what it changed from? - if (ctVariationChangedToNothing && propertyType.Variations != ContentVariation.Nothing) - propertyType.Variations = ContentVariation.Nothing; + //if the content type variation isn't changing track if any property type is changing + if (!ctVariationChanging) + { + if (propertyType.IsPropertyDirty("Variations")) + propertyTypeVariationChanges[propertyType.Id] = propertyType.Variations; + } + else + { + switch(entity.Variations) + { + case ContentVariation.Nothing: + //if the content type is changing to Nothing, then all property type's must change to nothing + propertyType.Variations = ContentVariation.Nothing; + break; + case ContentVariation.Culture: + //we don't need to modify the property type in this case + break; + case ContentVariation.CultureAndSegment: + case ContentVariation.Segment: + default: + throw new NotSupportedException(); //TODO: Support this + } + } var groupId = propertyType.PropertyGroupId?.Value ?? default(int); // if the Id of the DataType is not set, we resolve it from the db by its PropertyEditorAlias @@ -438,6 +464,27 @@ AND umbracoNode.id <> @id", orphanPropertyTypeIds.Remove(typeId); } + //check if any property types were changing variation + if (propertyTypeVariationChanges.Count > 0) + { + var changes = new Dictionary(); + + //now get the current property type variations for the changed ones so that we know which variation they + //are going from and to + var from = Database.Dictionary(Sql() + .Select(x => x.Id, x => x.Variations) + .From() + .WhereIn(x => x.Id, propertyTypeVariationChanges.Keys)); + + foreach(var f in from) + { + changes[f.Key] = (propertyTypeVariationChanges[f.Key], (ContentVariation)f.Value); + } + + //perform the move + MoveVariantData(changes); + } + // deal with orphan properties: those that were in a deleted tab, // and have not been re-mapped to another tab or to 'generic properties' if (orphanPropertyTypeIds != null) @@ -445,6 +492,130 @@ AND umbracoNode.id <> @id", DeletePropertyType(entity.Id, id); } + /// + /// Moves variant data for property type changes + /// + /// + private void MoveVariantData(IDictionary propertyTypeChanges) + { + var defaultLangId = Database.First(Sql().Select(x => x.Id).From().Where(x => x.IsDefaultVariantLanguage)); + + //Group by the "To" variation so we can bulk update in the correct batches + foreach(var g in propertyTypeChanges.GroupBy(x => x.Value.Item2)) + { + var propertyTypeIds = g.Select(s => s.Key).ToList(); + + //the ContentVariation that the data is moving "To" + var toVariantType = g.Key; + + switch(toVariantType) + { + case ContentVariation.Culture: + + MovePropertyDataToVariantCulture(defaultLangId, propertyTypeIds: propertyTypeIds); + + break; + case ContentVariation.Nothing: + + MovePropertyDataToVariantNothing(defaultLangId, propertyTypeIds: propertyTypeIds); + + break; + case ContentVariation.CultureAndSegment: + case ContentVariation.Segment: + default: + throw new NotSupportedException(); //TODO: Support this + } + } + } + + /// + /// Moves variant data for a content type variation change + /// + /// + /// + /// + private void MoveVariantData(IContentTypeComposition contentType, ContentVariation from, ContentVariation to) + { + var defaultLangId = Database.First(Sql().Select(x => x.Id).From().Where(x => x.IsDefaultVariantLanguage)); + + var sqlPropertyTypeIds = Sql().Select(x => x.Id).From().Where(x => x.ContentTypeId == contentType.Id); + switch (to) + { + case ContentVariation.Culture: + + MovePropertyDataToVariantCulture(defaultLangId, sqlPropertyTypeIds: sqlPropertyTypeIds); + + break; + case ContentVariation.Nothing: + + MovePropertyDataToVariantNothing(defaultLangId, sqlPropertyTypeIds: sqlPropertyTypeIds); + + break; + case ContentVariation.CultureAndSegment: + case ContentVariation.Segment: + default: + throw new NotSupportedException(); //TODO: Support this + } + } + + private void MovePropertyDataToVariantNothing(int defaultLangId, IReadOnlyCollection propertyTypeIds = null, Sql sqlPropertyTypeIds = null) + { + //first clear out any existing property data that might already exists under the default lang + var sqlDelete = Sql() + .Delete() + .Where(x => x.LanguageId == null); + if (sqlPropertyTypeIds != null) + sqlDelete.WhereIn(x => x.PropertyTypeId, sqlPropertyTypeIds); + if (propertyTypeIds != null) + sqlDelete.WhereIn(x => x.PropertyTypeId, propertyTypeIds); + + Database.Execute(sqlDelete); + + //now insert all property data into the default language that exists under the invariant lang + var cols = Sql().Columns(x => x.VersionId, x => x.PropertyTypeId, x => x.Segment, x => x.IntegerValue, x => x.DecimalValue, x => x.DateValue, x => x.VarcharValue, x => x.TextValue, x => x.LanguageId); + var sqlSelectData = Sql().Select(x => x.VersionId, x => x.PropertyTypeId, x => x.Segment, x => x.IntegerValue, x => x.DecimalValue, x => x.DateValue, x => x.VarcharValue, x => x.TextValue) + .Append(", NULL") //null language ID + .From() + .Where(x => x.LanguageId == defaultLangId); + if (sqlPropertyTypeIds != null) + sqlSelectData.WhereIn(x => x.PropertyTypeId, sqlPropertyTypeIds); + if (propertyTypeIds != null) + sqlSelectData.WhereIn(x => x.PropertyTypeId, propertyTypeIds); + + var sqlInsert = Sql($"INSERT INTO {PropertyDataDto.TableName} ({cols})").Append(sqlSelectData); + + Database.Execute(sqlInsert); + } + + private void MovePropertyDataToVariantCulture(int defaultLangId, IReadOnlyCollection propertyTypeIds = null, Sql sqlPropertyTypeIds = null) + { + //first clear out any existing property data that might already exists under the default lang + var sqlDelete = Sql() + .Delete() + .Where(x => x.LanguageId == defaultLangId); + if (sqlPropertyTypeIds != null) + sqlDelete.WhereIn(x => x.PropertyTypeId, sqlPropertyTypeIds); + if (propertyTypeIds != null) + sqlDelete.WhereIn(x => x.PropertyTypeId, propertyTypeIds); + + Database.Execute(sqlDelete); + + //now insert all property data into the default language that exists under the invariant lang + var cols = Sql().Columns(x => x.VersionId, x => x.PropertyTypeId, x => x.Segment, x => x.IntegerValue, x => x.DecimalValue, x => x.DateValue, x => x.VarcharValue, x => x.TextValue, x => x.LanguageId); + var sqlSelectData = Sql().Select(x => x.VersionId, x => x.PropertyTypeId, x => x.Segment, x => x.IntegerValue, x => x.DecimalValue, x => x.DateValue, x => x.VarcharValue, x => x.TextValue) + .Append($", {defaultLangId}") //default language ID + .From() + .Where(x => x.LanguageId == null); + if (sqlPropertyTypeIds != null) + sqlSelectData.WhereIn(x => x.PropertyTypeId, sqlPropertyTypeIds); + if (propertyTypeIds != null) + sqlSelectData.WhereIn(x => x.PropertyTypeId, propertyTypeIds); + + var sqlInsert = Sql($"INSERT INTO {PropertyDataDto.TableName} ({cols})").Append(sqlSelectData); + + Database.Execute(sqlInsert); + } + private void DeletePropertyType(int contentTypeId, int propertyTypeId) { // first clear dependencies diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 379d5ad48a..496a66137a 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -170,7 +170,6 @@ - diff --git a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs index ad16f4228a..5b4dcceb00 100644 --- a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs @@ -30,10 +30,6 @@ namespace Umbraco.Tests.Services [Test] public void Change_Content_Type_From_Variant_Invariant() { - //initialize the listener which is responsible for updating content based on variant/invariant changes - var listener = new UpdateContentOnVariantChangesComponent(); - listener.Initialize(ServiceContext.ContentService, ServiceContext.LocalizationService); - //create content type with a property type that varies by culture var contentType = MockedContentTypes.CreateBasicContentType(); contentType.Variations = ContentVariation.Culture; @@ -72,16 +68,23 @@ namespace Umbraco.Tests.Services ServiceContext.ContentTypeService.Save(contentType); doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + //at this stage all property types were switched to invariant so even though the variant value + //exists it will not be returned because the property type is invariant, + //so this check proves that null will be returned + Assert.IsNull(doc.GetValue("title", "en-US")); + + //we can now switch the property type to be variant and the value can be returned again + contentType.PropertyTypes.First().Variations = ContentVariation.Culture; + ServiceContext.ContentTypeService.Save(contentType); + doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + Assert.AreEqual("hello world", doc.GetValue("title", "en-US")); + } [Test] public void Change_Property_Type_From_Invariant_Variant() { - //initialize the listener which is responsible for updating content based on variant/invariant changes - var listener = new UpdateContentOnVariantChangesComponent(); - listener.Initialize(ServiceContext.ContentService, ServiceContext.LocalizationService); - //create content type with a property type that varies by culture var contentType = MockedContentTypes.CreateBasicContentType(); contentType.Variations = ContentVariation.Culture; @@ -126,10 +129,6 @@ namespace Umbraco.Tests.Services [Test] public void Change_Property_Type_From_Variant_Invariant() { - //initialize the listener which is responsible for updating content based on variant/invariant changes - var listener = new UpdateContentOnVariantChangesComponent(); - listener.Initialize(ServiceContext.ContentService, ServiceContext.LocalizationService); - //create content type with a property type that varies by culture var contentType = MockedContentTypes.CreateBasicContentType(); contentType.Variations = ContentVariation.Culture; From 8f9db821593c91dbc1e2a8c114527a826b7c17af Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 4 Oct 2018 14:21:30 +0200 Subject: [PATCH 08/44] clean up states when dialog closes, prevent dialog from closing then date picker is open, wip support for invariant content --- .../overlays/umboverlay.directive.js | 6 + .../components/overlays/umb-overlay.html | 2 +- .../content/overlays/schedule.controller.js | 53 ++-- .../src/views/content/overlays/schedule.html | 242 ++++++++++++------ 4 files changed, 201 insertions(+), 102 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/overlays/umboverlay.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/overlays/umboverlay.directive.js index 6655bef4ca..07cfbb9848 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/overlays/umboverlay.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/overlays/umboverlay.directive.js @@ -700,6 +700,12 @@ Opens an overlay to show a custom YSOD.
}; + scope.outSideClick = function() { + if(!scope.model.disableBackdropClick) { + scope.closeOverLay(); + } + }; + unsubscribe.push(unregisterOverlay); scope.$on('$destroy', function () { for (var i = 0; i < unsubscribe.length; i++) { diff --git a/src/Umbraco.Web.UI.Client/src/views/components/overlays/umb-overlay.html b/src/Umbraco.Web.UI.Client/src/views/components/overlays/umb-overlay.html index feacf3adf8..40b0e181bf 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/overlays/umb-overlay.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/overlays/umb-overlay.html @@ -1,4 +1,4 @@ -
+
diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js index fa835341e2..1aad7cf07b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js @@ -1,17 +1,20 @@ (function () { "use strict"; - function ScheduleContentController($scope, localizationService, dateHelper, userService) { + function ScheduleContentController($scope, $timeout, localizationService, dateHelper, userService) { var vm = this; vm.datePickerChange = datePickerChange; + vm.datePickerShow = datePickerShow; + vm.datePickerClose = datePickerClose; vm.clearPublishDate = clearPublishDate; vm.clearUnpublishDate = clearUnpublishDate; vm.dirtyVariantFilter = dirtyVariantFilter; vm.pristineVariantFilter = pristineVariantFilter; vm.changeSelection = changeSelection; + vm.firstSelectedDates = {}; vm.currentUser = null; vm.datePickerConfig = { pickDate: true, @@ -37,18 +40,21 @@ }); } - _.each(vm.variants, - function (variant) { - variant.compositeId = variant.language.culture + "_" + (variant.segment ? variant.segment : ""); - variant.htmlId = "_content_variant_" + variant.compositeId; + // Check for variants: if a node is invariant it will still have the default language in variants + // so we have to check for length > 1 + if (vm.variants.length > 1) { - //check for pristine variants - if (!vm.hasPristineVariants) { - vm.hasPristineVariants = pristineVariantFilter(variant); - } - }); + _.each(vm.variants, + function (variant) { + variant.compositeId = variant.language.culture + "_" + (variant.segment ? variant.segment : ""); + variant.htmlId = "_content_variant_" + variant.compositeId; + + //check for pristine variants + if (!vm.hasPristineVariants) { + vm.hasPristineVariants = pristineVariantFilter(variant); + } + }); - if (vm.variants.length !== 0) { //now sort it so that the current one is at the top vm.variants = _.sortBy(vm.variants, function (v) { return v.active ? 0 : 1; @@ -64,11 +70,8 @@ active.save = true; } - //$scope.model.disableSubmitButton = !canPublish(); - - } else { - //disable Publish button if we have nothing to publish, should not happen - //$scope.model.disableSubmitButton = true; + $scope.model.disableSubmitButton = !canSchedule(); + } // get current backoffice user and format dates @@ -95,6 +98,16 @@ } } + function datePickerShow() { + $scope.model.disableBackdropClick = true; + } + + function datePickerClose() { + $timeout(function(){ + $scope.model.disableBackdropClick = false; + }); + } + function setPublishDate(variant, date) { if (!date) { @@ -111,6 +124,8 @@ // make sure dates are formatted to the user's locale formatDatesToLocal(variant); + // store the first selected date so we can apply to other selected variants + } function setUnpublishDate(variant, date) { @@ -202,10 +217,14 @@ onInit(); - //when this dialog is closed, reset all 'save' flags + //when this dialog is closed, clean up $scope.$on('$destroy', function () { for (var i = 0; i < vm.variants.length; i++) { vm.variants[i].schedule = false; + vm.variants[i].releaseDate = null; + vm.variants[i].releaseDateFormatted = null; + vm.variants[i].removeDate = null; + vm.variants[i].releaseDateFormatted = null; vm.variants[i].save = false; } }); diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html index b12b697552..2547eec32b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html @@ -1,103 +1,177 @@
-
-

-
+ +
-
+
+

+
-
- -
- -
- - +
-
- - - -
- -
-
Publish:
- -
- - -
- {{variant.releaseDateFormatted}} -
- - - Set date - - -
- - - - -
- -
Unpublish:
- -
- - -
- {{variant.removeDateFormatted}} -
- - - Set date - - -
- - - - -
- -
+
+ +
+ +
+ +
+ {{vm.variants[0].releaseDateFormatted}}
-
- + + Set date + + + + + + + +
+ +
+ +
+ +
+ + +
+ {{vm.variants[0].removeDateFormatted}} +
+ + + Set date + + +
+ + + + +
+
-
+
-
-
-

+ +
+ +
+

-
-
-
- {{ variant.language.name }} -
-
- - - +
+ +
+ +
+ +
+ + + +
+ + - +
+ +
+
Publish:
+ +
+ + +
+ {{variant.releaseDateFormatted}} +
+ + + Set date + + +
+ + + + +
+ +
Unpublish:
+ +
+ + +
+ {{variant.removeDateFormatted}} +
+ + + Set date + + +
+ + + + +
+ +
+ +
+
+ +
+
+
+
+ +
+
+

+
+ +
+
+
+ {{ variant.language.name }} +
+
+ + - +
+
\ No newline at end of file From 1c5547e594f5b42ee132484186f89acf600dab0d Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 4 Oct 2018 15:23:38 +0200 Subject: [PATCH 09/44] add better styling for scheduling of invariant content --- .../src/less/properties.less | 37 +++----- .../src/views/content/overlays/schedule.html | 91 ++++++++++--------- 2 files changed, 61 insertions(+), 67 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/properties.less b/src/Umbraco.Web.UI.Client/src/less/properties.less index 06f05ab0aa..2e700dd77a 100644 --- a/src/Umbraco.Web.UI.Client/src/less/properties.less +++ b/src/Umbraco.Web.UI.Client/src/less/properties.less @@ -1,23 +1,21 @@ //----- SCHEDULED PUBLISH ------ -.place-holder { - height: 60px; - width: 60px; - margin: 15px auto; - background-color: @gray-8; -} - .date-wrapper { display: flex; - justify-content: space-around; flex-direction: row; + border-top: 1px solid @gray-10; + border-bottom: 1px solid @gray-10; +} + +.date-wrapper__date { + padding: 10px; } .date-container { text-align: center; } -.date-wrapper__number{ +.date-wrapper__number { font-size: 40px; line-height: 50px; color: @gray-2; @@ -31,21 +29,21 @@ margin-bottom: 5px; } -.date-container__date { - padding: 0 10px; -} .date-container__date:hover { background-color: @gray-10; cursor: pointer; } -.date-wrapper__date{ - font-size: 13px; - color: @gray-6; - margin: 0; +.date-wrapper__date { + padding: 10px; + flex: 1 1 50%; } -.data-wrapper__add{ +.date-wrapper__date:last-of-type { + border-left: 1px solid @gray-10; +} + +.data-wrapper__add { font-size: 18px; line-height: 10px; color: @gray-8; @@ -53,11 +51,6 @@ margin: 0; } -.date-separate { - width: 1px; - background-color: @gray-8; -} - //------------------- HISTORY ------------------ .history { diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html index 2547eec32b..1a170b9d75 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html @@ -7,62 +7,63 @@

-
+
+
+ + +
+ -
- -
- -
- +
+ {{vm.variants[0].releaseDateFormatted}} +
-
- {{vm.variants[0].releaseDateFormatted}} -
+ + Set date + - - Set date +
+ + + - - - - - - +
-
- -
+
+ -
- +
+ -
- {{vm.variants[0].removeDateFormatted}} -
- - - Set date +
+ {{vm.variants[0].removeDateFormatted}} +
+ +
+ Set date + + +
+ + + - - - - - - +
-
-
From 5b6c6c0cd1462a9954c2e041561487dce0cc390b Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 4 Oct 2018 15:37:59 +0200 Subject: [PATCH 10/44] remove schedule publish box from info app --- .../content/umbcontentnodeinfo.directive.js | 111 ------------------ .../content/umb-content-node-info.html | 73 +----------- 2 files changed, 1 insertion(+), 183 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js index 4831ecea8c..2126e80c20 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js @@ -69,9 +69,6 @@ // get document type details scope.documentType = scope.node.documentType; - // make sure dates are formatted to the user's locale - formatDatesToLocal(); - //default setting for redirect url management scope.urlTrackerDisabled = false; @@ -117,22 +114,6 @@ scope.node.template = templateAlias; }; - scope.datePickerChange = function (event, type) { - if (type === 'publish') { - setPublishDate(event.date.format("YYYY-MM-DD HH:mm")); - } else if (type === 'unpublish') { - setUnpublishDate(event.date.format("YYYY-MM-DD HH:mm")); - } - }; - - scope.clearPublishDate = function () { - clearPublishDate(); - }; - - scope.clearUnpublishDate = function () { - clearUnpublishDate(); - }; - function loadAuditTrail() { scope.loadingAuditTrail = true; @@ -243,97 +224,6 @@ } } - function setPublishDate(date) { - - if (!date) { - return; - } - - //The date being passed in here is the user's local date/time that they have selected - //we need to convert this date back to the server date on the model. - - var serverTime = dateHelper.convertToServerStringTime(moment(date), Umbraco.Sys.ServerVariables.application.serverTimeOffset); - - // update publish value - scope.node.releaseDate = serverTime; - - // make sure dates are formatted to the user's locale - formatDatesToLocal(); - - // emit event - var args = { node: scope.node, date: date }; - eventsService.emit("editors.content.changePublishDate", args); - - } - - function clearPublishDate() { - - // update publish value - scope.node.releaseDate = null; - - // emit event - var args = { node: scope.node, date: null }; - eventsService.emit("editors.content.changePublishDate", args); - - } - - function setUnpublishDate(date) { - - if (!date) { - return; - } - - //The date being passed in here is the user's local date/time that they have selected - //we need to convert this date back to the server date on the model. - - var serverTime = dateHelper.convertToServerStringTime(moment(date), Umbraco.Sys.ServerVariables.application.serverTimeOffset); - - // update publish value - scope.node.removeDate = serverTime; - - // make sure dates are formatted to the user's locale - formatDatesToLocal(); - - // emit event - var args = { node: scope.node, date: date }; - eventsService.emit("editors.content.changeUnpublishDate", args); - - } - - function clearUnpublishDate() { - - // update publish value - scope.node.removeDate = null; - - // emit event - var args = { node: scope.node, date: null }; - eventsService.emit("editors.content.changeUnpublishDate", args); - - } - - function ucfirst(string) { - return string.charAt(0).toUpperCase() + string.slice(1); - } - - function formatDatesToLocal() { - // get current backoffice user and format dates - userService.getCurrentUser().then(function (currentUser) { - scope.node.createDateFormatted = dateHelper.getLocalDate(scope.node.createDate, currentUser.locale, 'LLL'); - - scope.node.releaseDateYear = scope.node.releaseDate ? ucfirst(dateHelper.getLocalDate(scope.node.releaseDate, currentUser.locale, 'YYYY')) : null; - scope.node.releaseDateMonth = scope.node.releaseDate ? ucfirst(dateHelper.getLocalDate(scope.node.releaseDate, currentUser.locale, 'MMMM')) : null; - scope.node.releaseDateDayNumber = scope.node.releaseDate ? ucfirst(dateHelper.getLocalDate(scope.node.releaseDate, currentUser.locale, 'DD')) : null; - scope.node.releaseDateDay = scope.node.releaseDate ? ucfirst(dateHelper.getLocalDate(scope.node.releaseDate, currentUser.locale, 'dddd')) : null; - scope.node.releaseDateTime = scope.node.releaseDate ? ucfirst(dateHelper.getLocalDate(scope.node.releaseDate, currentUser.locale, 'HH:mm')) : null; - - scope.node.removeDateYear = scope.node.removeDate ? ucfirst(dateHelper.getLocalDate(scope.node.removeDate, currentUser.locale, 'YYYY')) : null; - scope.node.removeDateMonth = scope.node.removeDate ? ucfirst(dateHelper.getLocalDate(scope.node.removeDate, currentUser.locale, 'MMMM')) : null; - scope.node.removeDateDayNumber = scope.node.removeDate ? ucfirst(dateHelper.getLocalDate(scope.node.removeDate, currentUser.locale, 'DD')) : null; - scope.node.removeDateDay = scope.node.removeDate ? ucfirst(dateHelper.getLocalDate(scope.node.removeDate, currentUser.locale, 'dddd')) : null; - scope.node.removeDateTime = scope.node.removeDate ? ucfirst(dateHelper.getLocalDate(scope.node.removeDate, currentUser.locale, 'HH:mm')) : null; - }); - } - // load audit trail and redirects when on the info tab evts.push(eventsService.on("app.tabChange", function (event, args) { $timeout(function () { @@ -356,7 +246,6 @@ if(isInfoTab) { loadAuditTrail(); loadRedirectUrls(); - formatDatesToLocal(); setNodePublishStatus(scope.node); } }); diff --git a/src/Umbraco.Web.UI.Client/src/views/components/content/umb-content-node-info.html b/src/Umbraco.Web.UI.Client/src/views/components/content/umb-content-node-info.html index c2e5df6f30..03d4318ba2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/content/umb-content-node-info.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/content/umb-content-node-info.html @@ -112,78 +112,7 @@
- - - - -
- -
- - - - -
- -
- -
- -
-
{{node.releaseDateMonth}} {{node.releaseDateYear}}
-
{{node.releaseDateDayNumber}}
-
{{node.releaseDateDay}} {{node.releaseDateTime}}
-
- - Set date - -
- -
- - - Clear date - - -
- -
- -
- - -
- -
- -
- -
-
{{node.removeDateMonth}} {{node.removeDateYear}}
-
{{node.removeDateDayNumber}}
-
{{node.removeDateDay}} {{node.removeDateTime}}
-
- - Set date - -
- -
- - - Clear date - -
- -
- - -
-
+ From 99e7fb008e464b1ca55c169afa94cbc59a96a087 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 4 Oct 2018 16:03:13 +0200 Subject: [PATCH 11/44] remove unused styles --- .../src/less/properties.less | 35 ------------------- 1 file changed, 35 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/properties.less b/src/Umbraco.Web.UI.Client/src/less/properties.less index 2e700dd77a..916f1b5a3a 100644 --- a/src/Umbraco.Web.UI.Client/src/less/properties.less +++ b/src/Umbraco.Web.UI.Client/src/less/properties.less @@ -7,33 +7,6 @@ border-bottom: 1px solid @gray-10; } -.date-wrapper__date { - padding: 10px; -} - -.date-container { - text-align: center; -} - -.date-wrapper__number { - font-size: 40px; - line-height: 50px; - color: @gray-2; - font-weight: 900; -} - -.date-container__title { - font-size: 16px; - font-weight: bold; - color: @gray-3; - margin-bottom: 5px; -} - -.date-container__date:hover { - background-color: @gray-10; - cursor: pointer; -} - .date-wrapper__date { padding: 10px; flex: 1 1 50%; @@ -43,14 +16,6 @@ border-left: 1px solid @gray-10; } -.data-wrapper__add { - font-size: 18px; - line-height: 10px; - color: @gray-8; - font-weight: 900; - margin: 0; -} - //------------------- HISTORY ------------------ .history { From 01bb00a8ec32c35520c1ac44e2ce0615f42374f6 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 4 Oct 2018 16:04:14 +0200 Subject: [PATCH 12/44] better date formatting --- .../src/views/content/overlays/schedule.controller.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js index 1aad7cf07b..7974103b7a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js @@ -99,11 +99,13 @@ } function datePickerShow() { + // prevent the overlay from closing when the date picker is open $scope.model.disableBackdropClick = true; } function datePickerClose() { $timeout(function(){ + // allow the date picker to close now the date picker is closed $scope.model.disableBackdropClick = false; }); } @@ -159,15 +161,12 @@ } function formatDatesToLocal(variant) { - if(variant && variant.releaseDate) { - variant.releaseDateFormatted = dateHelper.getLocalDate(variant.releaseDate, vm.currentUser.locale, "YYYY-MM-DD HH:mm"); + variant.releaseDateFormatted = dateHelper.getLocalDate(variant.releaseDate, vm.currentUser.locale, "MMM Do YYYY, HH:mm"); } - if(variant && variant.removeDate) { - variant.removeDateFormatted = dateHelper.getLocalDate(variant.removeDate, vm.currentUser.locale, "YYYY-MM-DD HH:mm"); + variant.removeDateFormatted = dateHelper.getLocalDate(variant.removeDate, vm.currentUser.locale, "MMM Do YYYY, HH:mm"); } - } function changeSelection(variant) { From c5ae149d4054268d58971a80debfaf45ba878652 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 4 Oct 2018 16:27:41 +0200 Subject: [PATCH 13/44] Gets remaining tests in place along with moving name values --- .../Implement/ContentTypeRepositoryBase.cs | 91 ++++++++++++++++++- .../Implement/LanguageRepository.cs | 5 + .../Services/ContentTypeServiceTests.cs | 72 +++++++++++++-- 3 files changed, 154 insertions(+), 14 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index 13317e7b20..eed7b5a071 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -511,14 +511,10 @@ AND umbracoNode.id <> @id", switch(toVariantType) { case ContentVariation.Culture: - MovePropertyDataToVariantCulture(defaultLangId, propertyTypeIds: propertyTypeIds); - break; case ContentVariation.Nothing: - MovePropertyDataToVariantNothing(defaultLangId, propertyTypeIds: propertyTypeIds); - break; case ContentVariation.CultureAndSegment: case ContentVariation.Segment: @@ -542,14 +538,89 @@ AND umbracoNode.id <> @id", switch (to) { case ContentVariation.Culture: + //move the property data MovePropertyDataToVariantCulture(defaultLangId, sqlPropertyTypeIds: sqlPropertyTypeIds); + //now we need to move the names + //first clear out any existing names that might already exists under the default lang + //there's 2x tables to update + + //clear out the versionCultureVariation table + var sqlSelect = Sql().Select(x => x.Id) + .From() + .InnerJoin().On(x => x.Id, x => x.VersionId) + .InnerJoin().On(x => x.NodeId, x => x.NodeId) + .Where(x => x.ContentTypeId == contentType.Id) + .Where(x => x.LanguageId == defaultLangId); + var sqlDelete = Sql() + .Delete() + .WhereIn(x => x.Id, sqlSelect); + Database.Execute(sqlDelete); + + //clear out the documentCultureVariation table + sqlSelect = Sql().Select(x => x.Id) + .From() + .InnerJoin().On(x => x.NodeId, x => x.NodeId) + .Where(x => x.ContentTypeId == contentType.Id) + .Where(x => x.LanguageId == defaultLangId); + sqlDelete = Sql() + .Delete() + .WhereIn(x => x.Id, sqlSelect); + Database.Execute(sqlDelete); + + //now we need to insert names into these 2 tables based on the invariant data + + //insert rows into the versionCultureVariationDto table based on the data from contentVersionDto for the default lang + var cols = Sql().Columns(x => x.VersionId, x => x.Name, x => x.UpdateUserId, x => x.UpdateDate, x => x.LanguageId); + sqlSelect = Sql().Select(x => x.Id, x => x.Text, x => x.UserId, x => x.VersionDate) + .Append($", {defaultLangId}") //default language ID + .From() + .InnerJoin().On(x => x.NodeId, x => x.NodeId) + .Where(x => x.ContentTypeId == contentType.Id); + var sqlInsert = Sql($"INSERT INTO {ContentVersionCultureVariationDto.TableName} ({cols})").Append(sqlSelect); + Database.Execute(sqlInsert); + + //insert rows into the documentCultureVariation table + cols = Sql().Columns(x => x.NodeId, x => x.Edited, x => x.Published, x => x.Name, x => x.Available, x => x.LanguageId); + sqlSelect = Sql().Select(x => x.NodeId, x => x.Edited, x => x.Published) + .AndSelect(x => x.Text) + .Append($", 1, {defaultLangId}") //make Available + default language ID + .From() + .InnerJoin().On(x => x.NodeId, x => x.NodeId) + .InnerJoin().On(x => x.NodeId, x => x.NodeId) + .Where(x => x.ContentTypeId == contentType.Id); + sqlInsert = Sql($"INSERT INTO {DocumentCultureVariationDto.TableName} ({cols})").Append(sqlSelect); + Database.Execute(sqlInsert); + break; case ContentVariation.Nothing: + //move the property data MovePropertyDataToVariantNothing(defaultLangId, sqlPropertyTypeIds: sqlPropertyTypeIds); + //we dont need to move the names! this is because we always keep the invariant names with the name of the default language. + + //however, if we were to move names, we could do this: BUT this doesn't work with SQLCE, for that we'd have to update row by row :( + + ////now we need to move the names + + ////first update umbracoNode from documentCultureVariation + //var sqlUpdate = Sql($"UPDATE {NodeDto.TableName} SET {Sql().Columns(x => x.Text)} = {Sql().Columns(x => x.Name)}") + // .From() + // .InnerJoin().On(x => x.NodeId, x => x.NodeId) + // .InnerJoin().On(x => x.NodeId, x => x.NodeId) + // .Where(x => x.ContentTypeId == contentType.Id); + //Database.Execute(sqlUpdate); + + ////next update umbracoContentVersion from contentVersionCultureVariation + //sqlUpdate = Sql($"UPDATE {ContentVersionDto.TableName} SET {Sql().Columns(x => x.Text)} = {Sql().Columns(x => x.Name)}") + // .From() + // .InnerJoin().On(x => x.VersionId, x => x.Id) + // .InnerJoin().On(x => x.NodeId, x => x.NodeId) + // .Where(x => x.ContentTypeId == contentType.Id); + //Database.Execute(sqlUpdate); + break; case ContentVariation.CultureAndSegment: case ContentVariation.Segment: @@ -558,6 +629,12 @@ AND umbracoNode.id <> @id", } } + /// + /// This will move all property data from variant to invariant + /// + /// + /// Optional list of property type ids of the properties to be updated + /// Optional SQL statement used for the sub-query to select the properties type ids for the properties to be updated private void MovePropertyDataToVariantNothing(int defaultLangId, IReadOnlyCollection propertyTypeIds = null, Sql sqlPropertyTypeIds = null) { //first clear out any existing property data that might already exists under the default lang @@ -587,6 +664,12 @@ AND umbracoNode.id <> @id", Database.Execute(sqlInsert); } + /// + /// This will move all property data from invariant to variant + /// + /// + /// Optional list of property type ids of the properties to be updated + /// Optional SQL statement used for the sub-query to select the properties type ids for the properties to be updated private void MovePropertyDataToVariantCulture(int defaultLangId, IReadOnlyCollection propertyTypeIds = null, Sql sqlPropertyTypeIds = null) { //first clear out any existing property data that might already exists under the default lang diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs index 2026daba74..8a0ba73f85 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs @@ -219,6 +219,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement if (TypedCachePolicy != null) TypedCachePolicy.GetAllCached(PerformGetAll); + var id = GetIdByIsoCode(isoCode, throwOnNotFound: false); return id.HasValue ? Get(id.Value) : null; } @@ -234,6 +235,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement // ensure cache is populated, in a non-expensive way if (TypedCachePolicy != null) TypedCachePolicy.GetAllCached(PerformGetAll); + else + PerformGetAll(); //we don't have a typed cache (i.e. unit tests) but need to populate the _codeIdMap lock (_codeIdMap) { @@ -255,6 +258,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement // ensure cache is populated, in a non-expensive way if (TypedCachePolicy != null) TypedCachePolicy.GetAllCached(PerformGetAll); + else + PerformGetAll(); lock (_codeIdMap) // yes, we want to lock _codeIdMap { diff --git a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs index 5b4dcceb00..892166e566 100644 --- a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs @@ -25,7 +25,55 @@ namespace Umbraco.Tests.Services public class ContentTypeServiceTests : TestWithSomeContentBase { - //TODO: Then write the ones for content type changes + [Test] + public void Change_Content_Type_From_Invariant_Variant() + { + //create content type with a property type that varies by culture + var contentType = MockedContentTypes.CreateBasicContentType(); + contentType.Variations = ContentVariation.Nothing; + var contentCollection = new PropertyTypeCollection(true); + contentCollection.Add(new PropertyType("test", ValueStorageType.Ntext) + { + Alias = "title", + Name = "Title", + Description = "", + Mandatory = false, + SortOrder = 1, + DataTypeId = -88, + Variations = ContentVariation.Nothing + }); + contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 }); + ServiceContext.ContentTypeService.Save(contentType); + + //create some content of this content type + IContent doc = MockedContent.CreateBasicContent(contentType); + doc.Name = "Hello1"; + doc.SetValue("title", "hello world"); + ServiceContext.ContentService.Save(doc); + + Assert.AreEqual("Hello1", doc.Name); + Assert.AreEqual("hello world", doc.GetValue("title")); + + //change the content type to be variant, we will also update the name here to detect the copy changes + doc.Name = "Hello2"; + ServiceContext.ContentService.Save(doc); + contentType.Variations = ContentVariation.Culture; + ServiceContext.ContentTypeService.Save(contentType); + doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + + Assert.AreEqual("Hello2", doc.GetCultureName("en-US")); + Assert.AreEqual("hello world", doc.GetValue("title")); //We are not checking against en-US here because properties will remain invariant + + //change back property type to be invariant, we will also update the name here to detect the copy changes + doc.SetCultureName("Hello3", "en-US"); + ServiceContext.ContentService.Save(doc); + contentType.Variations = ContentVariation.Nothing; + ServiceContext.ContentTypeService.Save(contentType); + doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + + Assert.AreEqual("Hello3", doc.Name); + Assert.AreEqual("hello world", doc.GetValue("title")); + } [Test] public void Change_Content_Type_From_Variant_Invariant() @@ -45,25 +93,30 @@ namespace Umbraco.Tests.Services Variations = ContentVariation.Culture }); contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 }); - contentType.ResetDirtyProperties(false); ServiceContext.ContentTypeService.Save(contentType); //create some content of this content type IContent doc = MockedContent.CreateBasicContent(contentType); - doc.SetCultureName("Home", "en-US"); + doc.SetCultureName("Hello1", "en-US"); doc.SetValue("title", "hello world", "en-US"); ServiceContext.ContentService.Save(doc); + Assert.AreEqual("Hello1", doc.GetCultureName("en-US")); Assert.AreEqual("hello world", doc.GetValue("title", "en-US")); - //change the content type to be invariant - contentType.Variations = ContentVariation.Nothing; + //change the content type to be invariant, we will also update the name here to detect the copy changes + doc.SetCultureName("Hello2", "en-US"); + ServiceContext.ContentService.Save(doc); + contentType.Variations = ContentVariation.Nothing; ServiceContext.ContentTypeService.Save(contentType); doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + Assert.AreEqual("Hello2", doc.Name); Assert.AreEqual("hello world", doc.GetValue("title")); - //change back property type to be variant + //change back property type to be variant, we will also update the name here to detect the copy changes + doc.Name = "Hello3"; + ServiceContext.ContentService.Save(doc); contentType.Variations = ContentVariation.Culture; ServiceContext.ContentTypeService.Save(contentType); doc = ServiceContext.ContentService.GetById(doc.Id); //re-get @@ -78,6 +131,7 @@ namespace Umbraco.Tests.Services ServiceContext.ContentTypeService.Save(contentType); doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + Assert.AreEqual("Hello3", doc.GetCultureName("en-US")); Assert.AreEqual("hello world", doc.GetValue("title", "en-US")); } @@ -87,7 +141,7 @@ namespace Umbraco.Tests.Services { //create content type with a property type that varies by culture var contentType = MockedContentTypes.CreateBasicContentType(); - contentType.Variations = ContentVariation.Culture; + contentType.Variations = ContentVariation.Nothing; var contentCollection = new PropertyTypeCollection(true); contentCollection.Add(new PropertyType("test", ValueStorageType.Ntext) { @@ -100,12 +154,11 @@ namespace Umbraco.Tests.Services Variations = ContentVariation.Nothing }); contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 }); - contentType.ResetDirtyProperties(false); ServiceContext.ContentTypeService.Save(contentType); //create some content of this content type IContent doc = MockedContent.CreateBasicContent(contentType); - doc.SetCultureName("Home", "en-US"); + doc.Name = "Home"; doc.SetValue("title", "hello world"); ServiceContext.ContentService.Save(doc); @@ -144,7 +197,6 @@ namespace Umbraco.Tests.Services Variations = ContentVariation.Culture }); contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 }); - contentType.ResetDirtyProperties(false); ServiceContext.ContentTypeService.Save(contentType); //create some content of this content type From 304c874006f35634101b81e024ee08372237411a Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 4 Oct 2018 16:36:19 +0200 Subject: [PATCH 14/44] removes comments --- .../Implement/ContentTypeRepositoryBase.cs | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index eed7b5a071..93f8b123f7 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -602,24 +602,7 @@ AND umbracoNode.id <> @id", //we dont need to move the names! this is because we always keep the invariant names with the name of the default language. //however, if we were to move names, we could do this: BUT this doesn't work with SQLCE, for that we'd have to update row by row :( - - ////now we need to move the names - - ////first update umbracoNode from documentCultureVariation - //var sqlUpdate = Sql($"UPDATE {NodeDto.TableName} SET {Sql().Columns(x => x.Text)} = {Sql().Columns(x => x.Name)}") - // .From() - // .InnerJoin().On(x => x.NodeId, x => x.NodeId) - // .InnerJoin().On(x => x.NodeId, x => x.NodeId) - // .Where(x => x.ContentTypeId == contentType.Id); - //Database.Execute(sqlUpdate); - - ////next update umbracoContentVersion from contentVersionCultureVariation - //sqlUpdate = Sql($"UPDATE {ContentVersionDto.TableName} SET {Sql().Columns(x => x.Text)} = {Sql().Columns(x => x.Name)}") - // .From() - // .InnerJoin().On(x => x.VersionId, x => x.Id) - // .InnerJoin().On(x => x.NodeId, x => x.NodeId) - // .Where(x => x.ContentTypeId == contentType.Id); - //Database.Execute(sqlUpdate); + // if we want these SQL statements back, look into GIT history break; case ContentVariation.CultureAndSegment: From 0ae1d06c2d6212a9dde15b482bc3bd8f5a8b18d6 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 4 Oct 2018 16:39:31 +0200 Subject: [PATCH 15/44] fix merge --- .../Repositories/Implement/ContentTypeRepositoryBase.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index 93f8b123f7..19f3623680 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -498,7 +498,7 @@ AND umbracoNode.id <> @id", /// private void MoveVariantData(IDictionary propertyTypeChanges) { - var defaultLangId = Database.First(Sql().Select(x => x.Id).From().Where(x => x.IsDefaultVariantLanguage)); + var defaultLangId = Database.First(Sql().Select(x => x.Id).From().Where(x => x.IsDefault)); //Group by the "To" variation so we can bulk update in the correct batches foreach(var g in propertyTypeChanges.GroupBy(x => x.Value.Item2)) @@ -532,7 +532,7 @@ AND umbracoNode.id <> @id", /// private void MoveVariantData(IContentTypeComposition contentType, ContentVariation from, ContentVariation to) { - var defaultLangId = Database.First(Sql().Select(x => x.Id).From().Where(x => x.IsDefaultVariantLanguage)); + var defaultLangId = Database.First(Sql().Select(x => x.Id).From().Where(x => x.IsDefault)); var sqlPropertyTypeIds = Sql().Select(x => x.Id).From().Where(x => x.ContentTypeId == contentType.Id); switch (to) From 7d56ebf6624c6240c4a85c1f5d54492813295ff5 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 4 Oct 2018 20:21:13 +0200 Subject: [PATCH 16/44] fix width of date picker --- src/Umbraco.Web.UI.Client/src/less/main.less | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/src/less/main.less b/src/Umbraco.Web.UI.Client/src/less/main.less index 6d567c5fb3..0284a79865 100644 --- a/src/Umbraco.Web.UI.Client/src/less/main.less +++ b/src/Umbraco.Web.UI.Client/src/less/main.less @@ -48,6 +48,7 @@ h5.-black { border: none } .bootstrap-datetimepicker-widget { + width: auto !important; td { &.active, span.active { background: @turquoise !important; From a1abe568ce8d83fc4a1584b0782b09cdeb3456cd Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 4 Oct 2018 21:01:47 +0200 Subject: [PATCH 17/44] clean up --- .../content/umbcontentnodeinfo.directive.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js index 2126e80c20..b2e64983d6 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/umbcontentnodeinfo.directive.js @@ -46,19 +46,6 @@ }); - scope.datePickerConfig = { - pickDate: true, - pickTime: true, - useSeconds: false, - format: "YYYY-MM-DD HH:mm", - icons: { - time: "icon-time", - date: "icon-calendar", - up: "icon-chevron-up", - down: "icon-chevron-down" - } - }; - scope.auditTrailOptions = { "id": scope.node.id }; From 41aa6e680e88079990c786a2fbc0b1c48bd23c99 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 5 Oct 2018 09:54:57 +0200 Subject: [PATCH 18/44] schedule button should always show an ellipsis because it always opens a dialog --- .../src/common/services/contenteditinghelper.service.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js index 70deafdeb9..5e9509977b 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js @@ -198,7 +198,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica labelKey: "buttons_schedulePublish", handler: args.methods.schedulePublish, alias: "schedulePublish", - addEllipsis: args.content.variants && args.content.variants.length > 1 ? "true" : "false" + addEllipsis: "true" }; default: return null; From 8eac3c58946e97a6b770f34bec7816887203bd9e Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 5 Oct 2018 11:15:21 +0200 Subject: [PATCH 19/44] clean up old schedule publshing button code --- .../components/content/edit.controller.js | 8 ----- .../services/contenteditinghelper.service.js | 34 ------------------- 2 files changed, 42 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js index 456673b6b9..71d7da32eb 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/content/edit.controller.js @@ -97,14 +97,6 @@ eventsService.unsubscribe(evts[e]); } - evts.push(eventsService.on("editors.content.changePublishDate", function (event, args) { - createButtons(args.node); - })); - - evts.push(eventsService.on("editors.content.changeUnpublishDate", function (event, args) { - createButtons(args.node); - })); - evts.push(eventsService.on("editors.documentType.saved", function (name, args) { // if this content item uses the updated doc type we need to reload the content item if (args && args.documentType && args.documentType.key === content.documentType.key) { diff --git a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js index 5e9509977b..777b336447 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/contenteditinghelper.service.js @@ -266,40 +266,6 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica } } - // If we have a scheduled publish or unpublish date change the default button to - // "save" and update the label to "save and schedule - if (args.content.releaseDate || args.content.removeDate) { - - // if save button is alread the default don't change it just update the label - if (buttons.defaultButton && buttons.defaultButton.letter === "A") { - buttons.defaultButton.labelKey = "buttons_saveAndSchedule"; - return buttons; - } - - if (buttons.defaultButton && buttons.subButtons && buttons.subButtons.length > 0) { - // save a copy of the default so we can push it to the sub buttons later - var defaultButtonCopy = angular.copy(buttons.defaultButton); - var newSubButtons = []; - - // if save button is not the default button - find it and make it the default - angular.forEach(buttons.subButtons, function (subButton) { - - if (subButton.letter === "A") { - buttons.defaultButton = subButton; - buttons.defaultButton.labelKey = "buttons_saveAndSchedule"; - } else { - newSubButtons.push(subButton); - } - - }); - - // push old default button into subbuttons - newSubButtons.push(defaultButtonCopy); - buttons.subButtons = newSubButtons; - } - - } - return buttons; }, From 2e5d0f85e81cfd3c7b07a4d53b1828e196f97589 Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 5 Oct 2018 11:53:35 +0200 Subject: [PATCH 20/44] clears redirects on variation change --- .../Implement/ContentTypeRepositoryBase.cs | 21 +++++++++ .../Services/ContentTypeServiceTests.cs | 44 +++++++++++++++++++ 2 files changed, 65 insertions(+) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index 19f3623680..7104c9f713 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -274,6 +274,8 @@ AND umbracoNode.id <> @id", if (compositionBase != null && compositionBase.RemovedContentTypeKeyTracker != null && compositionBase.RemovedContentTypeKeyTracker.Any()) { + //TODO: Could we do the below with bulk SQL statements instead of looking everything up and then manipulating? + // find Content based on the current ContentType var sql = Sql() .SelectAll() @@ -292,6 +294,7 @@ AND umbracoNode.id <> @id", // based on the PropertyTypes that belong to the removed ContentType. foreach (var contentDto in contentDtos) { + //TODO: This could be done with bulk SQL statements foreach (var propertyType in propertyTypes) { var nodeId = contentDto.NodeId; @@ -408,6 +411,7 @@ AND umbracoNode.id <> @id", { //we've already looked up the previous version of the content type so we know it's previous variation state MoveVariantData(entity, (ContentVariation)dtoPk.Variations, entity.Variations); + Clear301Redirects(entity); } //track any property types that are changing variation @@ -492,6 +496,23 @@ AND umbracoNode.id <> @id", DeletePropertyType(entity.Id, id); } + /// + /// Clear any redirects associated with content for a content type + /// + private void Clear301Redirects(IContentTypeComposition contentType) + { + //first clear out any existing property data that might already exists under the default lang + var sqlSelect = Sql().Select(x => x.UniqueId) + .From() + .InnerJoin().On(x => x.NodeId, x => x.NodeId) + .Where(x => x.ContentTypeId == contentType.Id); + var sqlDelete = Sql() + .Delete() + .WhereIn((System.Linq.Expressions.Expression>)(x => x.ContentKey), sqlSelect); + + Database.Execute(sqlDelete); + } + /// /// Moves variant data for property type changes /// diff --git a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs index 892166e566..2d0471b9bd 100644 --- a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs @@ -24,6 +24,50 @@ namespace Umbraco.Tests.Services [UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerTest, PublishedRepositoryEvents = true)] public class ContentTypeServiceTests : TestWithSomeContentBase { + [Test] + public void Change_Content_Type_Variation_Clears_Redirects() + { + //create content type with a property type that varies by culture + var contentType = MockedContentTypes.CreateBasicContentType(); + contentType.Variations = ContentVariation.Nothing; + var contentCollection = new PropertyTypeCollection(true); + contentCollection.Add(new PropertyType("test", ValueStorageType.Ntext) + { + Alias = "title", + Name = "Title", + Description = "", + Mandatory = false, + SortOrder = 1, + DataTypeId = -88, + Variations = ContentVariation.Nothing + }); + contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 }); + ServiceContext.ContentTypeService.Save(contentType); + var contentType2 = MockedContentTypes.CreateBasicContentType("test"); + ServiceContext.ContentTypeService.Save(contentType2); + + //create some content of this content type + IContent doc = MockedContent.CreateBasicContent(contentType); + doc.Name = "Hello1"; + ServiceContext.ContentService.Save(doc); + + IContent doc2 = MockedContent.CreateBasicContent(contentType2); + ServiceContext.ContentService.Save(doc2); + + ServiceContext.RedirectUrlService.Register("hello/world", doc.Key); + ServiceContext.RedirectUrlService.Register("hello2/world2", doc2.Key); + + Assert.AreEqual(1, ServiceContext.RedirectUrlService.GetContentRedirectUrls(doc.Key).Count()); + Assert.AreEqual(1, ServiceContext.RedirectUrlService.GetContentRedirectUrls(doc2.Key).Count()); + + //change variation + contentType.Variations = ContentVariation.Culture; + ServiceContext.ContentTypeService.Save(contentType); + + Assert.AreEqual(0, ServiceContext.RedirectUrlService.GetContentRedirectUrls(doc.Key).Count()); + Assert.AreEqual(1, ServiceContext.RedirectUrlService.GetContentRedirectUrls(doc2.Key).Count()); + + } [Test] public void Change_Content_Type_From_Invariant_Variant() From 06d41086f310a009d5cf6485b2212cf433b2a07e Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 5 Oct 2018 11:56:47 +0200 Subject: [PATCH 21/44] adds stub code for clearing scheduled publishing --- .../Repositories/Implement/ContentTypeRepositoryBase.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index 7104c9f713..d1737d495a 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -412,6 +412,7 @@ AND umbracoNode.id <> @id", //we've already looked up the previous version of the content type so we know it's previous variation state MoveVariantData(entity, (ContentVariation)dtoPk.Variations, entity.Variations); Clear301Redirects(entity); + ClearScheduledPublishing(entity); } //track any property types that are changing variation @@ -513,6 +514,14 @@ AND umbracoNode.id <> @id", Database.Execute(sqlDelete); } + /// + /// Clear any scheduled publishing associated with content for a content type + /// + private void ClearScheduledPublishing(IContentTypeComposition contentType) + { + //TODO: Fill this in when scheduled publishing is enabled for variants + } + /// /// Moves variant data for property type changes /// From fdc94b9d1b423b54982e33fb576e17dd5b7c5bfe Mon Sep 17 00:00:00 2001 From: Shannon Date: Fri, 5 Oct 2018 15:07:19 +0200 Subject: [PATCH 22/44] Writes tests to ensure that property values are updated in docs that are of a composed type of the one that variants are being changed in. --- .../Models/ContentTypeBaseExtensions.cs | 15 +++ .../Models/IContentTypeComposition.cs | 1 + .../IContentTypeRepositoryBase.cs | 6 + .../Implement/ContentTypeRepositoryBase.cs | 10 +- .../Services/ContentTypeServiceExtensions.cs | 18 +-- ...peServiceBaseOfTRepositoryTItemTService.cs | 3 + .../Services/ContentTypeServiceTests.cs | 113 ++++++++++++++++++ .../Editors/ContentTypeControllerBase.cs | 2 +- 8 files changed, 148 insertions(+), 20 deletions(-) diff --git a/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs b/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs index 8af48bb881..0d2f817660 100644 --- a/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs +++ b/src/Umbraco.Core/Models/ContentTypeBaseExtensions.cs @@ -63,5 +63,20 @@ namespace Umbraco.Core.Models aliases = a; return hasAnyPropertyVariationChanged; } + + /// + /// Returns the list of content types the composition is used in + /// + /// + /// + /// + internal static IEnumerable GetWhereCompositionIsUsedInContentTypes(this IContentTypeComposition source, + IContentTypeComposition[] allContentTypes) + { + var sourceId = source != null ? source.Id : 0; + + // find which content types are using this composition + return allContentTypes.Where(x => x.ContentTypeComposition.Any(y => y.Id == sourceId)).ToArray(); + } } } diff --git a/src/Umbraco.Core/Models/IContentTypeComposition.cs b/src/Umbraco.Core/Models/IContentTypeComposition.cs index b5277a23be..36ace19f0f 100644 --- a/src/Umbraco.Core/Models/IContentTypeComposition.cs +++ b/src/Umbraco.Core/Models/IContentTypeComposition.cs @@ -10,6 +10,7 @@ namespace Umbraco.Core.Models /// /// Gets or sets the content types that compose this content type. /// + //fixme: we should be storing key references, not the object else we are caching way too much IEnumerable ContentTypeComposition { get; set; } /// diff --git a/src/Umbraco.Core/Persistence/Repositories/IContentTypeRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/IContentTypeRepositoryBase.cs index f5e9013082..3bb1ac38ca 100644 --- a/src/Umbraco.Core/Persistence/Repositories/IContentTypeRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/IContentTypeRepositoryBase.cs @@ -10,6 +10,12 @@ namespace Umbraco.Core.Persistence.Repositories { TItem Get(string alias); IEnumerable> Move(TItem moving, EntityContainer container); + + /// + /// Returns the content types that are direct compositions of the content type + /// + /// The content type id + /// IEnumerable GetTypesDirectlyComposedOf(int id); /// diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs index d1737d495a..3f1ea3116e 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepositoryBase.cs @@ -415,7 +415,7 @@ AND umbracoNode.id <> @id", ClearScheduledPublishing(entity); } - //track any property types that are changing variation + //track any content type/property types that are changing variation which will require content updates var propertyTypeVariationChanges = new Dictionary(); // insert or update properties @@ -426,7 +426,9 @@ AND umbracoNode.id <> @id", if (!ctVariationChanging) { if (propertyType.IsPropertyDirty("Variations")) + { propertyTypeVariationChanges[propertyType.Id] = propertyType.Variations; + } } else { @@ -481,7 +483,7 @@ AND umbracoNode.id <> @id", .From() .WhereIn(x => x.Id, propertyTypeVariationChanges.Keys)); - foreach(var f in from) + foreach (var f in from) { changes[f.Key] = (propertyTypeVariationChanges[f.Key], (ContentVariation)f.Value); } @@ -490,6 +492,7 @@ AND umbracoNode.id <> @id", MoveVariantData(changes); } + // deal with orphan properties: those that were in a deleted tab, // and have not been re-mapped to another tab or to 'generic properties' if (orphanPropertyTypeIds != null) @@ -845,8 +848,11 @@ AND umbracoNode.id <> @id", } } + /// public IEnumerable GetTypesDirectlyComposedOf(int id) { + //fixme - this will probably be more efficient to simply load all content types and do the calculation, see GetWhereCompositionIsUsedInContentTypes + var sql = Sql() .SelectAll() .From() diff --git a/src/Umbraco.Core/Services/ContentTypeServiceExtensions.cs b/src/Umbraco.Core/Services/ContentTypeServiceExtensions.cs index 9e82213aa5..66b3982b49 100644 --- a/src/Umbraco.Core/Services/ContentTypeServiceExtensions.cs +++ b/src/Umbraco.Core/Services/ContentTypeServiceExtensions.cs @@ -109,23 +109,7 @@ namespace Umbraco.Core.Services return new ContentTypeAvailableCompositionsResults(ancestors, result); } - /// - /// Returns the list of content types the composition is used in - /// - /// - /// - /// - /// - internal static IEnumerable GetWhereCompositionIsUsedInContentTypes(this IContentTypeService ctService, - IContentTypeComposition source, - IContentTypeComposition[] allContentTypes) - { - - var sourceId = source != null ? source.Id : 0; - - // find which content types are using this composition - return allContentTypes.Where(x => x.ContentTypeComposition.Any(y => y.Id == sourceId)).ToArray(); - } + private static IContentTypeComposition[] GetAncestors(IContentTypeComposition ctype, IContentTypeComposition[] allContentTypes) { diff --git a/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs b/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs index a3bc87315b..a114f415cc 100644 --- a/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs +++ b/src/Umbraco.Core/Services/Implement/ContentTypeServiceBaseOfTRepositoryTItemTService.cs @@ -346,6 +346,9 @@ namespace Umbraco.Core.Services.Implement public IEnumerable GetComposedOf(int id) { + //fixme: this is essentially the same as ContentTypeServiceExtensions.GetWhereCompositionIsUsedInContentTypes which loads + // all content types to figure this out, this instead makes quite a few queries so should be replaced + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(ReadLockIds); diff --git a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs index 2d0471b9bd..f25382d557 100644 --- a/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs +++ b/src/Umbraco.Tests/Services/ContentTypeServiceTests.cs @@ -266,6 +266,119 @@ namespace Umbraco.Tests.Services Assert.AreEqual("hello world", doc.GetValue("title", "en-US")); } + [Test] + public void Change_Property_Type_From_Variant_Invariant_On_A_Composition() + { + //create content type with a property type that varies by culture + var contentType = MockedContentTypes.CreateBasicContentType(); + contentType.Variations = ContentVariation.Culture; + var contentCollection = new PropertyTypeCollection(true); + contentCollection.Add(new PropertyType("test", ValueStorageType.Ntext) + { + Alias = "title", + Name = "Title", + Description = "", + Mandatory = false, + SortOrder = 1, + DataTypeId = -88, + Variations = ContentVariation.Culture + }); + contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 }); + ServiceContext.ContentTypeService.Save(contentType); + + //compose this from the other one + var contentType2 = MockedContentTypes.CreateBasicContentType("test"); + contentType2.Variations = ContentVariation.Culture; + contentType2.AddContentType(contentType); + ServiceContext.ContentTypeService.Save(contentType2); + + //create some content of this content type + IContent doc = MockedContent.CreateBasicContent(contentType); + doc.SetCultureName("Home", "en-US"); + doc.SetValue("title", "hello world", "en-US"); + ServiceContext.ContentService.Save(doc); + + IContent doc2 = MockedContent.CreateBasicContent(contentType2); + doc2.SetCultureName("Home", "en-US"); + doc2.SetValue("title", "hello world", "en-US"); + ServiceContext.ContentService.Save(doc2); + + //change the property type to be invariant + contentType.PropertyTypes.First().Variations = ContentVariation.Nothing; + ServiceContext.ContentTypeService.Save(contentType); + doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + doc2 = ServiceContext.ContentService.GetById(doc2.Id); //re-get + + Assert.AreEqual("hello world", doc.GetValue("title")); + Assert.AreEqual("hello world", doc2.GetValue("title")); + + //change back property type to be variant + contentType.PropertyTypes.First().Variations = ContentVariation.Culture; + ServiceContext.ContentTypeService.Save(contentType); + doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + doc2 = ServiceContext.ContentService.GetById(doc2.Id); //re-get + + Assert.AreEqual("hello world", doc.GetValue("title", "en-US")); + Assert.AreEqual("hello world", doc2.GetValue("title", "en-US")); + } + + [Test] + public void Change_Content_Type_From_Variant_Invariant_On_A_Composition() + { + //create content type with a property type that varies by culture + var contentType = MockedContentTypes.CreateBasicContentType(); + contentType.Variations = ContentVariation.Culture; + var contentCollection = new PropertyTypeCollection(true); + contentCollection.Add(new PropertyType("test", ValueStorageType.Ntext) + { + Alias = "title", + Name = "Title", + Description = "", + Mandatory = false, + SortOrder = 1, + DataTypeId = -88, + Variations = ContentVariation.Culture + }); + contentType.PropertyGroups.Add(new PropertyGroup(contentCollection) { Name = "Content", SortOrder = 1 }); + ServiceContext.ContentTypeService.Save(contentType); + + //compose this from the other one + var contentType2 = MockedContentTypes.CreateBasicContentType("test"); + contentType2.Variations = ContentVariation.Culture; + contentType2.AddContentType(contentType); + ServiceContext.ContentTypeService.Save(contentType2); + + //create some content of this content type + IContent doc = MockedContent.CreateBasicContent(contentType); + doc.SetCultureName("Home", "en-US"); + doc.SetValue("title", "hello world", "en-US"); + ServiceContext.ContentService.Save(doc); + + IContent doc2 = MockedContent.CreateBasicContent(contentType2); + doc2.SetCultureName("Home", "en-US"); + doc2.SetValue("title", "hello world", "en-US"); + ServiceContext.ContentService.Save(doc2); + + //change the content type to be invariant + contentType.Variations = ContentVariation.Nothing; + ServiceContext.ContentTypeService.Save(contentType); + doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + doc2 = ServiceContext.ContentService.GetById(doc2.Id); //re-get + + Assert.AreEqual("hello world", doc.GetValue("title")); + Assert.AreEqual("hello world", doc2.GetValue("title")); + + //change back content type to be variant + contentType.Variations = ContentVariation.Culture; + ServiceContext.ContentTypeService.Save(contentType); + doc = ServiceContext.ContentService.GetById(doc.Id); //re-get + doc2 = ServiceContext.ContentService.GetById(doc2.Id); //re-get + + //this will be null because the doc type was changed back to variant but it's property types don't get changed back + Assert.IsNull(doc.GetValue("title", "en-US")); + Assert.IsNull(doc2.GetValue("title", "en-US")); + } + [Test] public void Deleting_Media_Type_With_Hierarchy_Of_Media_Items_Moves_Orphaned_Media_To_Recycle_Bin() { diff --git a/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs b/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs index fa1aaf7345..22d86631ca 100644 --- a/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs +++ b/src/Umbraco.Web/Editors/ContentTypeControllerBase.cs @@ -161,7 +161,7 @@ namespace Umbraco.Web.Editors throw new ArgumentOutOfRangeException("The entity type was not a content type"); } - var contentTypesWhereCompositionIsUsed = Services.ContentTypeService.GetWhereCompositionIsUsedInContentTypes(source, allContentTypes); + var contentTypesWhereCompositionIsUsed = source.GetWhereCompositionIsUsedInContentTypes(allContentTypes); return contentTypesWhereCompositionIsUsed .Select(x => Mapper.Map(x)) .Select(x => From 90900067a852d7c8efd08c4243de01356508346f Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Sun, 7 Oct 2018 15:29:24 +0200 Subject: [PATCH 23/44] wip Add flatpickr library + create flatpickr component --- src/Umbraco.Web.UI.Client/gulpfile.js | 12 +- src/Umbraco.Web.UI.Client/package.json | 1 + .../components/umbflatpickr.directive.js | 164 ++++++++++++++++++ .../content/overlays/schedule.controller.js | 44 +++-- .../src/views/content/overlays/schedule.html | 56 +++--- 5 files changed, 235 insertions(+), 42 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/common/directives/components/umbflatpickr.directive.js diff --git a/src/Umbraco.Web.UI.Client/gulpfile.js b/src/Umbraco.Web.UI.Client/gulpfile.js index 2d34e8ecb3..1a2942ec2b 100644 --- a/src/Umbraco.Web.UI.Client/gulpfile.js +++ b/src/Umbraco.Web.UI.Client/gulpfile.js @@ -142,7 +142,7 @@ gulp.task('docserve', function(cb) { **************************/ gulp.task('dependencies', function () { - //bower component specific copy rules + //bower component/npm specific copy rules //this is to patch the sometimes wonky rules these libs are distrbuted under //as we do multiple things in this task, we merge the multiple streams @@ -199,6 +199,16 @@ gulp.task('dependencies', function () { .pipe(gulp.dest(root + targets.lib + "/codemirror")) ); + // npm dependencies + // flatpickr + stream.add( + gulp.src([ + "./node_modules/flatpickr/dist/flatpickr.js", + "./node_modules/flatpickr/dist/flatpickr.css"], + { base: "./node_modules/flatpickr/dist" }) + .pipe(gulp.dest(root + targets.lib + "/flatpickr")) + ); + //copy over libs which are not on bower (/lib) and //libraries that have been managed by bower-installer (/lib-bower) stream.add( diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index c05401a05c..7051c2e3e6 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -5,6 +5,7 @@ "build": "gulp" }, "dependencies": { + "flatpickr": "^4.5.2", "npm": "^6.4.1" }, "devDependencies": { diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/umbflatpickr.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbflatpickr.directive.js new file mode 100644 index 0000000000..828d17e4c5 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/umbflatpickr.directive.js @@ -0,0 +1,164 @@ +(function() { + 'use strict'; + + var umbFlatpickr = { + template: '' + + '' + + '
' + + '
', + controller: umbFlatpickrCtrl, + transclude: true, + bindings: { + ngModel: '<', + options: '<', + onSetup: '&', + onChange: '&?', + onOpen: '&?', + onClose: '&?', + onMonthChange: '&?' + } + }; + + function umbFlatpickrCtrl($element, $timeout, $scope, assetsService) { + var ctrl = this; + var loaded = false; + + ctrl.$onInit = function() { + + // load css file for the date picker + assetsService.loadCss('lib/flatpickr/flatpickr.css', $scope); + + // load the js file for the date picker + assetsService.loadJs('lib/flatpickr/flatpickr.js', $scope).then(function () { + // init date picker + loaded = true; + grabElementAndRunFlatpickr(); + }); + + }; + + ctrl.$onChanges = function() { + if(loaded) { + //grabElementAndRunFlatpickr(); + } + }; + + function grabElementAndRunFlatpickr() { + $timeout(function() { + var transcludeEl = $element.find('ng-transclude')[0]; + var element = transcludeEl.children[0]; + + setDatepicker(element); + }, 0, true); + } + + function setDatepicker(element) { + var fpLib = flatpickr ? flatpickr : FlatpickrInstance; + + if (!fpLib) { + return console.warn('Unable to find any flatpickr installation'); + } + + setUpCallbacks(); + + var fpInstance = new fpLib(element, ctrl.options); + + if (ctrl.onSetup) { + ctrl.onSetup({ + fpItem: fpInstance + }); + } + + // If has ngModel set the date + if (ctrl.ngModel) { + fpInstance.setDate(ctrl.ngModel); + } + + // destroy the flatpickr instance when the dom element is removed + angular.element(element).on('$destroy', function() { + fpInstance.destroy(); + }); + + // Refresh the scope + $scope.$applyAsync(); + } + + function setUpCallbacks() { + // bind hook for onChange + if(ctrl.options && ctrl.onChange) { + ctrl.options.onChange = function(selectedDates, dateStr, instance) { + $timeout(function() { + ctrl.onChange({selectedDates: selectedDates, dateStr: dateStr, instance: instance}); + }); + }; + } + + // bind hook for onOpen + if(ctrl.options && ctrl.onOpen) { + ctrl.options.onOpen = function(selectedDates, dateStr, instance) { + $timeout(function() { + ctrl.onOpen({selectedDates: selectedDates, dateStr: dateStr, instance: instance}); + }); + }; + } + + // bind hook for onOpen + if(ctrl.options && ctrl.onClose) { + ctrl.options.onClose = function(selectedDates, dateStr, instance) { + $timeout(function() { + ctrl.onClose({selectedDates: selectedDates, dateStr: dateStr, instance: instance}); + }); + }; + } + + // bind hook for onMonthChange + if(ctrl.options && ctrl.onMonthChange) { + ctrl.options.onMonthChange = function(selectedDates, dateStr, instance) { + $timeout(function() { + ctrl.onMonthChange({selectedDates: selectedDates, dateStr: dateStr, instance: instance}); + }); + }; + } + + // bind hook for onYearChange + if(ctrl.options && ctrl.onYearChange) { + ctrl.options.onYearChange = function(selectedDates, dateStr, instance) { + $timeout(function() { + ctrl.onYearChange({selectedDates: selectedDates, dateStr: dateStr, instance: instance}); + }); + }; + } + + // bind hook for onReady + if(ctrl.options && ctrl.onReady) { + ctrl.options.onReady = function(selectedDates, dateStr, instance) { + $timeout(function() { + ctrl.onReady({selectedDates: selectedDates, dateStr: dateStr, instance: instance}); + }); + }; + } + + // bind hook for onValueUpdate + if(ctrl.onValueUpdate) { + ctrl.options.onValueUpdate = function(selectedDates, dateStr, instance) { + $timeout(function() { + ctrl.onValueUpdate({selectedDates: selectedDates, dateStr: dateStr, instance: instance}); + }); + }; + } + + // bind hook for onDayCreate + if(ctrl.onDayCreate) { + ctrl.options.onDayCreate = function(selectedDates, dateStr, instance) { + $timeout(function() { + ctrl.onDayCreate({selectedDates: selectedDates, dateStr: dateStr, instance: instance}); + }); + }; + } + + } + } + + angular.module('umbraco.directives').component('umbFlatpickr', umbFlatpickr); + +})(); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js index 7974103b7a..6f570be8a5 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js @@ -5,6 +5,7 @@ var vm = this; + vm.datePickerSetup = datePickerSetup; vm.datePickerChange = datePickerChange; vm.datePickerShow = datePickerShow; vm.datePickerClose = datePickerClose; @@ -16,18 +17,6 @@ vm.firstSelectedDates = {}; vm.currentUser = null; - vm.datePickerConfig = { - pickDate: true, - pickTime: true, - useSeconds: false, - format: "YYYY-MM-DD HH:mm", - icons: { - time: "icon-time", - date: "icon-calendar", - up: "icon-chevron-up", - down: "icon-chevron-down" - } - }; function onInit() { @@ -79,8 +68,23 @@ vm.currentUser = currentUser; - // format all dates to local angular.forEach(vm.variants, function(variant) { + + // prevent selecting publish/unpublish date before today + var now = new Date(); + var nowFormatted = moment(now).format("YYYY-MM-DD HH:mm"); + + var datePickerConfig = { + enableTime: true, + dateFormat: "Y-m-d H:i", + time_24hr: true, + minDate: nowFormatted, + defaultDate: nowFormatted + }; + + variant.datePickerConfig = datePickerConfig; + + // format all dates to local if(variant.releaseDate || variant.removeDate) { formatDatesToLocal(variant); } @@ -90,22 +94,24 @@ } - function datePickerChange(variant, event, type) { + function datePickerSetup(variant, datePickerInstance) { + variant.datePickerInstance = datePickerInstance; + }; + + function datePickerChange(variant, dateStr, type) { if (type === 'publish') { - setPublishDate(variant, event.date.format("YYYY-MM-DD HH:mm")); + setPublishDate(variant, dateStr); } else if (type === 'unpublish') { - setUnpublishDate(variant, event.date.format("YYYY-MM-DD HH:mm")); + setUnpublishDate(variant, dateStr); } } function datePickerShow() { - // prevent the overlay from closing when the date picker is open $scope.model.disableBackdropClick = true; } function datePickerClose() { $timeout(function(){ - // allow the date picker to close now the date picker is closed $scope.model.disableBackdropClick = false; }); } @@ -128,6 +134,8 @@ // store the first selected date so we can apply to other selected variants + // variant.datePickerInstance.set("maxDate", moment(variant.releaseDate).format("YYYY-MM-DD HH:mm")); + } function setUnpublishDate(variant, date) { diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html index 1a170b9d75..665dc003f3 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html @@ -14,25 +14,31 @@
- -
- {{vm.variants[0].releaseDateFormatted}} + + +
+
+ {{vm.variants[0].releaseDateFormatted}} +
+ + + Set date +
- - Set date - - - +
+
@@ -42,25 +48,29 @@
- + on-close="vm.datePickerClose()"> -
- {{vm.variants[0].removeDateFormatted}} +
+
+ {{vm.variants[0].removeDateFormatted}} +
+ + + Set date +
- - - Set date - - + +
From 8c52529e472cb0a9ee479fbe2b06bfe6fc784c0d Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Sun, 7 Oct 2018 20:01:20 +0200 Subject: [PATCH 24/44] add babel + babel config --- src/Umbraco.Web.UI.Client/.babelrc | 3 + src/Umbraco.Web.UI.Client/.eslintrc | 4 + src/Umbraco.Web.UI.Client/gulpfile.js | 22 +- src/Umbraco.Web.UI.Client/package-lock.json | 1282 ++++++++++++++++--- src/Umbraco.Web.UI.Client/package.json | 3 + 5 files changed, 1130 insertions(+), 184 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/.babelrc diff --git a/src/Umbraco.Web.UI.Client/.babelrc b/src/Umbraco.Web.UI.Client/.babelrc new file mode 100644 index 0000000000..ff3059c3f0 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": ["@babel/preset-env"] +} \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/.eslintrc b/src/Umbraco.Web.UI.Client/.eslintrc index 1b39098cfc..1bfa081b9a 100644 --- a/src/Umbraco.Web.UI.Client/.eslintrc +++ b/src/Umbraco.Web.UI.Client/.eslintrc @@ -7,6 +7,10 @@ "comma-dangle": ["error", "never"] }, + "parserOptions": { + "ecmaVersion": 6 + }, + "globals": { "angular": false, "_": false, diff --git a/src/Umbraco.Web.UI.Client/gulpfile.js b/src/Umbraco.Web.UI.Client/gulpfile.js index 2d34e8ecb3..985d939fcd 100644 --- a/src/Umbraco.Web.UI.Client/gulpfile.js +++ b/src/Umbraco.Web.UI.Client/gulpfile.js @@ -6,6 +6,7 @@ var wrap = require("gulp-wrap-js"); var sort = require('gulp-sort'); var connect = require('gulp-connect'); var open = require('gulp-open'); +const babel = require("gulp-babel"); var runSequence = require('run-sequence'); const imagemin = require('gulp-imagemin'); @@ -33,17 +34,18 @@ Helper functions function processJs(files, out) { return gulp.src(files) - // check for js errors - .pipe(eslint()) - // outputs the lint results to the console - .pipe(eslint.format()) - // sort files in stream by path or any custom sort comparator - .pipe(sort()) - .pipe(concat(out)) - .pipe(wrap('(function(){\n%= body %\n})();')) - .pipe(gulp.dest(root + targets.js)); + // check for js errors + .pipe(eslint()) + // outputs the lint results to the console + .pipe(eslint.format()) + // sort files in stream by path or any custom sort comparator + .pipe(babel()) + .pipe(sort()) + .pipe(concat(out)) + .pipe(wrap('(function(){\n%= body %\n})();')) + .pipe(gulp.dest(root + targets.js)); - console.log(out + " compiled"); + console.log(out + " compiled"); } function processLess(files, out) { diff --git a/src/Umbraco.Web.UI.Client/package-lock.json b/src/Umbraco.Web.UI.Client/package-lock.json index 43a973b4f1..fd6ffefbae 100644 --- a/src/Umbraco.Web.UI.Client/package-lock.json +++ b/src/Umbraco.Web.UI.Client/package-lock.json @@ -11,6 +11,267 @@ "@babel/highlight": "^7.0.0" } }, + "@babel/core": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.1.2.tgz", + "integrity": "sha512-IFeSSnjXdhDaoysIlev//UzHZbdEmm7D0EIH2qtse9xK7mXEZQpYjs2P00XlP1qYsYvid79p+Zgg6tz1mp6iVw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.1.2", + "@babel/helpers": "^7.1.2", + "@babel/parser": "^7.1.2", + "@babel/template": "^7.1.2", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.1.2", + "convert-source-map": "^1.1.0", + "debug": "^3.1.0", + "json5": "^0.5.0", + "lodash": "^4.17.10", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "debug": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "semver": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", + "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.1.2.tgz", + "integrity": "sha512-70A9HWLS/1RHk3Ck8tNHKxOoKQuSKocYgwDN85Pyl/RBduss6AKxUR7RIZ/lzduQMSYfWEM4DDBu6A+XGbkFig==", + "dev": true, + "requires": { + "@babel/types": "^7.1.2", + "jsesc": "^2.5.1", + "lodash": "^4.17.10", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz", + "integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz", + "integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-call-delegate": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.1.0.tgz", + "integrity": "sha512-YEtYZrw3GUK6emQHKthltKNZwszBcHK58Ygcis+gVUrF4/FmTVr5CCqQNSfmvg2y+YDEANyYoaLz/SHsnusCwQ==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.0.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-define-map": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.1.0.tgz", + "integrity": "sha512-yPPcW8dc3gZLN+U1mhYV91QU3n5uTbx7DUdf8NnPbjS0RMwBuHi9Xt2MUgppmNz7CJxTBWsGczTiEp1CSOTPRg==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/types": "^7.0.0", + "lodash": "^4.17.10" + } + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz", + "integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-function-name": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", + "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", + "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.0.0.tgz", + "integrity": "sha512-Ggv5sldXUeSKsuzLkddtyhyHe2YantsxWKNi7A+7LeD12ExRDWTRk29JCXpaHPAbMaIPZSil7n+lq78WY2VY7w==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz", + "integrity": "sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-module-imports": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz", + "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-module-transforms": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.1.0.tgz", + "integrity": "sha512-0JZRd2yhawo79Rcm4w0LwSMILFmFXjugG3yqf+P/UsKsRS1mJCmMwwlHDlMg7Avr9LrvSpp4ZSULO9r8jpCzcw==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0", + "lodash": "^4.17.10" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz", + "integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", + "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", + "dev": true + }, + "@babel/helper-regex": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.0.0.tgz", + "integrity": "sha512-TR0/N0NDCcUIUEbqV6dCO+LptmmSQFQ7q70lfcEB4URsjD0E1HzicrwUH+ap6BAQ2jhCX9Q4UqZy4wilujWlkg==", + "dev": true, + "requires": { + "lodash": "^4.17.10" + } + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz", + "integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-wrap-function": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-replace-supers": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.1.0.tgz", + "integrity": "sha512-BvcDWYZRWVuDeXTYZWxekQNO5D4kO55aArwZOTFXw6rlLQA8ZaDicJR1sO47h+HrnCiDFiww0fSPV0d713KBGQ==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.0.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-simple-access": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz", + "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==", + "dev": true, + "requires": { + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz", + "integrity": "sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-wrap-function": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.1.0.tgz", + "integrity": "sha512-R6HU3dete+rwsdAfrOzTlE9Mcpk4RjU3aX3gi9grtmugQY0u79X7eogUvfXA5sI81Mfq1cn6AgxihfN33STjJA==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helpers": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.1.2.tgz", + "integrity": "sha512-Myc3pUE8eswD73aWcartxB16K6CGmHDv9KxOmD2CeOs/FaEAQodr3VYGmlvOmog60vNQ2w8QbatuahepZwrHiA==", + "dev": true, + "requires": { + "@babel/template": "^7.1.2", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.1.2" + } + }, "@babel/highlight": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", @@ -59,10 +320,497 @@ } } }, + "@babel/parser": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.1.2.tgz", + "integrity": "sha512-x5HFsW+E/nQalGMw7hu+fvPqnBeBaIr0lWJ2SG0PPL2j+Pm9lYvCrsZJGIgauPIENx0v10INIyFjmSNUD/gSqQ==", + "dev": true + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.1.0.tgz", + "integrity": "sha512-Fq803F3Jcxo20MXUSDdmZZXrPe6BWyGcWBPPNB/M7WaUYESKDeKMOGIxEzQOjGSmW/NWb6UaPZrtTB2ekhB/ew==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0", + "@babel/plugin-syntax-async-generators": "^7.0.0" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.0.0.tgz", + "integrity": "sha512-kfVdUkIAGJIVmHmtS/40i/fg/AGnw/rsZBCaapY5yjeO5RA9m165Xbw9KMOu2nqXP5dTFjEjHdfNdoVcHv133Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-json-strings": "^7.0.0" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.0.0.tgz", + "integrity": "sha512-14fhfoPcNu7itSen7Py1iGN0gEm87hX/B+8nZPqkdmANyyYWYMY2pjA3r8WXbWVKMzfnSNS0xY8GVS0IjXi/iw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-object-rest-spread": "^7.0.0" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.0.0.tgz", + "integrity": "sha512-JPqAvLG1s13B/AuoBjdBYvn38RqW6n1TzrQO839/sIpqLpbnXKacsAgpZHzLD83Sm8SDXMkkrAvEnJ25+0yIpw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.0.0" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.0.0.tgz", + "integrity": "sha512-tM3icA6GhC3ch2SkmSxv7J/hCWKISzwycub6eGsDrFDgukD4dZ/I+x81XgW0YslS6mzNuQ1Cbzh5osjIMgepPQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0", + "regexpu-core": "^4.2.0" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.0.0.tgz", + "integrity": "sha512-im7ged00ddGKAjcZgewXmp1vxSZQQywuQXe2B1A7kajjZmDeY/ekMPmWr9zJgveSaQH0k7BcGrojQhcK06l0zA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.0.0.tgz", + "integrity": "sha512-UlSfNydC+XLj4bw7ijpldc1uZ/HB84vw+U6BTuqMdIEmz/LDe63w/GHtpQMdXWdqQZFeAI9PjnHe/vDhwirhKA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.0.0.tgz", + "integrity": "sha512-5A0n4p6bIiVe5OvQPxBnesezsgFJdHhSs3uFSvaPdMqtsovajLZ+G2vZyvNe10EzJBWWo3AcHGKhAFUxqwp2dw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.0.0.tgz", + "integrity": "sha512-Wc+HVvwjcq5qBg1w5RG9o9RVzmCaAg/Vp0erHCKpAYV8La6I94o4GQAmFYNmkzoMO6gzoOSulpKeSSz6mPEoZw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.0.0.tgz", + "integrity": "sha512-2EZDBl1WIO/q4DIkIp4s86sdp4ZifL51MoIviLY/gG/mLSuOIEg7J8o6mhbxOTvUJkaN50n+8u41FVsr5KLy/w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.1.0.tgz", + "integrity": "sha512-rNmcmoQ78IrvNCIt/R9U+cixUHeYAzgusTFgIAv+wQb9HJU4szhpDD6e5GCACmj/JP5KxuCwM96bX3L9v4ZN/g==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.0.0.tgz", + "integrity": "sha512-AOBiyUp7vYTqz2Jibe1UaAWL0Hl9JUXEgjFvvvcSc9MVDItv46ViXFw2F7SVt1B5k+KWjl44eeXOAk3UDEaJjQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.0.0.tgz", + "integrity": "sha512-GWEMCrmHQcYWISilUrk9GDqH4enf3UmhOEbNbNrlNAX1ssH3MsS1xLOS6rdjRVPgA7XXVPn87tRkdTEoA/dxEg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "lodash": "^4.17.10" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.1.0.tgz", + "integrity": "sha512-rNaqoD+4OCBZjM7VaskladgqnZ1LO6o2UxuWSDzljzW21pN1KXkB7BstAVweZdxQkHAujps5QMNOTWesBciKFg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-define-map": "^7.1.0", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.0.0.tgz", + "integrity": "sha512-ubouZdChNAv4AAWAgU7QKbB93NU5sHwInEWfp+/OzJKA02E6Woh9RVoX4sZrbRwtybky/d7baTUqwFx+HgbvMA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.1.2.tgz", + "integrity": "sha512-cvToXvp/OsYxtEn57XJu9BvsGSEYjAh9UeUuXpoi7x6QHB7YdWyQ4lRU/q0Fu1IJNT0o0u4FQ1DMQBzJ8/8vZg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.0.0.tgz", + "integrity": "sha512-00THs8eJxOJUFVx1w8i1MBF4XH4PsAjKjQ1eqN/uCH3YKwP21GCKfrn6YZFZswbOk9+0cw1zGQPHVc1KBlSxig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0", + "regexpu-core": "^4.1.3" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.0.0.tgz", + "integrity": "sha512-w2vfPkMqRkdxx+C71ATLJG30PpwtTpW7DDdLqYt2acXU7YjztzeWW2Jk1T6hKqCLYCcEA5UQM/+xTAm+QCSnuQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.1.0.tgz", + "integrity": "sha512-uZt9kD1Pp/JubkukOGQml9tqAeI8NkE98oZnHZ2qHRElmeKCodbTZgOEUtujSCSLhHSBWbzNiFSDIMC4/RBTLQ==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.0.0.tgz", + "integrity": "sha512-TlxKecN20X2tt2UEr2LNE6aqA0oPeMT1Y3cgz8k4Dn1j5ObT8M3nl9aA37LLklx0PBZKETC9ZAf9n/6SujTuXA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.1.0.tgz", + "integrity": "sha512-VxOa1TMlFMtqPW2IDYZQaHsFrq/dDoIjgN098NowhexhZcz3UGlvPgZXuE1jEvNygyWyxRacqDpCZt+par1FNg==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.0.0.tgz", + "integrity": "sha512-1NTDBWkeNXgpUcyoVFxbr9hS57EpZYXpje92zv0SUzjdu3enaRwF/l3cmyRnXLtIdyJASyiS6PtybK+CgKf7jA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.1.0.tgz", + "integrity": "sha512-wt8P+xQ85rrnGNr2x1iV3DW32W8zrB6ctuBkYBbf5/ZzJY99Ob4MFgsZDFgczNU76iy9PWsy4EuxOliDjdKw6A==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.1.0.tgz", + "integrity": "sha512-wtNwtMjn1XGwM0AXPspQgvmE6msSJP15CX2RVfpTSTNPLhKhaOjaIfBaVfj4iUZ/VrFSodcFedwtPg/NxwQlPA==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.0.0.tgz", + "integrity": "sha512-8EDKMAsitLkiF/D4Zhe9CHEE2XLh4bfLbb9/Zf3FgXYQOZyZYyg7EAel/aT2A7bHv62jwHf09q2KU/oEexr83g==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.1.0.tgz", + "integrity": "sha512-enrRtn5TfRhMmbRwm7F8qOj0qEYByqUvTttPEGimcBH4CJHphjyK1Vg7sdU7JjeEmgSpM890IT/efS2nMHwYig==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.0.0.tgz", + "integrity": "sha512-yin069FYjah+LbqfGeTfzIBODex/e++Yfa0rH0fpfam9uTbuEeEOx5GLGr210ggOV77mVRNoeqSYqeuaqSzVSw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.1.0.tgz", + "integrity": "sha512-/O02Je1CRTSk2SSJaq0xjwQ8hG4zhZGNjE8psTsSNPXyLRCODv7/PBozqT5AmQMzp7MI3ndvMhGdqp9c96tTEw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.1.0" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.1.0.tgz", + "integrity": "sha512-vHV7oxkEJ8IHxTfRr3hNGzV446GAb+0hgbA7o/0Jd76s+YzccdWuTU296FOCOl/xweU4t/Ya4g41yWz80RFCRw==", + "dev": true, + "requires": { + "@babel/helper-call-delegate": "^7.1.0", + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.0.0.tgz", + "integrity": "sha512-sj2qzsEx8KDVv1QuJc/dEfilkg3RRPvPYx/VnKLtItVQRWt1Wqf5eVCOLZm29CiGFfYYsA3VPjfizTCV0S0Dlw==", + "dev": true, + "requires": { + "regenerator-transform": "^0.13.3" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.0.0.tgz", + "integrity": "sha512-g/99LI4vm5iOf5r1Gdxq5Xmu91zvjhEG5+yZDJW268AZELAu4J1EiFLnkSG3yuUsZyOipVOVUKoGPYwfsTymhw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.0.0.tgz", + "integrity": "sha512-L702YFy2EvirrR4shTj0g2xQp7aNwZoWNCkNu2mcoU0uyzMl0XRwDSwzB/xp6DSUFiBmEXuyAyEN16LsgVqGGQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.0.0.tgz", + "integrity": "sha512-LFUToxiyS/WD+XEWpkx/XJBrUXKewSZpzX68s+yEOtIbdnsRjpryDw9U06gYc6klYEij/+KQVRnD3nz3AoKmjw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.0.0.tgz", + "integrity": "sha512-vA6rkTCabRZu7Nbl9DfLZE1imj4tzdWcg5vtdQGvj+OH9itNNB6hxuRMHuIY8SGnEt1T9g5foqs9LnrHzsqEFg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.0.0.tgz", + "integrity": "sha512-1r1X5DO78WnaAIvs5uC48t41LLckxsYklJrZjNKcevyz83sF2l4RHbw29qrCPr/6ksFsdfRpT/ZgxNWHXRnffg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.0.0.tgz", + "integrity": "sha512-uJBrJhBOEa3D033P95nPHu3nbFwFE9ZgXsfEitzoIXIwqAZWk7uXcg06yFKXz9FSxBH5ucgU/cYdX0IV8ldHKw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0", + "regexpu-core": "^4.1.3" + } + }, + "@babel/preset-env": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.1.0.tgz", + "integrity": "sha512-ZLVSynfAoDHB/34A17/JCZbyrzbQj59QC1Anyueb4Bwjh373nVPq5/HMph0z+tCmcDjXDe+DlKQq9ywQuvWrQg==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-async-generator-functions": "^7.1.0", + "@babel/plugin-proposal-json-strings": "^7.0.0", + "@babel/plugin-proposal-object-rest-spread": "^7.0.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.0.0", + "@babel/plugin-syntax-async-generators": "^7.0.0", + "@babel/plugin-syntax-object-rest-spread": "^7.0.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.0.0", + "@babel/plugin-transform-arrow-functions": "^7.0.0", + "@babel/plugin-transform-async-to-generator": "^7.1.0", + "@babel/plugin-transform-block-scoped-functions": "^7.0.0", + "@babel/plugin-transform-block-scoping": "^7.0.0", + "@babel/plugin-transform-classes": "^7.1.0", + "@babel/plugin-transform-computed-properties": "^7.0.0", + "@babel/plugin-transform-destructuring": "^7.0.0", + "@babel/plugin-transform-dotall-regex": "^7.0.0", + "@babel/plugin-transform-duplicate-keys": "^7.0.0", + "@babel/plugin-transform-exponentiation-operator": "^7.1.0", + "@babel/plugin-transform-for-of": "^7.0.0", + "@babel/plugin-transform-function-name": "^7.1.0", + "@babel/plugin-transform-literals": "^7.0.0", + "@babel/plugin-transform-modules-amd": "^7.1.0", + "@babel/plugin-transform-modules-commonjs": "^7.1.0", + "@babel/plugin-transform-modules-systemjs": "^7.0.0", + "@babel/plugin-transform-modules-umd": "^7.1.0", + "@babel/plugin-transform-new-target": "^7.0.0", + "@babel/plugin-transform-object-super": "^7.1.0", + "@babel/plugin-transform-parameters": "^7.1.0", + "@babel/plugin-transform-regenerator": "^7.0.0", + "@babel/plugin-transform-shorthand-properties": "^7.0.0", + "@babel/plugin-transform-spread": "^7.0.0", + "@babel/plugin-transform-sticky-regex": "^7.0.0", + "@babel/plugin-transform-template-literals": "^7.0.0", + "@babel/plugin-transform-typeof-symbol": "^7.0.0", + "@babel/plugin-transform-unicode-regex": "^7.0.0", + "browserslist": "^4.1.0", + "invariant": "^2.2.2", + "js-levenshtein": "^1.1.3", + "semver": "^5.3.0" + }, + "dependencies": { + "browserslist": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.2.0.tgz", + "integrity": "sha512-Berls1CHL7qfQz8Lct6QxYA5d2Tvt4doDWHcjvAISybpd+EKZVppNtXgXhaN6SdrPKo7YLTSZuYBs5cYrSWN8w==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000889", + "electron-to-chromium": "^1.3.73", + "node-releases": "^1.0.0-alpha.12" + } + }, + "semver": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", + "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==", + "dev": true + } + } + }, + "@babel/template": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.1.2.tgz", + "integrity": "sha512-SY1MmplssORfFiLDcOETrW7fCLl+PavlwMh92rrGcikQaRq4iWPVH0MpwPpY3etVMx6RnDjXtr6VZYr/IbP/Ag==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.1.2", + "@babel/types": "^7.1.2" + } + }, + "@babel/traverse": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.1.0.tgz", + "integrity": "sha512-bwgln0FsMoxm3pLOgrrnGaXk18sSM9JNf1/nHC/FksmNGFbYnPWY4GYCfLxyP1KRmfsxqkRpfoa6xr6VuuSxdw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.0.0", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.0.0", + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "debug": "^3.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.10" + }, + "dependencies": { + "debug": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.5.tgz", + "integrity": "sha512-D61LaDQPQkxJ5AUM2mbSJRbPkNs/TmdmOeLAi1hgDkpDfIfetSrjmWhccwtuResSwMbACjx/xXQofvM9CE/aeg==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.1.2.tgz", + "integrity": "sha512-pb1I05sZEKiSlMUV9UReaqsCPUpgbHHHu2n1piRm7JkuBkm6QxcaIzKu6FMnMtCbih/cEYTR+RGYYC96Yk9HAg==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.10", + "to-fast-properties": "^2.0.0" + } + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "integrity": "sha1-+PLIh60Qv2f2NPAFtph/7TF5qsg=", "dev": true }, "accepts": { @@ -78,7 +826,7 @@ "accord": { "version": "0.28.0", "resolved": "https://registry.npmjs.org/accord/-/accord-0.28.0.tgz", - "integrity": "sha512-sPF34gqHegaCSryKf5wHJ8wREK1dTZnHmC9hsB7D8xjntRdd30DXDPKf0YVIcSvnXJmcYu5SCvZRz28H++kFhQ==", + "integrity": "sha1-vsUWovci59UPX59C+Bt387lUSLo=", "dev": true, "requires": { "convert-source-map": "^1.5.0", @@ -197,7 +945,7 @@ "amqplib": { "version": "0.5.2", "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.5.2.tgz", - "integrity": "sha512-l9mCs6LbydtHqRniRwYkKdqxVa6XMz3Vw1fh+2gJaaVgTM6Jk3o8RccAKWKtlhT1US5sWrFh+KKxsVUALURSIA==", + "integrity": "sha1-0tcxPH/6pNELzx5iUt5FkbbMe2M=", "dev": true, "optional": true, "requires": { @@ -222,7 +970,7 @@ }, "ansi-colors": { "version": "1.1.0", - "resolved": "http://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", "dev": true, "requires": { @@ -283,7 +1031,7 @@ "anymatch": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", - "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "integrity": "sha1-VT3Lj5HjyImEXf26NMd3IbkLnXo=", "dev": true, "requires": { "micromatch": "^2.1.5", @@ -407,7 +1155,7 @@ "argparse": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "integrity": "sha1-vNZ5HqWuCXJeF+WtmIE0zUCz2RE=", "dev": true, "requires": { "sprintf-js": "~1.0.2" @@ -422,7 +1170,7 @@ "arr-flatten": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "integrity": "sha1-NgSLv/TntH4TZkQxbJlmnqWukfE=", "dev": true }, "arr-union": { @@ -452,7 +1200,7 @@ "array-slice": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "integrity": "sha1-42jqFfibxwaff/uJrsOmx9SsItQ=", "dev": true }, "array-union": { @@ -479,7 +1227,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 }, "arrify": { @@ -519,7 +1267,7 @@ "ast-types": { "version": "0.11.5", "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.11.5.tgz", - "integrity": "sha512-oJjo+5e7/vEc2FBK8gUalV0pba4L3VdBIs2EKhOLHLcOd2FgQIVQN9xb0eZ9IjEWyAL7vq6fGJxOvVvdCHNyMw==", + "integrity": "sha1-mJCCXWYMA8KDOfMV6foKNg4x7Cg=", "dev": true, "optional": true }, @@ -548,7 +1296,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": { @@ -626,7 +1374,7 @@ "base": { "version": "0.11.2", "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "integrity": "sha1-e95c7RRbbVUakNuH+DxVi060io8=", "dev": true, "requires": { "cache-base": "^1.0.1", @@ -650,7 +1398,7 @@ "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -659,7 +1407,7 @@ "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -668,7 +1416,7 @@ "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", @@ -851,7 +1599,7 @@ "bl": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz", - "integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==", + "integrity": "sha1-oWCRFxcQPAdBDO9j71Gzl8Alr5w=", "dev": true, "requires": { "readable-stream": "^2.3.5", @@ -882,7 +1630,7 @@ "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -977,7 +1725,7 @@ "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "integrity": "sha1-PH/L9SnYcibz0vUrlm/1Jx60Qd0=", "dev": true, "requires": { "balanced-match": "^1.0.0", @@ -987,7 +1735,7 @@ "braces": { "version": "2.3.2", "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "integrity": "sha1-WXn9PxTNUxVl5fot8av/8d+u5yk=", "dev": true, "requires": { "arr-flatten": "^1.1.0", @@ -1026,7 +1774,7 @@ "buffer-alloc": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", - "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "integrity": "sha1-iQ3ZDZI6hz4I4Q5f1RpX5bfM4Ow=", "dev": true, "requires": { "buffer-alloc-unsafe": "^1.1.0", @@ -1036,7 +1784,7 @@ "buffer-alloc-unsafe": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", - "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "integrity": "sha1-vX3CauKXLQ7aJTvgYdupkjScGfA=", "dev": true }, "buffer-crc32": { @@ -1105,7 +1853,7 @@ "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -1179,7 +1927,7 @@ "cache-base": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "integrity": "sha1-Cn9GQWgxyLZi7jb+TnxZ129marI=", "dev": true, "requires": { "collection-visit": "^1.0.0", @@ -1248,6 +1996,12 @@ "integrity": "sha512-Rf9Sbm2KS7s6Rk8iNeI5zJdquqctXBXAfy/bb1tCCYRds5RAaHNdyt2D4z8TSRToDkYsAwiSBV/bFHR+4IgTiw==", "dev": true }, + "caniuse-lite": { + "version": "1.0.30000889", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000889.tgz", + "integrity": "sha512-MFxcQ6x/LEEoaIhO7Zdb7Eg8YyNONN+WBnS5ERJ0li2yRw51+i4xXUNxnLaveTb/4ZoJqsWKEmlomhG2pYzlQA==", + "dev": true + }, "canonical-path": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/canonical-path/-/canonical-path-0.0.2.tgz", @@ -1375,7 +2129,7 @@ "clap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.3.tgz", - "integrity": "sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==", + "integrity": "sha1-TzZ0WzIAhJJVf0ZBLWbVDLmbzlE=", "dev": true, "requires": { "chalk": "^1.1.3" @@ -1384,7 +2138,7 @@ "class-utils": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "integrity": "sha1-+TNprouafOAv1B+q0MqDAzGQxGM=", "dev": true, "requires": { "arr-union": "^3.1.0", @@ -1459,7 +2213,7 @@ "cloneable-readable": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.2.tgz", - "integrity": "sha512-Bq6+4t+lbM8vhTs/Bef5c5AdEMtapp/iFb6+s4/Hh9MVTt8OLKH7ZOOZSCT+Ys7hsHvqv0GuMPJ1lnQJVHvxpg==", + "integrity": "sha1-1ZHe5Kj4vBXaQ86X3O66E9Q+KmU=", "dev": true, "requires": { "inherits": "^2.0.1", @@ -1491,7 +2245,7 @@ "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -1562,7 +2316,7 @@ "color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "integrity": "sha1-k4NDeaHMmgxh+C9S8NBDIiUb1aI=", "dev": true }, "colormin": { @@ -1720,7 +2474,7 @@ "concat-with-sourcemaps": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz", - "integrity": "sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==", + "integrity": "sha1-1OqT8FriV5CVG5nns7CeOQikCC4=", "dev": true, "requires": { "source-map": "^0.6.1" @@ -1729,7 +2483,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", "dev": true } } @@ -1844,7 +2598,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 }, "convert-source-map": { @@ -1887,7 +2641,7 @@ "core-js": { "version": "2.5.7", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz", - "integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw==", + "integrity": "sha1-+XJgj/DOrWi4QaFqky0LGDeRgU4=", "dev": true }, "core-util-is": { @@ -1899,7 +2653,7 @@ "cosmiconfig": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-2.2.2.tgz", - "integrity": "sha512-GiNXLwAFPYHy25XmTPpafYvn3CLAkJ8FLsscq78MQd1Kh0OU6Yzhn4eV2MVF4G9WEQZoWEGltatdR+ntGPMl5A==", + "integrity": "sha1-YXPOvVb6wELB9DkO33r2wHx8uJI=", "dev": true, "requires": { "is-directory": "^0.3.1", @@ -2123,7 +2877,7 @@ "data-uri-to-buffer": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-1.2.0.tgz", - "integrity": "sha512-vKQ9DTQPN1FLYiiEEOQ6IBGFqvjCa5rSK3cWMy/Nespm5d/x3dGFT9UBZnkLxCwua/IXBi2TYnwTEpsOvhC4UQ==", + "integrity": "sha1-dxY+qcINhkG0cH6PGKvfmnjzSDU=", "dev": true, "optional": true }, @@ -2142,7 +2896,7 @@ "debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", "dev": true, "requires": { "ms": "2.0.0" @@ -2371,7 +3125,7 @@ "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -2646,7 +3400,7 @@ "deep-extend": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "integrity": "sha1-xPp8lUBKF6nD6Mp+FTcxK3NjMKw=", "dev": true }, "deep-is": { @@ -2676,7 +3430,7 @@ "define-property": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "integrity": "sha1-1Flono1lS6d+AqgX+HENcCyxbp0=", "dev": true, "requires": { "is-descriptor": "^1.0.2", @@ -2686,7 +3440,7 @@ "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -2695,7 +3449,7 @@ "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -2704,7 +3458,7 @@ "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", @@ -3075,7 +3829,7 @@ "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -3156,7 +3910,7 @@ "duplexify": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.0.tgz", - "integrity": "sha512-fO3Di4tBKJpYTFHAxTU00BcfWMY9w24r/x21a6rZRbsD/ToUgGxsMbiGRmB7uVAXeGKXD9MwiLZa5E97EVgIRQ==", + "integrity": "sha1-WSkD9dgLONA3IgVBJk1poZj7NBA=", "dev": true, "requires": { "end-of-stream": "^1.0.0", @@ -3168,7 +3922,7 @@ "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "integrity": "sha1-7SljTRm6ukY7bOa4CjchPqtx7EM=", "dev": true, "requires": { "once": "^1.4.0" @@ -3198,7 +3952,7 @@ "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -3276,7 +4030,7 @@ "engine.io": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.1.5.tgz", - "integrity": "sha512-D06ivJkYxyRrcEe0bTpNnBQNgP9d3xog+qZlLbui8EsMr/DouQpf5o9FzJnWYHEYE0YsFHllUv2R1dkgYZXHcA==", + "integrity": "sha1-Dn751pDrCzVZfx1K0Comyi26OEU=", "dev": true, "requires": { "accepts": "~1.3.4", @@ -3307,7 +4061,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" @@ -3324,7 +4078,7 @@ "engine.io-client": { "version": "3.1.6", "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.1.6.tgz", - "integrity": "sha512-hnuHsFluXnsKOndS4Hv6SvUrgdYx1pk2NqfaDMW+GWdgfU3+/V25Cj7I8a0x92idSpa5PIhJRKxPvp9mnoLsfg==", + "integrity": "sha1-W96xMPi5SlCsXL63JYPnpKBj3f0=", "dev": true, "requires": { "component-emitter": "1.2.1", @@ -3343,7 +4097,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" @@ -3354,7 +4108,7 @@ "engine.io-parser": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.2.tgz", - "integrity": "sha512-dInLFzr80RijZ1rGpx1+56/uFoH7/7InhH3kZt+Ms6hT8tNx3NGW/WNSA/f8As1WkOfkuyb3tnRyuXGxusclMw==", + "integrity": "sha1-TA9M/3mq7su9z96maoI8YIVAkZY=", "dev": true, "requires": { "after": "0.8.2", @@ -3380,7 +4134,7 @@ "errno": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", - "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "integrity": "sha1-RoTXF3mtOa8Xfj8AeZb3xnyFJhg=", "dev": true, "optional": true, "requires": { @@ -3427,7 +4181,7 @@ "es-abstract": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.12.0.tgz", - "integrity": "sha512-C8Fx/0jFmV5IPoMOFPA9P9G5NtqW+4cOPit3MIuvR2t7Ag2K15EJTpxnHAYTzL+aYQJIESYeXZmDBfOBE1HcpA==", + "integrity": "sha1-nbvdJ8aFbwABQhyhh4LXhr+KYWU=", "dev": true, "requires": { "es-to-primitive": "^1.1.1", @@ -3749,13 +4503,13 @@ "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": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/exec-buffer/-/exec-buffer-3.2.0.tgz", - "integrity": "sha512-wsiD+2Tp6BWHoVv3B+5Dcx6E7u5zky+hUwOHjuH2hKSLR3dvRmX8fk8UD8uqQixHs4Wk6eDmiegVrMPjKj7wpA==", + "integrity": "sha1-sWhtvZBMfPmC5lLB9aebHlVzCCs=", "dev": true, "optional": true, "requires": { @@ -3940,7 +4694,7 @@ "fill-range": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", - "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "integrity": "sha1-6x53OrsFbc2N8r/favWbizqTZWU=", "dev": true, "requires": { "is-number": "^2.1.0", @@ -4056,7 +4810,7 @@ "is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "dev": true, "requires": { "is-plain-object": "^2.0.4" @@ -4089,7 +4843,7 @@ "extglob": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "integrity": "sha1-rQD+TcYSqSMuhxhxHcXLWrAoVUM=", "dev": true, "requires": { "array-unique": "^0.3.2", @@ -4123,7 +4877,7 @@ "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -4132,7 +4886,7 @@ "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -4141,7 +4895,7 @@ "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", @@ -4264,7 +5018,7 @@ "file-uri-to-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "integrity": "sha1-VTp7hEb/b2hDWcRF8eN6BdrMM90=", "dev": true, "optional": true }, @@ -4459,7 +5213,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" @@ -4523,7 +5277,7 @@ "fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "integrity": "sha1-a+Dem+mYzhavivwkSXue6bfM2a0=", "dev": true }, "fs-extra": { @@ -5111,7 +5865,7 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "integrity": "sha1-pWiZ0+o8m6uHS7l3O3xe3pL0iV0=", "dev": true }, "functional-red-black-tree": { @@ -5174,7 +5928,7 @@ "get-uri": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-2.0.2.tgz", - "integrity": "sha512-ZD325dMZOgerGqF/rF6vZXyFGTAay62svjQIT+X/oU2PtxYpFxvSkbsdi+oxIrsNxlZVd4y8wUDqkaExWTI/Cw==", + "integrity": "sha1-XHlecTJvbKEoby/IJXXNK6sq9Xg=", "dev": true, "optional": true, "requires": { @@ -5212,7 +5966,7 @@ "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, "optional": true, "requires": { @@ -5396,7 +6150,7 @@ "global-modules": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "integrity": "sha1-bXcPDrUjrHgWTXK15xqIdyZcw+o=", "dev": true, "requires": { "global-prefix": "^1.0.1", @@ -5492,7 +6246,7 @@ "glogg": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.1.tgz", - "integrity": "sha512-ynYqXLoluBKf9XGR1gA59yEJisIL7YHEH4xr3ZziHB5/yl4qWfaK8Js9jGe6gBGCSCKVqiyO30WnRZADvemUNw==", + "integrity": "sha1-3PdY5EeJzD89MsHzVio2duajSBA=", "dev": true, "requires": { "sparkles": "^1.0.0" @@ -5606,6 +6360,26 @@ } } }, + "gulp-babel": { + "version": "8.0.0-beta.2", + "resolved": "http://registry.npmjs.org/gulp-babel/-/gulp-babel-8.0.0-beta.2.tgz", + "integrity": "sha512-GTC2PxAXWkp6u1fP+C5+kn5biQ0dKGhkOSSXvKAf3ykF0+R3tevmLm/zSIkc1+S7U1JwH3XTvuMwRL6LD+sEiw==", + "dev": true, + "requires": { + "plugin-error": "^1.0.1", + "replace-ext": "^1.0.0", + "through2": "^2.0.0", + "vinyl-sourcemaps-apply": "^0.2.0" + }, + "dependencies": { + "replace-ext": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", + "dev": true + } + } + }, "gulp-concat": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/gulp-concat/-/gulp-concat-2.6.1.tgz", @@ -5700,7 +6474,7 @@ "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -5722,7 +6496,7 @@ "gulp-imagemin": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/gulp-imagemin/-/gulp-imagemin-4.1.0.tgz", - "integrity": "sha512-6nWkrMNY5ub+34+DwlgQdWg21Z4DWAOARLpnyuZ773pGPJrfiyQrkOzdz9DgQSGBQjU1zuw6gd+9clLi6eicuw==", + "integrity": "sha1-XONH8dFwb+08yPF3fKkJSlg7ULc=", "dev": true, "requires": { "chalk": "^2.1.0", @@ -5741,7 +6515,7 @@ "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "integrity": "sha1-QfuyAkPlCxK+DwS43tvwdSDOhB0=", "dev": true, "requires": { "color-convert": "^1.9.0" @@ -5772,7 +6546,7 @@ "chalk": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", - "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", + "integrity": "sha1-GMSasWoDe26wFSzIPjRxM4IVtm4=", "dev": true, "requires": { "ansi-styles": "^3.2.1", @@ -5828,7 +6602,7 @@ "gulp-less": { "version": "3.5.0", "resolved": "https://registry.npmjs.org/gulp-less/-/gulp-less-3.5.0.tgz", - "integrity": "sha512-FQLY7unaHdTOXG0jlwxeBQcWoPPrTMQZRA7HfYwSNi9IPVx5l7GJEN72mG4ri2yigp/f/VNGUAJnFMJHBmH3iw==", + "integrity": "sha1-gBT0ad38ZUTX3aUAmN7wNxu7T3g=", "dev": true, "requires": { "accord": "^0.28.0", @@ -6192,7 +6966,7 @@ "gulp-open": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/gulp-open/-/gulp-open-2.1.0.tgz", - "integrity": "sha512-JzFlG7szoFyjNtlo6f7JnkaNOm0ZaYKofSGvs+4YRI4G+oTknJDn8N14Ocau06yJA1eQoFSOQVHhVWqas1cnHA==", + "integrity": "sha1-rAHu6JjXenrAgS+tTz1T0IaH1Bw=", "dev": true, "requires": { "colors": "^1.1.2", @@ -6351,7 +7125,7 @@ "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -6486,7 +7260,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" @@ -6638,7 +7412,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", @@ -6649,7 +7423,7 @@ "http-proxy-agent": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", - "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "integrity": "sha1-5IIb7vWyFCogJr1zkm/lN2McVAU=", "dev": true, "requires": { "agent-base": "4", @@ -6659,7 +7433,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" @@ -6697,7 +7471,7 @@ "https-proxy-agent": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.1.tgz", - "integrity": "sha512-HPCTS1LW51bcyMYbxUIOO4HEOlQ1/1qRaFWcyxvwaqUS9TY88aoEuHUY33kuAh1YhVVaDQhLZsnPd+XNARWZlQ==", + "integrity": "sha1-UVUpcPoE1yPgTFbQQXjD+SWSu8A=", "dev": true, "requires": { "agent-base": "^4.1.0", @@ -6778,7 +7552,7 @@ "imagemin-gifsicle": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/imagemin-gifsicle/-/imagemin-gifsicle-5.2.0.tgz", - "integrity": "sha512-K01m5QuPK+0en8oVhiOOAicF7KjrHlCZxS++mfLI2mV/Ksfq/Y9nCXCWDz6jRv13wwlqe5T7hXT+ji2DnLc2yQ==", + "integrity": "sha1-N4FSTEV2Eu8EkWrzQkGitCv8tAo=", "dev": true, "optional": true, "requires": { @@ -6814,7 +7588,7 @@ "imagemin-svgo": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/imagemin-svgo/-/imagemin-svgo-6.0.0.tgz", - "integrity": "sha512-xwjBZQKpbkklHtJYnCOwRJjTRJA/nR0hQzKMh+CUZRvm/L0QwKKPJQ9tkPWQHrg+cydPu2i1vLgHuy2E0hKEkg==", + "integrity": "sha1-LdjIKUa+Qqjiy8rjxb8Ae8K4ueg=", "dev": true, "optional": true, "requires": { @@ -6833,7 +7607,7 @@ "coa": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/coa/-/coa-2.0.1.tgz", - "integrity": "sha512-5wfTTO8E2/ja4jFSxePXlG5nRu5bBtL/r1HCIpJW/lzT6yDtKl0u0Z4o/Vpz32IpKmBn7HerheEZQgA9N2DarQ==", + "integrity": "sha1-8/iwsVBz411wJj+xBCyywCPbOK8=", "dev": true, "optional": true, "requires": { @@ -6850,7 +7624,7 @@ "csso": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/csso/-/csso-3.5.1.tgz", - "integrity": "sha512-vrqULLffYU1Q2tLdJvaCYbONStnfkfimRxXNaGjxMldI0C7JPBC4rB1RyjhfdZ4m1frm8pM9uRPKH3d2knZ8gg==", + "integrity": "sha1-e564vmFiiXPBsmHhadLwJACOdYs=", "dev": true, "optional": true, "requires": { @@ -6860,7 +7634,7 @@ "css-tree": { "version": "1.0.0-alpha.29", "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.0.0-alpha.29.tgz", - "integrity": "sha512-sRNb1XydwkW9IOci6iB2xmy8IGCj6r/fr+JWitvJ2JxQRPzN3T4AGGVWCMlVmVwM1gtgALJRmGIlWv5ppnGGkg==", + "integrity": "sha1-P6nU7zFCy9HDAedmTB81K9gvWjk=", "dev": true, "optional": true, "requires": { @@ -6873,7 +7647,7 @@ "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "integrity": "sha1-E7BM2z5sXRnfkatph6hpVhmwqnE=", "dev": true, "optional": true }, @@ -6972,7 +7746,7 @@ "ini": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "integrity": "sha1-7uJfVtscnsYIXgwid4CD9Zar+Sc=", "dev": true }, "inquirer": { @@ -7054,6 +7828,15 @@ "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", "dev": true }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, "ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", @@ -7082,7 +7865,7 @@ "is-absolute": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", - "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "integrity": "sha1-OV4a6EsR8mrReV5zwXN45IowFXY=", "dev": true, "requires": { "is-relative": "^1.0.0", @@ -7133,7 +7916,7 @@ "is-buffer": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "integrity": "sha1-76ouqdqg16suoTqXsritUf776L4=", "dev": true }, "is-builtin-module": { @@ -7154,7 +7937,7 @@ "is-callable": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "integrity": "sha1-HhrfIZ4e62hNaR+dagX/DTCiTXU=", "dev": true }, "is-data-descriptor": { @@ -7186,7 +7969,7 @@ "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "integrity": "sha1-Nm2CQN3kh8pRgjsaufB6EKeCUco=", "dev": true, "requires": { "is-accessor-descriptor": "^0.1.6", @@ -7197,7 +7980,7 @@ "kind-of": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "integrity": "sha1-cpyR4thXt6QZofmqZWhcTDP1hF0=", "dev": true } } @@ -7282,7 +8065,7 @@ "is-my-ip-valid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz", - "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==", + "integrity": "sha1-ezUbjo7dTTmV1NBmaA5mTZRpaCQ=", "dev": true, "optional": true }, @@ -7365,7 +8148,7 @@ "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "integrity": "sha1-LBY7P6+xtgbZ0Xko8FwqHDjgdnc=", "dev": true, "requires": { "isobject": "^3.0.1" @@ -7420,7 +8203,7 @@ "is-relative": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", - "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "integrity": "sha1-obtpNc6MXboei5dUubLcwCDiJg0=", "dev": true, "requires": { "is-unc-path": "^1.0.0" @@ -7477,7 +8260,7 @@ "is-unc-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", - "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "integrity": "sha1-1zHoiY7QkKEsNSrS6u1Qla0yLJ0=", "dev": true, "requires": { "unc-path-regex": "^0.1.2" @@ -7486,7 +8269,7 @@ "is-url": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/is-url/-/is-url-1.2.4.tgz", - "integrity": "sha512-ITvGim8FhRiYe4IQ5uHSkj7pVaPDrCTkNd3yq3cV7iZAcJdHTUMPMEHcqSOy9xZ9qFenQCvi+2wjH9a1nXqHww==", + "integrity": "sha1-BKTfRtKMTP89c9Af8Gq+sxihqlI=", "dev": true }, "is-utf8": { @@ -7504,7 +8287,7 @@ "is-windows": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "integrity": "sha1-0YUOuXkezRjmGCzhKjDzlmNLsZ0=", "dev": true }, "is-zip": { @@ -7570,6 +8353,12 @@ "integrity": "sha512-xcinL3AuDJk7VSzsHgb9DvvIXayBbadtMZ4HFPx8rUszbW1MuNMlwYVC4zzCZ6e1sqZpnNS5ZFYOhXqA39T7LQ==", "dev": true }, + "js-levenshtein": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.4.tgz", + "integrity": "sha512-PxfGzSs0ztShKrUYPIn5r0MtyAhYcCwmndozzpz8YObbPnD1jFxzlBGbRnX2mIu6Z13xN6+PTu05TQFnZFlzow==", + "dev": true + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -7593,6 +8382,12 @@ "dev": true, "optional": true }, + "jsesc": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.1.tgz", + "integrity": "sha1-5CGiqOINawgZ3yiQj3glJrlt0f4=", + "dev": true + }, "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", @@ -7626,6 +8421,12 @@ "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", "dev": true }, + "json5": { + "version": "0.5.1", + "resolved": "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz", + "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=", + "dev": true + }, "jsonfile": { "version": "2.4.0", "resolved": "http://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz", @@ -7829,7 +8630,7 @@ "iconv-lite": { "version": "0.4.23", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", - "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "integrity": "sha1-KXhx9jvlB63Pv8pxXQzQ7thOmmM=", "dev": true, "requires": { "safer-buffer": ">= 2.1.2 < 3" @@ -7847,7 +8648,7 @@ "qs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "integrity": "sha1-yzroBuh0BERYTvFUzo7pjUA/PjY=", "dev": true }, "range-parser": { @@ -7859,7 +8660,7 @@ "raw-body": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", - "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "integrity": "sha1-GzJOzmtXBuFThVvBFIxlu39uoMM=", "dev": true, "requires": { "bytes": "3.0.0", @@ -7871,7 +8672,7 @@ "source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "integrity": "sha1-dHIq8y6WFOnCh6jQu95IteLxomM=", "dev": true }, "utils-merge": { @@ -7907,7 +8708,7 @@ "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "integrity": "sha1-ARRrNqYhjmTljzqNZt5df8b20FE=", "dev": true }, "klaw": { @@ -7974,7 +8775,7 @@ "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -7985,7 +8786,7 @@ "less": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/less/-/less-2.7.3.tgz", - "integrity": "sha512-KPdIJKWcEAb02TuJtaLrhue0krtRLoRoo7x6BNJIBelO00t/CCdJQUnHW5V34OnHMWzIktSalJxRO+FvytQlCQ==", + "integrity": "sha1-zBJg9RyQCp7A2R+2mYE54CUHtjs=", "dev": true, "requires": { "errno": "^0.1.1", @@ -8067,7 +8868,7 @@ "livereload-js": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.3.0.tgz", - "integrity": "sha512-j1R0/FeGa64Y+NmqfZhyoVRzcFlOZ8sNlKzHjh4VvLULFACZhn68XrX5DFg2FhMvSMJmROuFxRSa560ECWKBMg==", + "integrity": "sha1-w6si6Kr1vzUF2A0JjLrWdyZUjJo=", "dev": true }, "load-json-file": { @@ -8305,7 +9106,7 @@ "lodash.merge": { "version": "4.6.1", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.1.tgz", - "integrity": "sha512-AOYza4+Hf5z1/0Hztxpm2/xiPZgi/cjMqdnKTUWTBSKchJlxXXuUSxCCl8rJlf4g6yww/j6mA8nC8Hw/EZWxKQ==", + "integrity": "sha1-rcJdnLmbk5HFliTzefu6YNcRHVQ=", "dev": true }, "lodash.partialright": { @@ -8597,6 +9398,15 @@ "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", "dev": true }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, "loud-rejection": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", @@ -8610,7 +9420,7 @@ "lowercase-keys": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "integrity": "sha1-b54wtHCE2XGnyCD/FabFFnt0wm8=", "dev": true }, "lpad-align": { @@ -8674,7 +9484,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, "optional": true, "requires": { @@ -8698,7 +9508,7 @@ "make-dir": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", - "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "integrity": "sha1-ecEDO4BRW9bSTsmTPoYMp17ifww=", "dev": true, "requires": { "pify": "^3.0.0" @@ -8715,7 +9525,7 @@ "make-iterator": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", - "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "integrity": "sha1-KbM/MSqo9UfEpeSQ9Wr87JkTOtY=", "dev": true, "requires": { "kind-of": "^6.0.2" @@ -8769,7 +9579,7 @@ "mdn-data": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-1.1.4.tgz", - "integrity": "sha512-FSYbp3lyKjyj3E7fMl6rYvUdX0FBXaluGqlFoYESWQlyUTq8R+wp0rkFxoYFqZlHCvsUXGjyJmLQSnXToYhOSA==", + "integrity": "sha1-ULXU/8RXUnZXPE7tuHgIEqhBnwE=", "dev": true }, "media-typer": { @@ -8837,7 +9647,7 @@ "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -8874,7 +9684,7 @@ "micromatch": { "version": "3.1.10", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "integrity": "sha1-cIWbyVyYQJUvNZoGij/En57PrCM=", "dev": true, "requires": { "arr-diff": "^4.0.0", @@ -8922,7 +9732,7 @@ "minimatch": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "integrity": "sha1-UWbihkV/AzBgZL5Ul+jbsMPTIIM=", "dev": true, "requires": { "brace-expansion": "^1.1.7" @@ -8937,7 +9747,7 @@ "mixin-deep": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", - "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "integrity": "sha1-pJ5yaNzhoNlpjkUybFYm3zVD0P4=", "dev": true, "requires": { "for-in": "^1.0.2", @@ -8947,7 +9757,7 @@ "is-extendable": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "integrity": "sha1-p0cPnkJnM9gb2B4RVSZOOjUHyrQ=", "dev": true, "requires": { "is-plain-object": "^2.0.4" @@ -9088,6 +9898,23 @@ "integrity": "sha1-MjI8zLRsn78PwRgS1FAhzDHTJbs=", "dev": true }, + "node-releases": { + "version": "1.0.0-alpha.12", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.0.0-alpha.12.tgz", + "integrity": "sha512-VPB4rTPqpVyWKBHbSa4YPFme3+8WHsOSpvbp0Mfj0bWsC8TEjt4HQrLl1hsBDELlp1nB4lflSgSuGTYiuyaP7Q==", + "dev": true, + "requires": { + "semver": "^5.3.0" + }, + "dependencies": { + "semver": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.1.tgz", + "integrity": "sha512-PqpAxfrEhlSUWge8dwIp4tZnQ25DIOthpiaHNIthsjEFQD6EvqUKUDM7L8O2rShkFccYo1VjJR0coWfNkCubRw==", + "dev": true + } + } + }, "node-status-codes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-status-codes/-/node-status-codes-1.0.0.tgz", @@ -9207,7 +10034,7 @@ "normalize-package-data": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", - "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "integrity": "sha1-EvlaMH1YNSB1oEkHuErIvpisAS8=", "dev": true, "requires": { "hosted-git-info": "^2.1.4", @@ -12023,7 +12850,7 @@ "object-keys": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.12.tgz", - "integrity": "sha512-FTMyFUm2wBcGHnH2eXmz7tC6IwlqQZ6mVZ+6dm6vZ4IQIHjs6FdNsQBuKGPuUUUY6NfJw2PshC08Tn6LzLDOag==", + "integrity": "sha1-CcU4VTd1dTEMymL1W7M0q/97PtI=", "dev": true }, "object-visit": { @@ -12299,7 +13126,7 @@ "iconv-lite": { "version": "0.4.23", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", - "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", + "integrity": "sha1-KXhx9jvlB63Pv8pxXQzQ7thOmmM=", "dev": true, "optional": true, "requires": { @@ -12316,7 +13143,7 @@ "raw-body": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", - "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", + "integrity": "sha1-GzJOzmtXBuFThVvBFIxlu39uoMM=", "dev": true, "optional": true, "requires": { @@ -12331,7 +13158,7 @@ "pac-resolver": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-3.0.0.tgz", - "integrity": "sha512-tcc38bsjuE3XZ5+4vP96OfhOugrX+JcnpUbhfuc4LuXBLQhoTthOstZeoQJBDnQUDYzYmdImKsbz0xSl1/9qeA==", + "integrity": "sha1-auoweH2wqJFwTet4AKcip2FabyY=", "dev": true, "optional": true, "requires": { @@ -12671,7 +13498,7 @@ "postcss": { "version": "5.2.18", "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", + "integrity": "sha1-ut+hSX1GJE9jkPWLMZgw2RB4U8U=", "dev": true, "requires": { "chalk": "^1.1.3", @@ -13025,10 +13852,16 @@ "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", "dev": true }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true + }, "process-nextick-args": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", - "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "integrity": "sha1-o31zL0JxtKsa0HDTVQjoKQeI/6o=", "dev": true }, "progress": { @@ -13040,7 +13873,7 @@ "promise": { "version": "7.3.1", "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", - "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "integrity": "sha1-BktyYCsY+Q8pGSuLG8QY/9Hr078=", "dev": true, "optional": true, "requires": { @@ -13087,7 +13920,7 @@ "lru-cache": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz", - "integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==", + "integrity": "sha1-oRdc80lt/IQ2wVbDNLSVWZK85pw=", "dev": true, "optional": true, "requires": { @@ -13140,7 +13973,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": { @@ -13218,7 +14051,7 @@ "rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "integrity": "sha1-zZJL9SAKB1uDwYjNa54hG3/A0+0=", "dev": true, "requires": { "deep-extend": "^0.6.0", @@ -13269,7 +14102,7 @@ "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -13381,7 +14214,7 @@ "redis": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/redis/-/redis-2.8.0.tgz", - "integrity": "sha512-M1OkonEQwtRmZv4tEWF2VgpG0JWJ8Fv1PhlgT5+B+uNq2cA3Rt1Yt/ryoR+vQNOQcIEgdCdfH0jr3bDpihAw1A==", + "integrity": "sha1-ICKI4/WMSfYHnZevehDhMDrhSwI=", "dev": true, "optional": true, "requires": { @@ -13393,7 +14226,7 @@ "redis-commands": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.3.5.tgz", - "integrity": "sha512-foGF8u6MXGFF++1TZVC6icGXuMYPftKXt1FBT2vrfU9ZATNtZJ8duRC5d1lEfE8hyVe3jhelHGB91oB7I6qLsA==", + "integrity": "sha1-RJWIlBTx6IYmEYCxRC5ylWAtg6I=", "dev": true, "optional": true }, @@ -13440,10 +14273,34 @@ } } }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-7.0.0.tgz", + "integrity": "sha512-s5NGghCE4itSlUS+0WUj88G6cfMVMmH8boTPNvABf8od+2dhT9WDlWu8n01raQAJZMOK8Ch6jSexaRO7swd6aw==", + "dev": true, + "requires": { + "regenerate": "^1.4.0" + } + }, + "regenerator-transform": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.13.3.tgz", + "integrity": "sha512-5ipTrZFSq5vU2YoGoww4uaRVAK4wyYC4TSICibbfEPOruUu8FFP7ErV0BjmbIOEpn3O/k9na9UEdYR/3m7N6uA==", + "dev": true, + "requires": { + "private": "^0.1.6" + } + }, "regex-cache": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", - "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "integrity": "sha1-db3FiioUls7EihKDW8VMjVYjNt0=", "dev": true, "requires": { "is-equal-shallow": "^0.1.3" @@ -13452,7 +14309,7 @@ "regex-not": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "integrity": "sha1-H07OJ+ALC2XgJHpoEOaoXYOldSw=", "dev": true, "requires": { "extend-shallow": "^3.0.2", @@ -13465,6 +14322,43 @@ "integrity": "sha512-g2FAVtR8Uh8GO1Nv5wpxW7VFVwHcCEr4wyA8/MHiRkO8uHoR5ntAA8Uq3P1vvMTX/BeQiRVSpDGLd+Wn5HNOTA==", "dev": true }, + "regexpu-core": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.2.0.tgz", + "integrity": "sha512-Z835VSnJJ46CNBttalHD/dB+Sj2ezmY6Xp38npwU87peK6mqOzOpV8eYktdkLTEkzzD+JsTcxd84ozd8I14+rw==", + "dev": true, + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^7.0.0", + "regjsgen": "^0.4.0", + "regjsparser": "^0.3.0", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.0.2" + } + }, + "regjsgen": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.4.0.tgz", + "integrity": "sha512-X51Lte1gCYUdlwhF28+2YMO0U6WeN0GLpgpA7LK7mbdDnkQYiwvEpmpe0F/cv5L14EbxgrdayAG3JETBv0dbXA==", + "dev": true + }, + "regjsparser": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.3.0.tgz", + "integrity": "sha512-zza72oZBBHzt64G7DxdqrOo/30bhHkwMUoT0WqfGu98XLd7N+1tsy5MJ96Bk4MD0y74n629RhmrGW6XlnLLwCA==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + } + } + }, "remove-trailing-separator": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", @@ -13557,7 +14451,7 @@ "requestretry": { "version": "1.13.0", "resolved": "https://registry.npmjs.org/requestretry/-/requestretry-1.13.0.tgz", - "integrity": "sha512-Lmh9qMvnQXADGAQxsXHP4rbgO6pffCfuR8XUBdP9aitJcLQJxhp7YZK4xAVYXnPJ5E52mwrfiKQtKonPL8xsmg==", + "integrity": "sha1-IT7BAG7rdQ6LjOVBdig9FajVXZQ=", "dev": true, "optional": true, "requires": { @@ -13651,7 +14545,7 @@ "ret": { "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "integrity": "sha1-uKSCXVvbH8P29Twrwz+BOIaBx7w=", "dev": true }, "right-align": { @@ -13666,7 +14560,7 @@ "rimraf": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", - "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "integrity": "sha1-LtgVDSShbqhlHm1u8PR8QVjOejY=", "dev": true, "requires": { "glob": "^7.0.5" @@ -13690,7 +14584,7 @@ "run-sequence": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/run-sequence/-/run-sequence-2.2.1.tgz", - "integrity": "sha512-qkzZnQWMZjcKbh3CNly2srtrkaO/2H/SI5f2eliMCapdRD3UhMrwjfOAZJAnZ2H8Ju4aBzFZkBGXUqFs9V0yxw==", + "integrity": "sha1-HOZD2jb9jH6n4akynaM/wriJhJU=", "dev": true, "requires": { "chalk": "^1.1.3", @@ -13762,7 +14656,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=", "dev": true }, "safe-regex": { @@ -13777,13 +14671,13 @@ "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=", "dev": true }, "sax": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "integrity": "sha1-KBYjTiN4vdxOU1T6tcqold9xANk=", "dev": true }, "seek-bzip": { @@ -13954,7 +14848,7 @@ "set-value": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", - "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "integrity": "sha1-ca5KiPD+77v1LR6mBPP7MV67YnQ=", "dev": true, "requires": { "extend-shallow": "^2.0.1", @@ -13977,7 +14871,7 @@ "setprototypeof": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "integrity": "sha1-0L2FU2iHtv58DYGMuWLZ2RxU5lY=", "dev": true }, "shebang-command": { @@ -14051,7 +14945,7 @@ "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "integrity": "sha1-ZJIufFZbDhQgS6GqfWlkJ40lGC0=", "dev": true, "requires": { "base": "^0.11.1", @@ -14087,7 +14981,7 @@ "snapdragon-node": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "integrity": "sha1-bBdfhv8UvbByRWPo88GwIaKGhTs=", "dev": true, "requires": { "define-property": "^1.0.0", @@ -14107,7 +15001,7 @@ "is-accessor-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "integrity": "sha1-FpwvbT3x+ZJhgHI2XJsOofaHhlY=", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -14116,7 +15010,7 @@ "is-data-descriptor": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "integrity": "sha1-2Eh2Mh0Oet0DmQQGq7u9NrqSaMc=", "dev": true, "requires": { "kind-of": "^6.0.0" @@ -14125,7 +15019,7 @@ "is-descriptor": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "integrity": "sha1-OxWXRqZmBLBPjIFSS6NlxfFNhuw=", "dev": true, "requires": { "is-accessor-descriptor": "^1.0.0", @@ -14138,7 +15032,7 @@ "snapdragon-util": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "integrity": "sha1-+VZHlIbyrNeXAGk/b3uAXkWrVuI=", "dev": true, "requires": { "kind-of": "^3.2.0" @@ -14207,7 +15101,7 @@ "socket.io-parser": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.1.3.tgz", - "integrity": "sha512-g0a2HPqLguqAczs3dMECuA1RgoGFPyvDqcbaDEdCWY9g59kdUAz3YRmaJBNKXflrHNwB7Q12Gkf/0CZXfdHR7g==", + "integrity": "sha1-7S2l7nnxCVUDbj2kE7/X8eTYbI4=", "dev": true, "requires": { "component-emitter": "1.2.1", @@ -14219,7 +15113,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" @@ -14312,7 +15206,7 @@ "spdx-expression-parse": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "integrity": "sha1-meEZt6XaAOBUkcn6M4t5BII7QdA=", "dev": true, "requires": { "spdx-exceptions": "^2.1.0", @@ -14337,7 +15231,7 @@ "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "integrity": "sha1-fLCd2jqGWFcFxks5pkZgOGguj+I=", "dev": true, "requires": { "extend-shallow": "^3.0.0" @@ -14389,7 +15283,7 @@ "stable": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", + "integrity": "sha1-g26zyDgv4pNv6vVEYxAXzn1Ho88=", "dev": true, "optional": true }, @@ -14479,7 +15373,7 @@ "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -14490,7 +15384,7 @@ "stream-consume": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.1.tgz", - "integrity": "sha512-tNa3hzgkjEP7XbCkbRXe1jpg+ievoa0O4SCFlMOYEscGSS4JJsckGL8swUyAa/ApGU3Ae4t6Honor4HhL+tRyg==", + "integrity": "sha1-0721mMK9CugrjKx6xQsRB6eZbEg=", "dev": true }, "stream-counter": { @@ -14511,7 +15405,7 @@ "streamroller": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-0.7.0.tgz", - "integrity": "sha512-WREzfy0r0zUqp3lGO096wRuUp7ho1X6uo/7DJfTlEi0Iv/4gT7YHqXDjKC2ioVGBZtE8QzsQD9nx1nIuoZ57jQ==", + "integrity": "sha1-odG3z4PTmvsNYwSaWsv5NJO99ks=", "dev": true, "requires": { "date-format": "^1.2.0", @@ -14559,7 +15453,7 @@ "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -14714,7 +15608,7 @@ "strip-outer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", - "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", + "integrity": "sha1-sv0qv2YEudHmATBXGV34Nrip1jE=", "dev": true, "requires": { "escape-string-regexp": "^1.0.2" @@ -14763,7 +15657,7 @@ }, "table": { "version": "4.0.3", - "resolved": "http://registry.npmjs.org/table/-/table-4.0.3.tgz", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.3.tgz", "integrity": "sha512-S7rnFITmBH1EnyKcvxBh1LjYeQMmnZtCXSEbHcH6S0NoKit24ZuFO/T1vDcLdYsLQkM188PVVhQmzKIuThNkKg==", "dev": true, "requires": { @@ -14830,7 +15724,7 @@ "end-of-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", - "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "integrity": "sha1-7SljTRm6ukY7bOa4CjchPqtx7EM=", "dev": true, "requires": { "once": "^1.4.0" @@ -14860,7 +15754,7 @@ "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -14938,7 +15832,7 @@ "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -15084,7 +15978,7 @@ "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "integrity": "sha1-bTQzWIl2jSGyvNoKonfO07G/rfk=", "dev": true, "requires": { "os-tmpdir": "~1.0.2" @@ -15119,7 +16013,13 @@ "to-buffer": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", - "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==", + "integrity": "sha1-STvUj2LXxD/N7TE6A9ytsuEhOoA=", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", "dev": true }, "to-object-path": { @@ -15145,7 +16045,7 @@ "to-regex": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "integrity": "sha1-E8/dmzNlUvMLUfM6iuG0Knp1mc4=", "dev": true, "requires": { "define-property": "^2.0.2", @@ -15167,7 +16067,7 @@ "tough-cookie": { "version": "2.3.4", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", - "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "integrity": "sha1-7GDO44rGdQY//JelwYlwV47oNlU=", "dev": true, "requires": { "punycode": "^1.4.1" @@ -15196,6 +16096,12 @@ "escape-string-regexp": "^1.0.2" } }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, "tryit": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/tryit/-/tryit-1.0.3.tgz", @@ -15239,7 +16145,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", @@ -15282,7 +16188,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": { @@ -15297,6 +16203,34 @@ "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=", "dev": true }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.0.2.tgz", + "integrity": "sha512-Rx7yODZC1L/T8XKo/2kNzVAQaRE88AaMvI1EF/Xnj3GW2wzN6fop9DDWuFAKUVFH7vozkz26DzP0qyWLKLIVPQ==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.4.tgz", + "integrity": "sha512-2WSLa6OdYd2ng8oqiGIWnJqyFArvhn+5vgx5GTxMbUYjCYKUcuKS62YLFF0R/BDGlB1yzXjQOLtPAfHsgirEpg==", + "dev": true + }, "union-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", @@ -15494,7 +16428,7 @@ "util.promisify": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", - "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "integrity": "sha1-RA9xZaRZyaFtwUXrjnLzVocJcDA=", "dev": true, "optional": true, "requires": { @@ -15517,7 +16451,7 @@ "uws": { "version": "9.14.0", "resolved": "https://registry.npmjs.org/uws/-/uws-9.14.0.tgz", - "integrity": "sha512-HNMztPP5A1sKuVFmdZ6BPVpBQd5bUjNC8EFMFiICK+oho/OQsAJy5hnIx4btMHiOk8j04f/DbIlqnEZ9d72dqg==", + "integrity": "sha1-+sg4a+/DOno3BcvVjcR7Qwyk3ZU=", "dev": true, "optional": true }, @@ -15555,7 +16489,7 @@ "vendors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.2.tgz", - "integrity": "sha512-w/hry/368nO21AN9QljsaIhb9ZiZtZARoVH5f3CsFbawdLdayCgKRPup7CggujvySMxx0I91NOyxdVENohprLQ==", + "integrity": "sha1-f8te759WI7FWvOqJ7DfWNnbyGAE=", "dev": true }, "verror": { @@ -15628,7 +16562,7 @@ "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", "dev": true, "requires": { "safe-buffer": "~5.1.0" @@ -15829,7 +16763,7 @@ "websocket-extensions": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", - "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", + "integrity": "sha1-XS/yKXcAPsaHpLhwc9+7rBRszyk=", "dev": true }, "when": { @@ -15899,7 +16833,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", diff --git a/src/Umbraco.Web.UI.Client/package.json b/src/Umbraco.Web.UI.Client/package.json index c05401a05c..c9f91b3c3c 100644 --- a/src/Umbraco.Web.UI.Client/package.json +++ b/src/Umbraco.Web.UI.Client/package.json @@ -8,10 +8,13 @@ "npm": "^6.4.1" }, "devDependencies": { + "@babel/core": "^7.1.2", + "@babel/preset-env": "^7.1.0", "autoprefixer": "^6.5.0", "bower-installer": "^1.2.0", "cssnano": "^3.7.6", "gulp": "^3.9.1", + "gulp-babel": "^8.0.0-beta.2", "gulp-concat": "^2.6.0", "gulp-connect": "5.0.0", "gulp-eslint": "^5.0.0", From 6dfb1e7e830455b22566587c703cfe39a90a1fb3 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Sun, 7 Oct 2018 20:01:54 +0200 Subject: [PATCH 25/44] await is a reserved word --- .../directives/components/grid/grid.rte.directive.js | 8 ++++---- .../src/views/propertyeditors/rte/rte.controller.js | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/grid/grid.rte.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/grid/grid.rte.directive.js index e18137085b..9bdf94d245 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/grid/grid.rte.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/grid/grid.rte.directive.js @@ -44,11 +44,11 @@ angular.module("umbraco.directives") var stylesheets = []; var styleFormats = []; - var await = []; + var requests = []; //queue file loading if (typeof (tinymce) === "undefined") { - await.push(assetsService.loadJs("lib/tinymce/tinymce.min.js", scope)); + requests.push(assetsService.loadJs("lib/tinymce/tinymce.min.js", scope)); } @@ -61,7 +61,7 @@ angular.module("umbraco.directives") angular.forEach(scope.configuration.stylesheets, function(stylesheet, key){ stylesheets.push(Umbraco.Sys.ServerVariables.umbracoSettings.cssPath + "/" + stylesheet + ".css"); - await.push(stylesheetResource.getRulesByName(stylesheet).then(function (rules) { + requests.push(stylesheetResource.getRulesByName(stylesheet).then(function (rules) { angular.forEach(rules, function (rule) { var r = {}; var split = ""; @@ -97,7 +97,7 @@ angular.module("umbraco.directives") //stores a reference to the editor var tinyMceEditor = null; - $q.all(await).then(function () { + $q.all(requests).then(function () { var uniqueId = scope.uniqueId; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js index 93083bf2a6..8dfe7b1feb 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js @@ -84,20 +84,20 @@ angular.module("umbraco") var toolbar = editorConfig.toolbar.join(" | "); var stylesheets = []; var styleFormats = []; - var await = []; + var requests = []; if (!editorConfig.maxImageSize && editorConfig.maxImageSize != 0) { editorConfig.maxImageSize = tinyMceService.defaultPrevalues().maxImageSize; } //queue file loading if (typeof tinymce === "undefined") { // Don't reload tinymce if already loaded - await.push(assetsService.loadJs("lib/tinymce/tinymce.min.js", $scope)); + requests.push(assetsService.loadJs("lib/tinymce/tinymce.min.js", $scope)); } //queue rules loading angular.forEach(editorConfig.stylesheets, function (val, key) { stylesheets.push(Umbraco.Sys.ServerVariables.umbracoSettings.cssPath + "/" + val + ".css?" + new Date().getTime()); - await.push(stylesheetResource.getRulesByName(val).then(function (rules) { + requests.push(stylesheetResource.getRulesByName(val).then(function (rules) { angular.forEach(rules, function (rule) { var r = {}; r.title = rule.name; @@ -170,7 +170,7 @@ angular.module("umbraco") } //wait for queue to end - $q.all(await).then(function () { + $q.all(requests).then(function () { //create a baseline Config to exten upon var baseLineConfigObj = { From 0cd24e94bb61ea3b19891b7e8a6070b25e562d97 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Sun, 7 Oct 2018 20:03:06 +0200 Subject: [PATCH 26/44] can't delete variables --- .../propertyeditors/grid/dialogs/layoutconfig.controller.js | 2 +- .../views/propertyeditors/grid/dialogs/rowconfig.controller.js | 2 +- .../src/views/propertyeditors/grid/grid.prevalues.controller.js | 2 +- .../src/views/propertyeditors/tags/tags.controller.js | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/layoutconfig.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/layoutconfig.controller.js index e2422e7da0..20bb8b880f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/layoutconfig.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/layoutconfig.controller.js @@ -28,7 +28,7 @@ angular.module("umbraco") if(toggle){ collection = []; }else{ - delete collection; + collection = null; } }; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowconfig.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowconfig.controller.js index 3cd16301cd..78b607a9a9 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowconfig.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/dialogs/rowconfig.controller.js @@ -27,7 +27,7 @@ function RowConfigController($scope) { collection = []; } else { - delete collection; + collection = null; } }; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.prevalues.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.prevalues.controller.js index 7978ca3150..c90e4f3de0 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.prevalues.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.prevalues.controller.js @@ -189,7 +189,7 @@ angular.module("umbraco") if(toggle){ collection = []; }else{ - delete collection; + collection = null; } }; diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.controller.js index 94d74ada7b..bcf27294f3 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/tags/tags.controller.js @@ -207,7 +207,7 @@ angular.module("umbraco") tagsHound.clearPrefetchCache(); tagsHound.clearRemoteCache(); $element.find('.tags-' + $scope.model.alias).typeahead('destroy'); - delete tagsHound; + tagsHound = null; }); }); From b9ad98b357e3d46d81e9cf40b7600a3bf6c4270e Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Sun, 7 Oct 2018 20:03:23 +0200 Subject: [PATCH 27/44] package is a reserved word --- .../src/common/resources/package.resource.js | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js index 554134d017..8fd6836884 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/package.resource.js @@ -104,52 +104,52 @@ function packageResource($q, $http, umbDataFormatter, umbRequestHelper) { * @returns {Int} the ID assigned to the saved package manifest * */ - import: function (package) { + import: function (umbPackage) { return umbRequestHelper.resourcePromise( $http.post( umbRequestHelper.getApiUrl( "packageInstallApiBaseUrl", - "Import"), package), + "Import"), umbPackage), 'Failed to install package. Error during the step "Import" '); }, - installFiles: function (package) { + installFiles: function (umbPackage) { return umbRequestHelper.resourcePromise( $http.post( umbRequestHelper.getApiUrl( "packageInstallApiBaseUrl", - "InstallFiles"), package), + "InstallFiles"), umbPackage), 'Failed to install package. Error during the step "InstallFiles" '); }, - checkRestart: function (package) { + checkRestart: function (umbPackage) { return umbRequestHelper.resourcePromise( $http.post( umbRequestHelper.getApiUrl( "packageInstallApiBaseUrl", - "CheckRestart"), package), + "CheckRestart"), umbPackage), 'Failed to install package. Error during the step "CheckRestart" '); }, - installData: function (package) { + installData: function (umbPackage) { return umbRequestHelper.resourcePromise( $http.post( umbRequestHelper.getApiUrl( "packageInstallApiBaseUrl", - "InstallData"), package), + "InstallData"), umbPackage), 'Failed to install package. Error during the step "InstallData" '); }, - cleanUp: function (package) { + cleanUp: function (umbPackage) { return umbRequestHelper.resourcePromise( $http.post( umbRequestHelper.getApiUrl( "packageInstallApiBaseUrl", - "CleanUp"), package), + "CleanUp"), umbPackage), 'Failed to install package. Error during the step "CleanUp" '); } }; From eda87cbbd21624a01b3f5024d55feaba0b62289d Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 8 Oct 2018 10:48:57 +0200 Subject: [PATCH 28/44] prevent unpublish date to be before publish date and vice versa --- .../content/overlays/schedule.controller.js | 18 +++++++++++++----- .../src/views/content/overlays/schedule.html | 3 ++- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js index 6f570be8a5..9b84bd5335 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js @@ -94,8 +94,14 @@ } - function datePickerSetup(variant, datePickerInstance) { - variant.datePickerInstance = datePickerInstance; + function datePickerSetup(variant, type, datePickerInstance) { + // store a date picker instance for publish and unpublish picker + // so we can change the settings independently. + if (type === 'publish') { + variant.releaseDatePickerInstance = datePickerInstance; + } else if (type === 'unpublish') { + variant.removeDatePickerInstance = datePickerInstance; + } }; function datePickerChange(variant, dateStr, type) { @@ -132,9 +138,8 @@ // make sure dates are formatted to the user's locale formatDatesToLocal(variant); - // store the first selected date so we can apply to other selected variants - - // variant.datePickerInstance.set("maxDate", moment(variant.releaseDate).format("YYYY-MM-DD HH:mm")); + // make sure the unpublish date can't be before the publish date + variant.removeDatePickerInstance.set("minDate", moment(variant.releaseDate).format("YYYY-MM-DD HH:mm")); } @@ -154,6 +159,9 @@ // make sure dates are formatted to the user's locale formatDatesToLocal(variant); + // make sure the publish date can't be after the publish date + variant.releaseDatePickerInstance.set("maxDate", moment(variant.removeDate).format("YYYY-MM-DD HH:mm")); + } function clearPublishDate(variant) { diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html index 665dc003f3..f6b374a95f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html @@ -18,7 +18,7 @@ @@ -51,6 +51,7 @@ From 8c71aefe707d124b3dd337c212e68d297c8dfc04 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 8 Oct 2018 13:58:38 +0200 Subject: [PATCH 29/44] prevents overlay from closing when clicking inside date picker --- .../common/directives/components/events/events.directive.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/events/events.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/components/events/events.directive.js index 3a467807a3..21980be925 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/events/events.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/components/events/events.directive.js @@ -173,6 +173,12 @@ angular.module('umbraco.directives') return; } + // ignore clicks in flatpickr datepicker + var flatpickr = $(event.target).closest(".flatpickr-calendar"); + if (flatpickr.length === 1) { + return; + } + //ignore clicks inside this element if( $(element).has( $(event.target) ).length > 0 ){ return; From fb783e33afb996fb4bf6c2c7e105d53adf71a136 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 8 Oct 2018 13:59:25 +0200 Subject: [PATCH 30/44] add flatpickr to variants --- .../src/views/content/overlays/schedule.html | 72 ++++++++++--------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html index f6b374a95f..65db34d077 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html @@ -24,9 +24,9 @@ on-close="vm.datePickerClose()">
-
+
+ Set date @@ -53,13 +53,13 @@ options="vm.variants[0].datePickerConfig" on-setup="vm.datePickerSetup(vm.variants[0], 'unpublish', fpItem)" on-change="vm.datePickerChange(vm.variants[0], dateStr, 'unpublish')" - on-show="vm.datePickerShow()" + on-open="vm.datePickerShow()" on-close="vm.datePickerClose()">
-
+
+
Set date @@ -111,22 +111,23 @@
Publish:
- - -
- {{variant.releaseDateFormatted}} + + - - - Set date - - - - + @@ -135,22 +136,23 @@
Unpublish:
- - -
- {{variant.removeDateFormatted}} + +
+ + + + Set date +
- - - Set date - - - - +
From 6869833c5475f11ac5f3c472e914e865c46d7fa7 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 8 Oct 2018 14:41:14 +0200 Subject: [PATCH 31/44] clean up settings when dates are cleared --- .../src/views/content/overlays/schedule.controller.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js index 9b84bd5335..06c0258472 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js @@ -167,12 +167,18 @@ function clearPublishDate(variant) { if(variant && variant.releaseDate) { variant.releaseDate = null; + // we don't have a publish date anymore so we can clear the min date for unpublish + var now = new Date(); + var nowFormatted = moment(now).format("YYYY-MM-DD HH:mm"); + variant.removeDatePickerInstance.set("minDate", nowFormatted); } } function clearUnpublishDate(variant) { if(variant && variant.removeDate) { variant.removeDate = null; + // we don't have a unpublish date anymore so we can clear the max date for publish + variant.releaseDatePickerInstance.set("maxDate", null); } } From 3d345badc3a1798e73d195a789387732a4991b55 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 8 Oct 2018 15:22:15 +0200 Subject: [PATCH 32/44] add comments to schedule controller + fix problem with backdrop clicks --- .../content/overlays/schedule.controller.js | 86 +++++++++++++++++-- .../src/views/content/overlays/schedule.html | 16 ++-- 2 files changed, 88 insertions(+), 14 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js index 06c0258472..bb4aa3ca48 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.controller.js @@ -94,6 +94,12 @@ } + /** + * Callback when date is set up + * @param {any} variant + * @param {any} type publish or unpublish + * @param {any} datePickerInstance The date picker instance + */ function datePickerSetup(variant, type, datePickerInstance) { // store a date picker instance for publish and unpublish picker // so we can change the settings independently. @@ -104,6 +110,12 @@ } }; + /** + * Callback when date picker date changes + * @param {any} variant + * @param {any} dateStr Date string from the date picker + * @param {any} type publish or unpublish + */ function datePickerChange(variant, dateStr, type) { if (type === 'publish') { setPublishDate(variant, dateStr); @@ -112,16 +124,57 @@ } } - function datePickerShow() { - $scope.model.disableBackdropClick = true; + /** + * Add flag when a date picker opens is we can prevent the overlay from closing + * @param {any} variant + * @param {any} type publish or unpublish + */ + function datePickerShow(variant, type) { + if (type === 'publish') { + variant.releaseDatePickerOpen = true; + } else if (type === 'unpublish') { + variant.removeDatePickerOpen = true; + } + checkForBackdropClick(); } - function datePickerClose() { + /** + * Remove flag when a date picker closes so the overlay can be closed again + * @param {any} variant + * @param {any} type publish or unpublish + */ + function datePickerClose(variant, type) { $timeout(function(){ - $scope.model.disableBackdropClick = false; - }); + if (type === 'publish') { + variant.releaseDatePickerOpen = false; + } else if (type === 'unpublish') { + variant.removeDatePickerOpen = false; + } + checkForBackdropClick(); + }, 200); } + /** + * Prevent the overlay from closing if any date pickers are open + */ + function checkForBackdropClick() { + + var open = _.find(vm.variants, function (variant) { + return variant.releaseDatePickerOpen || variant.removeDatePickerOpen; + }); + + if(open) { + $scope.model.disableBackdropClick = true; + } else { + $scope.model.disableBackdropClick = false; + } + } + + /** + * Sets the selected publish date + * @param {any} variant + * @param {any} date The selected date + */ function setPublishDate(variant, date) { if (!date) { @@ -143,6 +196,11 @@ } + /** + * Sets the selected unpublish date + * @param {any} variant + * @param {any} date The selected date + */ function setUnpublishDate(variant, date) { if (!date) { @@ -164,6 +222,10 @@ } + /** + * Clears the publish date + * @param {any} variant + */ function clearPublishDate(variant) { if(variant && variant.releaseDate) { variant.releaseDate = null; @@ -174,6 +236,10 @@ } } + /** + * Clears the unpublish date + * @param {any} variant + */ function clearUnpublishDate(variant) { if(variant && variant.removeDate) { variant.removeDate = null; @@ -182,6 +248,10 @@ } } + /** + * Formates the selected dates to fit the user culture + * @param {any} variant + */ function formatDatesToLocal(variant) { if(variant && variant.releaseDate) { variant.releaseDateFormatted = dateHelper.getLocalDate(variant.releaseDate, vm.currentUser.locale, "MMM Do YYYY, HH:mm"); @@ -190,7 +260,11 @@ variant.removeDateFormatted = dateHelper.getLocalDate(variant.removeDate, vm.currentUser.locale, "MMM Do YYYY, HH:mm"); } } - + + /** + * Called when new variants are selected or deselected + * @param {any} variant + */ function changeSelection(variant) { $scope.model.disableSubmitButton = !canSchedule(); //need to set the Save state to true if publish is true diff --git a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html index 65db34d077..0486bf68dd 100644 --- a/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html +++ b/src/Umbraco.Web.UI.Client/src/views/content/overlays/schedule.html @@ -20,8 +20,8 @@ options="vm.variants[0].datePickerConfig" on-setup="vm.datePickerSetup(vm.variants[0], 'publish', fpItem)" on-change="vm.datePickerChange(vm.variants[0], dateStr, 'publish')" - on-open="vm.datePickerShow()" - on-close="vm.datePickerClose()"> + on-open="vm.datePickerShow(vm.variants[0], 'publish')" + on-close="vm.datePickerClose(vm.variants[0], 'publish')">