From f5ceab82f1d4a19352aef73ad838ff9dbc15155e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Pjengaard?= Date: Fri, 12 Feb 2016 14:00:45 +0100 Subject: [PATCH 001/535] Update da.xml Added translation for contentPublishedFailedAwaitingRelease --- src/Umbraco.Web.UI/umbraco/config/lang/da.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml index 446796dd88..841faab68f 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml @@ -837,6 +837,7 @@ Mange hilsner fra Umbraco robotten Annulleret Handlingen blev annulleret af et 3. part tilføjelsesprogram Udgivelsen blev standset af et 3. parts modul + Udgivelsen kunne ikke udgives da publiceringsdato er sat Property type eksisterer allerede Egenskabstype oprettet DataType: %1%]]> From 95863ad618faf5c96460aa4c1ee66d2882432ec3 Mon Sep 17 00:00:00 2001 From: Kevin Jump Date: Tue, 16 Feb 2016 11:36:56 +0000 Subject: [PATCH 002/535] Stylesheet RegEx to capture multi class properties Change the RegEx in Stylesheet Helper to capture mutli element classes as stylesheet properties (See U4-7160) Previously single class names "H1", "P", ".test" all work but multi ".btn btn-default" fail - this change fixes that --- src/Umbraco.Core/Strings/Css/StylesheetHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Strings/Css/StylesheetHelper.cs b/src/Umbraco.Core/Strings/Css/StylesheetHelper.cs index ff7591c6b5..afcbf5fa3f 100644 --- a/src/Umbraco.Core/Strings/Css/StylesheetHelper.cs +++ b/src/Umbraco.Core/Strings/Css/StylesheetHelper.cs @@ -7,7 +7,7 @@ namespace Umbraco.Core.Strings.Css { internal class StylesheetHelper { - private const string RuleRegexFormat = @"/\*\*\s*umb_name:\s*(?{0}?)\s*\*/\s*(?[^\s,{{]*?)\s*{{\s*(?.*?)\s*}}"; + private const string RuleRegexFormat = @"/\*\*\s*umb_name:\s*(?{0}?)\s*\*/\s*(?[^,{{]*?)\s*{{\s*(?.*?)\s*}}"; public static IEnumerable ParseRules(string input) { From 3ce2b0e6a02544b2b56a4d852409636f4a302617 Mon Sep 17 00:00:00 2001 From: James Coxhead Date: Tue, 16 Feb 2016 14:06:08 +0000 Subject: [PATCH 003/535] Updated database installer to use new media picker instead of legacy picker --- .../Persistence/Migrations/Initial/BaseDataCreation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs b/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs index 5e07a617d4..038c1c3c1c 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs @@ -237,7 +237,7 @@ namespace Umbraco.Core.Persistence.Migrations.Initial _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 14, DataTypeId = -42, PropertyEditorAlias = Constants.PropertyEditors.DropDownListAlias, DbType = "Integer" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 15, DataTypeId = -43, PropertyEditorAlias = Constants.PropertyEditors.CheckBoxListAlias, DbType = "Nvarchar" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 16, DataTypeId = 1034, PropertyEditorAlias = Constants.PropertyEditors.ContentPickerAlias, DbType = "Integer" }); - _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 17, DataTypeId = 1035, PropertyEditorAlias = Constants.PropertyEditors.MediaPickerAlias, DbType = "Integer" }); + _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 17, DataTypeId = 1035, PropertyEditorAlias = Constants.PropertyEditors.MultipleMediaPickerAlias, DbType = "Integer" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 18, DataTypeId = 1036, PropertyEditorAlias = Constants.PropertyEditors.MemberPickerAlias, DbType = "Integer" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 21, DataTypeId = 1040, PropertyEditorAlias = Constants.PropertyEditors.RelatedLinksAlias, DbType = "Ntext" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 22, DataTypeId = 1041, PropertyEditorAlias = Constants.PropertyEditors.TagsAlias, DbType = "Ntext" }); From b72d52bf90bac1ed1aa4babdc44ed1756af6bc97 Mon Sep 17 00:00:00 2001 From: Lesley Date: Thu, 18 Feb 2016 17:16:01 +0000 Subject: [PATCH 004/535] Fix U4-8029 The div was too wide so description text was unreadable. --- .../src/views/propertyeditors/grid/grid.prevalues.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.prevalues.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.prevalues.html index 3061f01c29..9d9626694a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.prevalues.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/grid.prevalues.html @@ -1,5 +1,5 @@
-
+

From 227e7a9c70d7c2e3521c0bc55f83c673898b5566 Mon Sep 17 00:00:00 2001 From: Simone Chiaretta Date: Tue, 8 Mar 2016 11:21:21 +0100 Subject: [PATCH 005/535] [U4-8128] Always rejecting promise even with server error Updated postSaveContent and resourcePromise to always reject the promise (thus always calling callers error handler) even when the error is 500 server error --- .../services/umbrequesthelper.service.js | 33 +++++++++---------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js b/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js index ccdd283ea6..a3d1e5b0c6 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/umbrequesthelper.service.js @@ -170,16 +170,14 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ } } - else { - //return an error object including the error message for UI - deferred.reject({ - errorMsg: result.errorMsg, - data: result.data, - status: result.status - }); + //return an error object including the error message for UI + deferred.reject({ + errorMsg: result.errorMsg, + data: result.data, + status: result.status + }); - } }); @@ -266,15 +264,14 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ } } - else { - - //return an error object including the error message for UI - deferred.reject({ - errorMsg: 'An error occurred', - data: data, - status: status - }); - } + + //return an error object including the error message for UI + deferred.reject({ + errorMsg: 'An error occurred', + data: data, + status: status + }); + }); @@ -337,4 +334,4 @@ function umbRequestHelper($http, $q, umbDataFormatter, angularHelper, dialogServ } }; } -angular.module('umbraco.services').factory('umbRequestHelper', umbRequestHelper); \ No newline at end of file +angular.module('umbraco.services').factory('umbRequestHelper', umbRequestHelper); From 64ad8f660f98d9cb25042511f29481d1e27d5f49 Mon Sep 17 00:00:00 2001 From: AndyButland Date: Sat, 12 Mar 2016 19:17:51 +0100 Subject: [PATCH 006/535] Fixed issue with misasigned task assignee on send to translation --- src/umbraco.cms/businesslogic/task/Task.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/umbraco.cms/businesslogic/task/Task.cs b/src/umbraco.cms/businesslogic/task/Task.cs index 678cd60225..294077370f 100644 --- a/src/umbraco.cms/businesslogic/task/Task.cs +++ b/src/umbraco.cms/businesslogic/task/Task.cs @@ -131,7 +131,7 @@ namespace umbraco.cms.businesslogic.task set { _user = value; - TaskEntity.OwnerUserId = _user.Id; + TaskEntity.AssigneeUserId = _user.Id; } } From e3411f7212b27b58aa7dcbf81c92f58920543088 Mon Sep 17 00:00:00 2001 From: AndyButland Date: Sat, 12 Mar 2016 19:26:45 +0100 Subject: [PATCH 007/535] Provided a check that a language was selected when sending to translation such that a message is returned to the user rather than an unexpected error --- src/Umbraco.Web.UI/umbraco/config/lang/en.xml | 1 + .../umbraco/config/lang/en_us.xml | 1 + .../umbraco/dialogs/sendToTranslation.aspx.cs | 34 ++++++++++++------- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index 0842755da3..55df243b81 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -1145,6 +1145,7 @@ To manage your website, simply open the Umbraco back office and start adding con To close a translation task, please go to the Details view and click the "Close" button. ]]> The page '%0%' has been send to translation + Please select the language that the content should be translated into Send the page '%0%' to translation Assigned by Task opened 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 ce25e990c8..2b06337be7 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml @@ -1149,6 +1149,7 @@ To manage your website, simply open the Umbraco back office and start adding con To close a translation task, please go to the Details view and click the "Close" button. ]]> The page '%0%' has been send to translation + Please select the language that the content should be translated into Send the page '%0%' to translation Assigned by Task opened diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/sendToTranslation.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/sendToTranslation.aspx.cs index 80118b4836..c02baaaa7b 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/sendToTranslation.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/dialogs/sendToTranslation.aspx.cs @@ -92,20 +92,30 @@ namespace umbraco.presentation.dialogs protected void doTranslation_Click(object sender, EventArgs e) { - // testing translate - cms.businesslogic.translation.Translation.MakeNew( - _currentPage, - getUser(), - BusinessLogic.User.GetUser(int.Parse(translator.SelectedValue)), - new cms.businesslogic.language.Language(int.Parse(language.SelectedValue)), - comment.Text, includeSubpages.Checked, - true); + int languageId; + if (int.TryParse(language.SelectedValue, out languageId)) + { + cms.businesslogic.translation.Translation.MakeNew( + _currentPage, + getUser(), + BusinessLogic.User.GetUser(int.Parse(translator.SelectedValue)), + new cms.businesslogic.language.Language(languageId), + comment.Text, includeSubpages.Checked, + true); - pane_form.Visible = false; - pl_buttons.Visible = false; + pane_form.Visible = false; + pl_buttons.Visible = false; - feedback.Text = ui.Text("translation","pageHasBeenSendToTranslation", _currentPage.Text, base.getUser()) + "

" + ui.Text("defaultdialogs", "closeThisWindow") + "

"; - feedback.type = uicontrols.Feedback.feedbacktype.success; + feedback.Text = ui.Text("translation", "pageHasBeenSendToTranslation", _currentPage.Text, base.getUser()) + + "

" + + ui.Text("defaultdialogs", "closeThisWindow") + "

"; + feedback.type = uicontrols.Feedback.feedbacktype.success; + } + else + { + feedback.Text = ui.Text("translation", "noLanguageSelected"); + feedback.type = uicontrols.Feedback.feedbacktype.error; + } } } } From ae913ede6f03e62d92f60e9d4dbaf4d78bd38520 Mon Sep 17 00:00:00 2001 From: Lars-Erik Aabech Date: Sun, 10 Apr 2016 00:07:03 +0200 Subject: [PATCH 008/535] Virtualized creating of application context Closed setting up of application context Opens up a whole bunch of doors. :) --- .../Routing/UrlRoutingTestBase.cs | 4 +- .../TestHelpers/BaseDatabaseFactoryTest.cs | 45 ++++++++++--------- .../TestHelpers/BaseUmbracoApplicationTest.cs | 13 ++++-- 3 files changed, 34 insertions(+), 28 deletions(-) diff --git a/src/Umbraco.Tests/Routing/UrlRoutingTestBase.cs b/src/Umbraco.Tests/Routing/UrlRoutingTestBase.cs index 475909318a..be9928004b 100644 --- a/src/Umbraco.Tests/Routing/UrlRoutingTestBase.cs +++ b/src/Umbraco.Tests/Routing/UrlRoutingTestBase.cs @@ -57,10 +57,10 @@ namespace Umbraco.Tests.Routing public const int LangNlId = 337; public const int LangDkId = 338; - protected override void SetupApplicationContext() + protected override ApplicationContext CreateApplicationContext() { var settings = SettingsForTests.GetDefault(); - ApplicationContext.Current = new ApplicationContext( + return new ApplicationContext( new DatabaseContext(Mock.Of(), Logger, Mock.Of(), "test"), GetServiceContext(settings, Logger), CacheHelper, diff --git a/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs b/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs index 967998e517..d24a411f73 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs @@ -57,6 +57,7 @@ namespace Umbraco.Tests.TestHelpers private string _dbPath; //used to store (globally) the pre-built db with schema and initial data private static Byte[] _dbBytes; + private DefaultDatabaseFactory dbFactory; [SetUp] public override void Initialize() @@ -66,27 +67,11 @@ namespace Umbraco.Tests.TestHelpers var path = TestHelper.CurrentAssemblyDirectory; AppDomain.CurrentDomain.SetData("DataDirectory", path); - //disable cache - var cacheHelper = CacheHelper.CreateDisabledCacheHelper(); - - var dbFactory = new DefaultDatabaseFactory( + dbFactory = new DefaultDatabaseFactory( GetDbConnectionString(), GetDbProviderName(), Logger); - var repositoryFactory = new RepositoryFactory(cacheHelper, Logger, SqlSyntax, SettingsForTests.GenerateMockSettings()); - - var evtMsgs = new TransientMessagesFactory(); - _appContext = new ApplicationContext( - //assign the db context - new DatabaseContext(dbFactory, Logger, SqlSyntax, "System.Data.SqlServerCe.4.0"), - //assign the service context - new ServiceContext(repositoryFactory, new PetaPocoUnitOfWorkProvider(dbFactory), new FileUnitOfWorkProvider(), new PublishingStrategy(evtMsgs, Logger), cacheHelper, Logger, evtMsgs), - cacheHelper, - ProfilingLogger) - { - IsReady = true - }; base.Initialize(); @@ -103,16 +88,32 @@ namespace Umbraco.Tests.TestHelpers } } + protected override ApplicationContext CreateApplicationContext() + { + //disable cache + var cacheHelper = CacheHelper.CreateDisabledCacheHelper(); + + var repositoryFactory = new RepositoryFactory(cacheHelper, Logger, SqlSyntax, SettingsForTests.GenerateMockSettings()); + + var evtMsgs = new TransientMessagesFactory(); + _appContext = new ApplicationContext( + //assign the db context + new DatabaseContext(dbFactory, Logger, SqlSyntax, "System.Data.SqlServerCe.4.0"), + //assign the service context + new ServiceContext(repositoryFactory, new PetaPocoUnitOfWorkProvider(dbFactory), new FileUnitOfWorkProvider(), new PublishingStrategy(evtMsgs, Logger), cacheHelper, Logger, evtMsgs), + cacheHelper, + ProfilingLogger) + { + IsReady = true + }; + return _appContext; + } + protected virtual ISqlSyntaxProvider SqlSyntax { get { return new SqlCeSyntaxProvider(); } } - protected override void SetupApplicationContext() - { - ApplicationContext.Current = _appContext; - } - /// /// The database behavior to use for the test/fixture /// diff --git a/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs b/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs index abf1edd3a5..83020fd386 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs @@ -147,17 +147,21 @@ namespace Umbraco.Tests.TestHelpers /// /// Inheritors can override this if they wish to create a custom application context /// - protected virtual void SetupApplicationContext() + protected void SetupApplicationContext() { + var applicationContext = CreateApplicationContext(); + ApplicationContext.Current = applicationContext; + } + protected virtual ApplicationContext CreateApplicationContext() + { var sqlSyntax = new SqlCeSyntaxProvider(); var repoFactory = new RepositoryFactory(CacheHelper.CreateDisabledCacheHelper(), Logger, sqlSyntax, SettingsForTests.GenerateMockSettings()); var evtMsgs = new TransientMessagesFactory(); - ApplicationContext.Current = new ApplicationContext( + var applicationContext = new ApplicationContext( //assign the db context - new DatabaseContext(new DefaultDatabaseFactory(Core.Configuration.GlobalSettings.UmbracoConnectionName, Logger), - Logger, sqlSyntax, "System.Data.SqlServerCe.4.0"), + new DatabaseContext(new DefaultDatabaseFactory(Core.Configuration.GlobalSettings.UmbracoConnectionName, Logger), Logger, sqlSyntax, "System.Data.SqlServerCe.4.0"), //assign the service context new ServiceContext(repoFactory, new PetaPocoUnitOfWorkProvider(Logger), new FileUnitOfWorkProvider(), new PublishingStrategy(evtMsgs, Logger), CacheHelper, Logger, evtMsgs), CacheHelper, @@ -165,6 +169,7 @@ namespace Umbraco.Tests.TestHelpers { IsReady = true }; + return applicationContext; } /// From c10534a064d8fd2806f3c913ef0f2a1635665dad Mon Sep 17 00:00:00 2001 From: Alexander Bryukhov Date: Thu, 14 Apr 2016 23:31:24 +0600 Subject: [PATCH 009/535] Update UI language ru.xml Missing keys & some typos found --- src/Umbraco.Web.UI/umbraco/config/lang/ru.xml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml b/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml index fbf0e0adf2..2fd54be962 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml @@ -215,8 +215,10 @@ ДА, удалить - была перемещена внутрь + перемещены внутрь + скопированы внутрь Выбрать папку для перемещения + Выбрать папку для копирования в структуре дерева Все типы документов @@ -328,7 +330,7 @@ Провайдеры аутентификации Подробное сообщение об ошибке Трассировка стека - Inner Exception + Внутренняя ошибка Связать Разорвать связь @@ -725,6 +727,7 @@ Нажмите, чтобы загрузить + Невозможна загрузка этого файла, этот тип файлов не разрешен для загрузки Перетащите файлы сюда... Ссылка на файл или нажмите сюда, чтобы выбрать файлы @@ -1219,6 +1222,6 @@ Валидация числового значения Валидация по формату Url ...или указать свои правила валидации - Обязательно к заполению + Обязательно к заполнению From 054fd9ecef0fc94a7b327bbd34d1d87cbd4f059f Mon Sep 17 00:00:00 2001 From: bjarnef Date: Thu, 14 Apr 2016 22:18:14 +0200 Subject: [PATCH 010/535] Fix line-height when using custom icon font as section icon. --- src/Umbraco.Web.UI.Client/src/less/sections.less | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/less/sections.less b/src/Umbraco.Web.UI.Client/src/less/sections.less index c2db58a99e..c89be83a10 100644 --- a/src/Umbraco.Web.UI.Client/src/less/sections.less +++ b/src/Umbraco.Web.UI.Client/src/less/sections.less @@ -22,6 +22,8 @@ ul.sections li [class^="icon-"]:before, ul.sections li [class*=" icon-"]:before, ul.sections li img.icon-section { font-size: 30px; + line-height: 20px; /* set line-height to ensure all icons use same line-height */ + display: inline-block; margin: 1px 0 0 0; opacity: 0.4; -webkit-transition: all .3s linear; From e9bf41e869157b05cfdb4e3a6f0a39e3f72b55cd Mon Sep 17 00:00:00 2001 From: bjarnef Date: Thu, 14 Apr 2016 23:22:26 +0200 Subject: [PATCH 011/535] Wrap text "Include all child nodes" in a label --- src/Umbraco.Web.UI/umbraco/developer/Packages/editPackage.aspx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI/umbraco/developer/Packages/editPackage.aspx b/src/Umbraco.Web.UI/umbraco/developer/Packages/editPackage.aspx index 82746bb7c2..edea60c62b 100644 --- a/src/Umbraco.Web.UI/umbraco/developer/Packages/editPackage.aspx +++ b/src/Umbraco.Web.UI/umbraco/developer/Packages/editPackage.aspx @@ -75,7 +75,7 @@
- Include all child nodes + From 1d428045b6e65dbb62040a8c0499f0349453d0e1 Mon Sep 17 00:00:00 2001 From: Lars-Erik Aabech Date: Mon, 18 Apr 2016 15:35:09 +0200 Subject: [PATCH 012/535] Don't remove virtual on SetupApplicationContext. Might be many external inheritors. --- src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs b/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs index 83020fd386..84b109a66a 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseUmbracoApplicationTest.cs @@ -147,7 +147,7 @@ namespace Umbraco.Tests.TestHelpers /// /// Inheritors can override this if they wish to create a custom application context /// - protected void SetupApplicationContext() + protected virtual void SetupApplicationContext() { var applicationContext = CreateApplicationContext(); ApplicationContext.Current = applicationContext; From 3564e702594385770c553bd13dd4a8354f1013e2 Mon Sep 17 00:00:00 2001 From: bjarnef Date: Mon, 18 Apr 2016 20:42:19 +0200 Subject: [PATCH 013/535] Localize "unsaved changes" dialog. --- .../views/common/notifications/confirmroutechange.html | 10 +++++----- src/Umbraco.Web.UI/Umbraco/config/lang/cs.xml | 6 ++++++ src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml | 6 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/da.xml | 6 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/de.xml | 6 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/en.xml | 6 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml | 6 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/es.xml | 6 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/fr.xml | 6 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/he.xml | 6 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/it.xml | 6 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/ja.xml | 6 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/ko.xml | 6 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/nl.xml | 6 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/pl.xml | 6 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/pt.xml | 6 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/ru.xml | 6 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/sv.xml | 6 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/zh.xml | 6 ++++++ 19 files changed, 113 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/notifications/confirmroutechange.html b/src/Umbraco.Web.UI.Client/src/views/common/notifications/confirmroutechange.html index 80942baaeb..c3b72f67a8 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/notifications/confirmroutechange.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/notifications/confirmroutechange.html @@ -1,7 +1,7 @@
-

You have unsaved changes

-

Are you sure you want to navigate away from this page? - you have unsaved changes

+

You have unsaved changes

+

Are you sure you want to navigate away from this page? - you have unsaved changes

- - -
+ + +
\ No newline at end of file diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/cs.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/cs.xml index 62aeb85cc0..7d6c52ad9b 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/cs.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/cs.xml @@ -179,6 +179,12 @@ Navštívit Vítejte + + Stay + Discard changes + You have unsaved changes + Are you sure you want to navigate away from this page? - you have unsaved changes + Název Spravovat názvy hostitelů diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml index a02fa21219..47bf684818 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml @@ -186,6 +186,12 @@ Besøk Velkommen + + Stay + Discard changes + You have unsaved changes + Are you sure you want to navigate away from this page? - you have unsaved changes + Navn på lokal link Rediger domener diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml index 446796dd88..4c3dcc749f 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml @@ -187,6 +187,12 @@ Besøg Velkommen + + Bliv + Kassér ændringer + Du har ikke-gemte ændringer + Er du sikker på du vil navigere væk fra denne side? - du har ikke-gemte ændringer + Navn på lokalt link Rediger domæner diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/de.xml b/src/Umbraco.Web.UI/umbraco/config/lang/de.xml index 1dab89a922..a3f40cc0ea 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/de.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/de.xml @@ -186,6 +186,12 @@ Besuchen Willkommen + + Stay + Discard changes + You have unsaved changes + Are you sure you want to navigate away from this page? - you have unsaved changes + Name Hostnamen verwalten diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index b810183d42..7b476e5e8b 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -197,6 +197,12 @@ Visit Welcome + + Stay + Discard changes + You have unsaved changes + Are you sure you want to navigate away from this page? - you have unsaved changes + Name Manage hostnames 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 402902f48c..534185e5db 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml @@ -199,6 +199,12 @@ Visit Welcome + + Stay + Discard changes + You have unsaved changes + Are you sure you want to navigate away from this page? - you have unsaved changes + Name Manage hostnames diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/es.xml b/src/Umbraco.Web.UI/umbraco/config/lang/es.xml index c1478abbb1..9e79db1efa 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/es.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/es.xml @@ -185,6 +185,12 @@ Visita Bienvenido + + Stay + Discard changes + You have unsaved changes + Are you sure you want to navigate away from this page? - you have unsaved changes + Nombre Administrar dominios diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/fr.xml b/src/Umbraco.Web.UI/umbraco/config/lang/fr.xml index a0842c8821..45153d78fa 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/fr.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/fr.xml @@ -181,6 +181,12 @@ Visiter Bienvenue + + Stay + Discard changes + You have unsaved changes + Are you sure you want to navigate away from this page? - you have unsaved changes + Name Gérer les noms d'hôtes diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/he.xml b/src/Umbraco.Web.UI/umbraco/config/lang/he.xml index 4b006e8524..fab17bb6a4 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/he.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/he.xml @@ -131,6 +131,12 @@ בקר ברוכים הבאים + + Stay + Discard changes + You have unsaved changes + Are you sure you want to navigate away from this page? - you have unsaved changes + שם ניהול שם מתחם diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/it.xml b/src/Umbraco.Web.UI/umbraco/config/lang/it.xml index d07d0cb049..7c26a2538a 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/it.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/it.xml @@ -127,6 +127,12 @@ Visita Benvenuto + + Stay + Discard changes + You have unsaved changes + Are you sure you want to navigate away from this page? - you have unsaved changes + Nome Gestione alias Hostnames diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/ja.xml b/src/Umbraco.Web.UI/umbraco/config/lang/ja.xml index e1b675b208..177e9d6aa5 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/ja.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/ja.xml @@ -194,6 +194,12 @@ 訪れる ようこそ + + Stay + Discard changes + You have unsaved changes + Are you sure you want to navigate away from this page? - you have unsaved changes + 名前 ドメインの割り当て diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/ko.xml b/src/Umbraco.Web.UI/umbraco/config/lang/ko.xml index ee8db9901c..db0aa62d11 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/ko.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/ko.xml @@ -125,6 +125,12 @@ 방문 환영합니다 + + Stay + Discard changes + You have unsaved changes + Are you sure you want to navigate away from this page? - you have unsaved changes + 이름 호스트네임 관리 diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/nl.xml b/src/Umbraco.Web.UI/umbraco/config/lang/nl.xml index 9c8f587ca2..9fb6f51402 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/nl.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/nl.xml @@ -188,6 +188,12 @@ Bezoek Welkom + + Stay + Discard changes + You have unsaved changes + Are you sure you want to navigate away from this page? - you have unsaved changes + Naam Beheer domeinnamen diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/pl.xml b/src/Umbraco.Web.UI/umbraco/config/lang/pl.xml index 3c24885eb3..1a3058e289 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/pl.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/pl.xml @@ -125,6 +125,12 @@ Odwiedź Witaj + + Stay + Discard changes + You have unsaved changes + Are you sure you want to navigate away from this page? - you have unsaved changes + Nazwa Zarządzaj nazwami hostów diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/pt.xml b/src/Umbraco.Web.UI/umbraco/config/lang/pt.xml index 4c039524ab..736bb7a507 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/pt.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/pt.xml @@ -125,6 +125,12 @@ Visitar Bem Vindo(a) + + Stay + Discard changes + You have unsaved changes + Are you sure you want to navigate away from this page? - you have unsaved changes + Nome Gerenciar hostnames diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml b/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml index fbf0e0adf2..8f039dcc71 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml @@ -254,6 +254,12 @@ Посетить Рады приветствовать + + Stay + Discard changes + You have unsaved changes + Are you sure you want to navigate away from this page? - you have unsaved changes + Название Управление доменами diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/sv.xml b/src/Umbraco.Web.UI/umbraco/config/lang/sv.xml index b620ecc168..c397c735b3 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/sv.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/sv.xml @@ -181,6 +181,12 @@ Välkommen Besök + + Stay + Discard changes + You have unsaved changes + Are you sure you want to navigate away from this page? - you have unsaved changes + Namn Hantera domännamn diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/zh.xml b/src/Umbraco.Web.UI/umbraco/config/lang/zh.xml index 6237bb4f07..69f938c42d 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/zh.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/zh.xml @@ -166,6 +166,12 @@ 访问 欢迎 + + Stay + Discard changes + You have unsaved changes + Are you sure you want to navigate away from this page? - you have unsaved changes + 锚点名称 管理主机名 From 9174029126cf6ddabf8337c777e0a89487b53c94 Mon Sep 17 00:00:00 2001 From: bjarnef Date: Mon, 18 Apr 2016 22:33:38 +0200 Subject: [PATCH 014/535] Fix localization of listview buttons/links actions. --- .../views/propertyeditors/listview/listview.html | 15 ++++++++------- src/Umbraco.Web.UI/umbraco/config/lang/da.xml | 11 ++++++++--- src/Umbraco.Web.UI/umbraco/config/lang/en.xml | 5 +++-- src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml | 3 ++- 4 files changed, 21 insertions(+), 13 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html index 904939b75f..64c8e6216d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html @@ -31,13 +31,14 @@ - {{ selectedItemsCount() }} of {{ listViewResultSet.items.length }} selected + {{ selectedItemsCount() }} of {{ listViewResultSet.items.length }} selected
@@ -86,7 +87,7 @@ type="button" button-style="link" label="Publish" - key="actions_publish" + label-key="actions_publish" icon="icon-globe" action="publish()" disabled="actionInProgress"> @@ -97,7 +98,7 @@ type="button" button-style="link" label="Unpublish" - key="actions_unpublish" + label-key="actions_unpublish" icon="icon-block" action="unpublish()" disabled="actionInProgress"> @@ -108,7 +109,7 @@ type="button" button-style="link" label="Copy" - key="actions_copy" + label-key="actions_copy" icon="icon-documents" action="copy()" disabled="actionInProgress"> @@ -119,7 +120,7 @@ type="button" button-style="link" label="Move" - key="actions_move" + label-key="actions_move" icon="icon-enter" action="move()" disabled="actionInProgress"> @@ -129,8 +130,8 @@ ng-if="options.allowBulkDelete && (buttonPermissions == null || buttonPermissions.canDelete)" type="button" button-style="link" - label="Delete" - key="actions_delete" + label="Delete" + label-key="actions_delete" icon="icon-trash" action="delete()" disabled="actionInProgress"> diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml index 446796dd88..e9631c0e93 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml @@ -60,6 +60,7 @@ For + Ryd valg Vælg Vælg nuværende mappe Gør noget andet @@ -165,6 +166,10 @@ Klik for at uploade Slip filerne her... + Link til medie + eller klik her for at vælge filer + Tilladte filtyper er kun + Maks filstørrelse er Opret et nyt medlem @@ -197,7 +202,7 @@ Er du sikker på at du vil forlade Umbraco? Er du sikker? Klip - Rediger ordbogs nøgle + Rediger ordbogsnøgle Rediger sprog Indsæt lokalt link Indsæt tegn @@ -421,8 +426,8 @@ Listevisning Gemmer... nuværende - Flyt Indlejring + valgt @@ -985,7 +990,7 @@ Mange hilsner fra Umbraco robotten Roller Medlemstype Dokumenttyper - Dokumenttyper + Relationstyper Pakker Pakker diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index b810183d42..ad0891a616 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -65,6 +65,7 @@ Viewing for + Clear selection Select Select current folder Do something else @@ -171,7 +172,7 @@ Click to upload Drop your files here... - Link to media + Link to media or click here to choose files Only allowed file types are Max file size is @@ -479,8 +480,8 @@ List view Saving... current - Move Embed + selected 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 402902f48c..bb4e1b0e7a 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml @@ -65,6 +65,7 @@ Viewing for + Clear selection Select Select current folder Do something else @@ -483,8 +484,8 @@ List view Saving... current - Move Embed + selected Black From b607ba52f41c472b3f06b9ad239271730911b79e Mon Sep 17 00:00:00 2001 From: Dynacy Date: Fri, 22 Apr 2016 12:26:26 +0300 Subject: [PATCH 015/535] Create tr.xml Turkish Language --- src/Umbraco.Web.UI/umbraco/config/lang/tr.xml | 1073 +++++++++++++++++ 1 file changed, 1073 insertions(+) create mode 100644 src/Umbraco.Web.UI/umbraco/config/lang/tr.xml diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/tr.xml b/src/Umbraco.Web.UI/umbraco/config/lang/tr.xml new file mode 100644 index 0000000000..8adcb89801 --- /dev/null +++ b/src/Umbraco.Web.UI/umbraco/config/lang/tr.xml @@ -0,0 +1,1073 @@ + + + + Umbraco + http://our.umbraco.org/documentation/Extending-Umbraco/Language-Files + + + Kültür ve Alanadları + Denetim + Nodları Görüntüle + Döküman Tipini Değiştir + Kopyala + Oluştur + Paket Oluştur + Sil + Devredışı Bırak + Çöp Kutusunu Boşalt + Döküman Tipini Dışarı Çıkar + Döküman Tipini İçeri Aktar + İçeri Paket Aktar + Kanvasda Düzenle + Çıkış + Taşı + Bildiri + Herkes Ulaşsın + Yayınla + Yayınlama + Nodları Yenile + Bütün Siteyi Tekrar Yayınla + Onar + İzinler + Geri Al + Yayınlamak İçin Gönder + Çeviri İçin Gönder + Sırala + Yayına Gönder + Çeviri + Güncelleme + Varsayılan Değer + + + İzin Reddedildi + Yeni Alanadı Ekle + Kaldır + Hatalı Nod + Hatalı Alanadı + Alanadı önceden atanmış. + Dil + Alanadı + Yeni alanadı '%0%' oluşturuldu + Alanadı '%0%' silindi + Alanadı '%0%' önceden atanmış + Alanadı '%0%' güncellendi + Geçerli Alanadlarını Düzenle + + Miras Al + Dil Değiştir + or inherit culture from parent nodes. Will also apply
+ to the current node, unless a domain below applies too.]]>
+ Alanadları + + + Görüntüleniyor + + + Seç + Geçerli dosyaları seç + Başka Birşey Yapın + Kalın + Paragraf İşaretini Kaldır + Insert form field + Insert graphic headline + Edit Html + Indent Paragraph + Italic + Center + Justify Left + Justify Right + Insert Link + Insert local link (anchor) + Bullet List + Numeric List + Insert macro + Insert picture + Edit relations + Return to list + Save + Save and publish + Save and send for approval + Preview + Preview is disabled because there's no template assigned + Choose style + Show styles + Insert table + + + To change the document type for the selected content, first select from the list of valid types for this location. + Then confirm and/or amend the mapping of properties from the current type to the new, and click Save. + The content has been re-published. + Current Property + Current type + The document type cannot be changed, as there are no alternatives valid for this location. An alternative will be valid if it is allowed under the parent of the selected content item and that all existing child content items are allowed to be created under it. + Document Type Changed + Map Properties + Map to Property + New Template + New Type + none + Content + Select New Document Type + The document type of the selected content has been successfully changed to [new type] and the following properties mapped: + to + Could not complete property mapping as one or more properties have more than one mapping defined. + Only alternate types valid for the current location are displayed. + + + Is Published + About this page + Alias + (how would you describe the picture over the phone) + Alternative Links + Click to edit this item + Created by + Original author + Updated by + Created + Date/time this document was created + Document Type + Editing + Remove at + This item has been changed after publication + This item is not published + Last published + There are no items to show in the list. + Media Type + Link to media item(s) + Member Group + Role + Member Type + No date chosen + Page Title + Properties + This document is published but is not visible because the parent '%0%' is unpublished + Oops: this document is published but is not in the cache (internal error) + Publish + Publication Status + Publish at + Unpublish at + Clear Date + Sortorder is updated + To sort the nodes, simply drag the nodes or click one of the column headers. You can select multiple nodes by holding the "shift" or "control" key while selecting + Statistics + Title (optional) + Alternative text (optional) + Type + Unpublish + Last edited + Date/time this document was edited + Remove file(s) + Link to document + Member of group(s) + Not a member of group(s) + Child items + Target + + + Click to upload + Drop your files here... + Link to media + + + Create a new member + All Members + + + Where do you want to create the new %0% + Create an item under + Choose a type and a title + "document types".]]> + "media types".]]> + + + Browse your website + - Hide + If Umbraco isn't opening, you might need to allow popups from this site + has opened in a new window + Restart + Visit + Welcome + + + Name + Manage hostnames + Close this window + Are you sure you want to delete + Are you sure you want to disable + Please check this box to confirm deletion of %0% item(s) + Are you sure? + Are you sure? + Cut + Edit Dictionary Item + Edit Language + Insert local link + Insert character + Insert graphic headline + Insert picture + Insert link + Click to add a Macro + Insert table + Last Edited + Link + Internal link: + When using local links, insert "#" in front of link + Open in new window? + Macro Settings + This macro does not contain any properties you can edit + Paste + Edit Permissions for + The items in the recycle bin are now being deleted. Please do not close this window while this operation takes place + The recycle bin is now empty + When items are deleted from the recycle bin, they will be gone forever + regexlib.com's webservice is currently experiencing some problems, which we have no control over. We are very sorry for this inconvenience.]]> + Search for a regular expression to add validation to a form field. Example: 'email, 'zip-code' 'url' + Remove Macro + Required Field + Site is reindexed + The website cache has been refreshed. All publish content is now up to date. While all unpublished content is still unpublished + The website cache will be refreshed. All published content will be updated, while unpublished content will stay unpublished. + Number of columns + Number of rows + Set a placeholder id by setting an ID on your placeholder you can inject content into this template from child templates, + by referring this ID using a <asp:content /> element.]]> + Select a placeholder id from the list below. You can only + choose Id's from the current template's master.]]> + Click on the image to see full size + Pick item + View Cache Item + + + %0%' below
You can add additional languages under the 'languages' in the menu on the left + ]]>
+ Culture Name + + + Enter your username + Enter your password + Name the %0%... + Enter a name... + Type to search... + Type to filter... + Type to add tags (press enter after each tag)... + + + + Allow at root + Only Content Types with this checked can be created at the root level of Content and Media trees + Allowed child node types + Document Type Compositions + Create + Delete tab + Description + New tab + Tab + Thumbnail + Enable list view + Configures the content item to show a sortable & searchable list of its children, the children will not be shown in the tree + Current list view + The active list view data type + Create custom list view + Remove custom list view + + + Add prevalue + Database datatype + Property editor GUID + Property editor + Buttons + Enable advanced settings for + Enable context menu + Maximum default size of inserted images + Related stylesheets + Show label + Width and height + + + Your data has been saved, but before you can publish this page there are some errors you need to fix first: + The current membership provider does not support changing password (EnablePasswordRetrieval need to be true) + %0% already exists + There were errors: + There were errors: + The password should be a minimum of %0% characters long and contain at least %1% non-alpha numeric character(s) + %0% must be an integer + The %0% field in the %1% tab is mandatory + %0% is a mandatory field + %0% at %1% is not in a correct format + %0% is not in a correct format + + + The specified file type has been disallowed by the administrator + NOTE! Even though CodeMirror is enabled by configuration, it is disabled in Internet Explorer because it's not stable enough. + Please fill both alias and name on the new property type! + There is a problem with read/write access to a specific file or folder + Error loading Partial View script (file: %0%) + Error loading userControl '%0%' + Error loading customControl (Assembly: %0%, Type: '%1%') + Error loading MacroEngine script (file: %0%) + "Error parsing XSLT file: %0% + "Error reading XSLT file: %0% + Please enter a title + Please choose a type + You're about to make the picture larger than the original size. Are you sure that you want to proceed? + Error in python script + The python script has not been saved, because it contained error(s) + Startnode deleted, please contact your administrator + Please mark content before changing style + No active styles available + Please place cursor at the left of the two cells you wish to merge + You cannot split a cell that hasn't been merged. + Error in XSLT source + The XSLT has not been saved, because it contained error(s) + There is a configuration error with the data type used for this property, please check the data type + + + About + Action + Actions + Add + Alias + Are you sure? + Border + by + Cancel + Cell margin + Choose + Close + Close Window + Comment + Confirm + Constrain proportions + Continue + Copy + Create + Database + Date + Default + Delete + Deleted + Deleting... + Design + Dimensions + Down + Download + Edit + Edited + Elements + Email + Error + Find + Height + Help + Icon + Import + Inner margin + Insert + Install + Justify + Language + Layout + Loading + Locked + Login + Log off + Logout + Macro + Move + More + Name + New + Next + No + of + OK + Open + or + Password + Path + Placeholder ID + One moment please... + Previous + Properties + Email to receive form data + Recycle Bin + Remaining + Rename + Renew + Required + Retry + Permissions + Search + Server + Show + Show page on Send + Size + Sort + Type + Type to search... + Up + Update + Upgrade + Upload + Url + User + Username + Value + View + Welcome... + Width + Yes + Folder + Search results + + + Background color + Bold + Text color + Font + Text + + + Page + + + The installer cannot connect to the database. + Could not save the web.config file. Please modify the connection string manually. + Your database has been found and is identified as + Database configuration + install button to install the Umbraco %0% database + ]]> + Next to proceed.]]> + Database not found! Please check that the information in the "connection string" of the "web.config" file is correct.

+

To proceed, please edit the "web.config" file (using Visual Studio or your favourite text editor), scroll to the bottom, add the connection string for your database in the key named "UmbracoDbDSN" and save the file.

+

+ Click the retry button when + done.
+ More information on editing web.config here.

]]>
+ + Please contact your ISP if necessary. + If you're installing on a local machine or server you might need information from your system administrator.]]> + + Press the upgrade button to upgrade your database to Umbraco %0%

+

+ Don't worry - no content will be deleted and everything will continue working afterwards! +

+ ]]>
+ Press Next to + proceed. ]]> + next to continue the configuration wizard]]> + The Default users' password needs to be changed!]]> + The Default user has been disabled or has no access to Umbraco!

No further actions needs to be taken. Click Next to proceed.]]> + The Default user's password has been successfully changed since the installation!

No further actions needs to be taken. Click Next to proceed.]]> + The password is changed! + + Umbraco creates a default user with a login ('admin') and password ('default'). It's important that the password is + changed to something unique. +

+

+ This step will check the default user's password and suggest if it needs to be changed. +

+ ]]>
+ Get a great start, watch our introduction videos + By clicking the next button (or modifying the umbracoConfigurationStatus in web.config), you accept the license for this software as specified in the box below. Notice that this Umbraco distribution consists of two different licenses, the open source MIT license for the framework and the Umbraco freeware license that covers the UI. + Not installed yet. + Affected files and folders + More information on setting up permissions for Umbraco here + You need to grant ASP.NET modify permissions to the following files/folders + Your permission settings are almost perfect!

+ You can run Umbraco without problems, but you will not be able to install packages which are recommended to take full advantage of Umbraco.]]>
+ How to Resolve + Click here to read the text version + video tutorial on setting up folder permissions for Umbraco or read the text version.]]> + Your permission settings might be an issue! +

+ You can run Umbraco without problems, but you will not be able to create folders or install packages which are recommended to take full advantage of Umbraco.]]>
+ Your permission settings are not ready for Umbraco! +

+ In order to run Umbraco, you'll need to update your permission settings.]]>
+ Your permission settings are perfect!

+ You are ready to run Umbraco and install packages!]]>
+ Resolving folder issue + Follow this link for more information on problems with ASP.NET and creating folders + Setting up folder permissions + + I want to start from scratch + learn how) + You can still choose to install Runway later on. Please go to the Developer section and choose Packages. + ]]> + You've just set up a clean Umbraco platform. What do you want to do next? + Runway is installed + + This is our list of recommended modules, check off the ones you would like to install, or view the full list of modules + ]]> + Only recommended for experienced users + I want to start with a simple website + + "Runway" is a simple website providing some basic document types and templates. The installer can set up Runway for you automatically, + but you can easily edit, extend or remove it. It's not necessary and you can perfectly use Umbraco without it. However, + Runway offers an easy foundation based on best practices to get you started faster than ever. + If you choose to install Runway, you can optionally select basic building blocks called Runway Modules to enhance your Runway pages. +

+ + Included with Runway: Home page, Getting Started page, Installing Modules page.
+ Optional Modules: Top Navigation, Sitemap, Contact, Gallery. +
+ ]]>
+ What is Runway + Step 1/5 Accept license + Step 2/5: Database configuration + Step 3/5: Validating File Permissions + Step 4/5: Check Umbraco security + Step 5/5: Umbraco is ready to get you started + Thank you for choosing Umbraco + Browse your new site +You installed Runway, so why not see how your new website looks.]]> + Further help and information +Get help from our award winning community, browse the documentation or watch some free videos on how to build a simple site, how to use packages and a quick guide to the Umbraco terminology]]> + Umbraco %0% is installed and ready for use + /web.config file and update the AppSetting key UmbracoConfigurationStatus in the bottom to the value of '%0%'.]]> + started instantly by clicking the "Launch Umbraco" button below.
If you are new to Umbraco, +you can find plenty of resources on our getting started pages.]]>
+ Launch Umbraco +To manage your website, simply open the Umbraco back office and start adding content, updating the templates and stylesheets or add new functionality]]> + Connection to database failed. + Umbraco Version 3 + Umbraco Version 4 + Watch + Umbraco %0% for a fresh install or upgrading from version 3.0. +

+ Press "next" to start the wizard.]]>
+ + + Culture Code + Culture Name + + + You've been idle and logout will automatically occur in + Renew now to save your work + + + Happy super Sunday + Happy manic Monday + Happy tubular Tuesday + Happy wonderful Wednesday + Happy thunderous Thursday + Happy funky Friday + Happy Caturday + Log in below + Session timed out + © 2001 - %0%
Umbraco.com

]]>
+ + + Dashboard + Sections + Content + + + Choose page above... + %0% has been copied to %1% + Select where the document %0% should be copied to below + %0% has been moved to %1% + Select where the document %0% should be moved to below + has been selected as the root of your new content, click 'ok' below. + No node selected yet, please select a node in the list above before clicking 'ok' + The current node is not allowed under the chosen node because of its type + The current node cannot be moved to one of its subpages + The current node cannot exist at the root + The action isn't allowed since you have insufficient permissions on 1 or more child documents. + Relate copied items to original + + + Edit your notification for %0% + + Hi %0%

+ +

This is an automated mail to inform you that the task '%1%' + has been performed on the page '%2%' + by the user '%3%' +

+ +

+

Update summary:

+ + %6% +
+

+ + + +

Have a nice day!

+ Cheers from the Umbraco robot +

]]>
+ [%0%] Notification about %1% performed on %2% + Notifications + + + + button and locating the package. Umbraco packages usually have a ".umb" or ".zip" extension. + ]]> + Author + Demonstration + Documentation + Package meta data + Package name + Package doesn't contain any items +
+ You can safely remove this from the system by clicking "uninstall package" below.]]>
+ No upgrades available + Package options + Package readme + Package repository + Confirm uninstall + Package was uninstalled + The package was successfully uninstalled + Uninstall package + + Notice: any documents, media etc depending on the items you remove, will stop working, and could lead to system instability, + so uninstall with caution. If in doubt, contact the package author.]]> + Download update from the repository + Upgrade package + Upgrade instructions + There's an upgrade available for this package. You can download it directly from the Umbraco package repository. + Package version + Package version history + View package website + + + Paste with full formatting (Not recommended) + The text you're trying to paste contains special characters or formatting. This could be caused by copying text from Microsoft Word. Umbraco can remove special characters or formatting automatically, so the pasted content will be more suitable for the web. + Paste as raw text without any formatting at all + Paste, but remove formatting (Recommended) + + + Role based protection + using Umbraco's member groups.]]> + role-based authentication.]]> + Error Page + Used when people are logged on, but do not have access + Choose how to restrict access to this page + %0% is now protected + Protection removed from %0% + Login Page + Choose the page that contains the login form + Remove Protection + Select the pages that contain login form and error messages + Pick the roles who have access to this page + Set the login and password for this page + Single user protection + If you just want to setup simple protection using a single login and password + + + + + + + + + + Include unpublished child pages + Publishing in progress - please wait... + %0% out of %1% pages have been published... + %0% has been published + %0% and subpages have been published + Publish %0% and all its subpages + ok to publish %0% and thereby making its content publicly available.

+ You can publish this page and all it's sub-pages by checking publish all children below. + ]]>
+ + + You have not configured any approved colors + + + enter external link + choose internal page + Caption + Link + Open in new window + enter the display caption + Enter the link + + + Reset + + + Current version + Red text will not be shown in the selected version. , green means added]]> + Document has been rolled back + This displays the selected version as HTML, if you wish to see the difference between 2 versions at the same time, use the diff view + Rollback to + Select version + View + + + Edit script file + + + Concierge + Content + Courier + Developer + Umbraco Configuration Wizard + Media + Members + Newsletters + Settings + Statistics + Translation + Users + Help + Forms + Analytics + + + go to + Help topics for + Video chapters for + The best Umbraco video tutorials + + + Default template + Dictionary Key + To import a document type, find the ".udt" file on your computer by clicking the "Browse" button and click "Import" (you'll be asked for confirmation on the next screen) + New Tab Title + Node type + Type + Stylesheet + Script + Stylesheet property + Tab + Tab Title + Tabs + Master Content Type enabled + This Content Type uses + as a Master Content Type. Tabs from Master Content Types are not shown and can only be edited on the Master Content Type itself + No properties defined on this tab. Click on the "add a new property" link at the top to create a new property. + Master Document Type + Create matching template + + + Sorting complete. + Drag the different items up or down below to set how they should be arranged. Or click the column headers to sort the entire collection of items +
Do not close this window during sorting]]>
+ + + Failed + Insufficient user permissions, could not complete the operation + Cancelled + Operation was cancelled by a 3rd party add-in + Publishing was cancelled by a 3rd party add-in + Property type already exists + Property type created + DataType: %1%]]> + Propertytype deleted + Document Type saved + Tab created + Tab deleted + Tab with id: %0% deleted + Stylesheet not saved + Stylesheet saved + Stylesheet saved without any errors + Datatype saved + Dictionary item saved + Publishing failed because the parent page isn't published + Content published + and visible at the website + Content saved + Remember to publish to make changes visible + Sent For Approval + Changes have been sent for approval + Media saved + Media saved without any errors + Member saved + Stylesheet Property Saved + Stylesheet saved + Template saved + Error saving user (check log) + User Saved + User type saved + File not saved + file could not be saved. Please check file permissions + File saved + File saved without any errors + Language saved + Python script not saved + Python script could not be saved due to error + Python script saved + No errors in python script + Template not saved + Please make sure that you do not have 2 templates with the same alias + Template saved + Template saved without any errors! + XSLT not saved + XSLT contained an error + XSLT could not be saved, check file permissions + XSLT saved + No errors in XSLT + Content unpublished + Partial view saved + Partial view saved without any errors! + Partial view not saved + An error occurred saving the file. + Script view saved + Script view saved without any errors! + Script view not saved + An error occurred saving the file. + An error occurred saving the file. + + + Uses CSS syntax ex: h1, .redHeader, .blueTex + Edit stylesheet + Edit stylesheet property + Name to identify the style property in the rich text editor + Preview + Styles + + + Edit template + Insert content area + Insert content area placeholder + Insert dictionary item + Insert Macro + Insert Umbraco page field + Master template + Quick Guide to Umbraco template tags + Template + + + Insert control + Choose a layout for this section + below and add your first element]]> + + Click to embed + Click to insert image + Image caption... + Write here... + Grid layouts + Layouts are the overall work area for the grid editor, usually you only need one or two different layouts + Add grid layout + Adjust the layout by setting column widths and adding additional sections + + Row configurations + Rows are predefined cells arranged horizontally + Add row configuration + Adjust the row by setting cell widths and adding additional cells + + Columns + Total combined number of columns in the grid layout + + Settings + Configure what settings editors can change + + + Styles + Configure what styling editors can change + + Settings will only save if the entered json configuration is valid + + Allow all editors + Allow all row configurations + + + Alternative field + Alternative Text + Casing + Encoding + Choose field + Convert line breaks + Replaces line breaks with html-tag &lt;br&gt; + Custom Fields + Yes, Date only + Format as date + HTML encode + Will replace special characters by their HTML equivalent. + Will be inserted after the field value + Will be inserted before the field value + Lowercase + None + Insert after field + Insert before field + Recursive + Remove Paragraph tags + Will remove any &lt;P&gt; in the beginning and end of the text + Standard Fields + Uppercase + URL encode + Will format special characters in URLs + Will only be used when the field values above are empty + This field will only be used if the primary field is empty + Yes, with time. Separator: + + + Tasks assigned to you + assigned to you. To see a detailed view including comments, click on "Details" or just the page name. + You can also download the page as XML directly by clicking the "Download Xml" link.
+ To close a translation task, please go to the Details view and click the "Close" button. + ]]>
+ close task + Translation details + Download all translation tasks as XML + Download XML + Download XML DTD + Fields + Include subpages + + [%0%] Translation task for %1% + No translator users found. Please create a translator user before you start sending content to translation + Tasks created by you + created by you. To see a detailed view including comments, + click on "Details" or just the page name. You can also download the page as XML directly by clicking the "Download Xml" link. + To close a translation task, please go to the Details view and click the "Close" button. + ]]> + The page '%0%' has been send to translation + Send the page '%0%' to translation + Assigned by + Task opened + Total words + Translate to + Translation completed. + You can preview the pages, you've just translated, by clicking below. If the original page is found, you will get a comparison of the 2 pages. + Translation failed, the XML file might be corrupt + Translation options + Translator + Upload translation XML + + + Cache Browser + Recycle Bin + Created packages + Data Types + Dictionary + Installed packages + Install skin + Install starter kit + Languages + Install local package + Macros + Media Types + Members + Member Groups + Roles + Member Types + Document Types + Packages + Packages + Python Files + Install from repository + Install Runway + Runway modules + Scripting Files + Scripts + Stylesheets + Templates + XSLT Files + Analytics + + + New update ready + %0% is ready, click here for download + No connection to server + Error checking for update. Please review trace-stack for further information + + + Administrator + Category field + Change Your Password + Change Your Password + Confirm new password + You can change your password for accessing the Umbraco Back Office by filling out the form below and click the 'Change Password' button + Content Channel + Description field + Disable User + Document Type + Editor + Excerpt field + Language + Login + Start Node in Media Library + Sections + Disable Umbraco Access + Password + Reset password + Your password has been changed! + Please confirm the new password + Enter your new password + Your new password cannot be blank! + Current password + Invalid current password + There was a difference between the new password and the confirmed password. Please try again! + The confirmed password doesn't match the new password! + Replace child node permissions + You are currently modifying permissions for the pages: + Select pages to modify their permissions + Search all children + Start Node in Content + Name + User permissions + User type + User types + Writer + Translator + Change + Your profile + Your recent history + Session expires in + +
From ff5714196c91874d869a19b51a15648b098b7f8b Mon Sep 17 00:00:00 2001 From: Dynacy Date: Fri, 22 Apr 2016 12:34:03 +0300 Subject: [PATCH 016/535] Update tr.xml --- src/Umbraco.Web.UI/umbraco/config/lang/tr.xml | 1149 +++++++++-------- 1 file changed, 609 insertions(+), 540 deletions(-) diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/tr.xml b/src/Umbraco.Web.UI/umbraco/config/lang/tr.xml index 8adcb89801..6452af023b 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/tr.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/tr.xml @@ -1,470 +1,489 @@ - + Umbraco - http://our.umbraco.org/documentation/Extending-Umbraco/Language-Files + http://kayadata.com - Kültür ve Alanadları - Denetim - Nodları Görüntüle - Döküman Tipini Değiştir - Kopyala + Kültür ve Hostnames + Denetim Trail + Düğüm Araçtır + Belge Türü Değiştir + Kopya Oluştur Paket Oluştur Sil - Devredışı Bırak - Çöp Kutusunu Boşalt - Döküman Tipini Dışarı Çıkar - Döküman Tipini İçeri Aktar - İçeri Paket Aktar - Kanvasda Düzenle + Devre Dışı Bırak + Geri Dönüşümü Boşat + Belge Türü Çıkart + Belge Türü Al + Paket Ekle + Tuval Düzele Çıkış Taşı - Bildiri - Herkes Ulaşsın - Yayınla - Yayınlama - Nodları Yenile - Bütün Siteyi Tekrar Yayınla - Onar + Bildirimler + Genel Erişim + Yayımla + Yayından Kaldır + Yeniden Yükle + Siteleri Yeniden Yayınla + Düzelt İzinler - Geri Al - Yayınlamak İçin Gönder - Çeviri İçin Gönder + Rollback + Yayın için Gönder + Çeviri Gönder Sırala Yayına Gönder - Çeviri - Güncelleme + Çevir + Güncelle Varsayılan Değer - İzin Reddedildi - Yeni Alanadı Ekle - Kaldır - Hatalı Nod - Hatalı Alanadı - Alanadı önceden atanmış. + İzin reddedildi. + Yeni Domain ekle + kaldır + Geçersiz node. + Geçersiz domain biçimi. + Domain zaten eklenmiş. Dil - Alanadı - Yeni alanadı '%0%' oluşturuldu - Alanadı '%0%' silindi - Alanadı '%0%' önceden atanmış - Alanadı '%0%' güncellendi - Geçerli Alanadlarını Düzenle - + Domain + Yeni domain '%0%' oluşturuldu + Domain '%0%' silindi + Domain '%0%' zaten atanmış + Domain '%0%' güncellendi + Geçerli domain düzenle + + etki /> bir düzey yollar desteklenir
+
Miras Al - Dil Değiştir - or inherit culture from parent nodes. Will also apply
- to the current node, unless a domain below applies too.]]>
- Alanadları + Kültür + + veya üst düğümleri kültürünü devralır. Ayrıca
geçerli olacaktır + Geçerli düğümün , bir etki altında çok uygulanmadığı sürece .]]> +
+ Domainler Görüntüleniyor Seç - Geçerli dosyaları seç - Başka Birşey Yapın + Geçerli klasörü seçin + Başka birşey yapın Kalın - Paragraf İşaretini Kaldır - Insert form field - Insert graphic headline - Edit Html - Indent Paragraph - Italic - Center - Justify Left - Justify Right - Insert Link - Insert local link (anchor) - Bullet List - Numeric List - Insert macro - Insert picture - Edit relations - Return to list - Save - Save and publish - Save and send for approval - Preview - Preview is disabled because there's no template assigned - Choose style - Show styles - Insert table + Paragraf girinti iptal + Form alanı ekle + Grafik başlık ekle + Html Düzenle + Paragraf girintisi + Yatık + Ortalı + Sola Yasla + Sağa Yasla + Link ekle + Yerel bağlantı ekle + Bulet listesi + Sayısal Liste + Macro ekle + Resim ekle + Düzenleme ilişkileri + Listeye Dön + Kaydet + Kaydet ve Yayınla + Kaydet ve Onay için gönder + Önizle + Önizleme kapalı, Atanmış şablon yok + Stili seçin + Stilleri Göster + Tablo Ekle - To change the document type for the selected content, first select from the list of valid types for this location. - Then confirm and/or amend the mapping of properties from the current type to the new, and click Save. - The content has been re-published. - Current Property - Current type - The document type cannot be changed, as there are no alternatives valid for this location. An alternative will be valid if it is allowed under the parent of the selected content item and that all existing child content items are allowed to be created under it. - Document Type Changed - Map Properties - Map to Property - New Template - New Type - none - Content - Select New Document Type - The document type of the selected content has been successfully changed to [new type] and the following properties mapped: - to - Could not complete property mapping as one or more properties have more than one mapping defined. - Only alternate types valid for the current location are displayed. + Seçilen içerik için belge türünü değiştirmek için , öncelikle bu konum için geçerli türleri listesinden seçim yapın. + Ardından onaylamak ve / veya yeni akım tip özellikleri haritalama değişiklik ve Kaydet'i tıklatın . + İçerik yeniden yayımlanmıştır . + Güncel Mülkiyet + Güncel tip + Bu konum için geçerli hiçbir alternatifi olduğu gibi belge türü , değiştirilemez . Seçilen içerik öğesinin ebeveyn altında izin verilir ve mevcut tüm alt içerik öğeleri altında oluşturulacak izin eğer bir alternatif geçerli olacaktır . + Belge Türü değiştirildi + harita Özellikleri + Mülkiyet Harita + Yeni Şablon + Yeni Tip + Hiçbiri + İçerik + Yeni Belge Tipi Seçiniz + Seçilen içeriğin belge türü başarıyla [ yeni tip ] değişti ve aşağıdaki özellikleri eşleştirilmiş edilmiştir : + için + Bir veya daha fazla özellikleri olarak mülkiyet haritalama tamamlayamadı birden fazla eşleme tanımlanmış var. + Bulunduğunuz yerin için geçerli Sadece alternatif türleri görüntülenir. - Is Published - About this page - Alias - (how would you describe the picture over the phone) - Alternative Links - Click to edit this item - Created by - Original author - Updated by - Created - Date/time this document was created - Document Type - Editing - Remove at - This item has been changed after publication - This item is not published - Last published - There are no items to show in the list. - Media Type - Link to media item(s) - Member Group - Role - Member Type - No date chosen - Page Title - Properties - This document is published but is not visible because the parent '%0%' is unpublished - Oops: this document is published but is not in the cache (internal error) - Publish - Publication Status - Publish at - Unpublish at - Clear Date - Sortorder is updated - To sort the nodes, simply drag the nodes or click one of the column headers. You can select multiple nodes by holding the "shift" or "control" key while selecting - Statistics - Title (optional) - Alternative text (optional) - Type - Unpublish - Last edited - Date/time this document was edited - Remove file(s) - Link to document - Member of group(s) - Not a member of group(s) - Child items - Target + Yayımlandı + Bu sayfa hakkında + takma ad + ( nasıl telefon üzerinden resim anlatırsınız ) + Alternatif Linkler + Bu öğeyi düzenlemek için tıklayın + Tarafından yaratıldı + orijinal yazar + tarafından güncellendi + oluşturuldu + Bu belgenin oluşturulduğu tarih / zaman + Belge Türü + kurgu + en kaldır + Bu madde yayınlanmasından sonra değiştirildi + Bu öğe yayınlanmadı + Son yayınlanan + Listede gösterilecek öğe yok. + Medya Türü + Medya öğesinin bağlantı ( lar) + Üye Grubu + rol + Üye Türü + Hiçbir tarih seçildi + Sayfa başlığı + Özellikler + Ebeveyn ' %0% ' yayımlanmamış olduğu için bu belge yayınladı ama görünür değildir + Hata : Bu ​​belge yayınlandı ancak önbellek ( iç hata ) değil + yayınlamak + Yayın Durum + en Yayınla + en yayından + temizle tarihi + Sıralama güncellenir + Düğümlerini sıralamak için, sadece düğümleri sürükleyin veya sütun başlıkları birini tıklatın . Seçerken " shift " veya " kontrol " tuşunu basılı tutarak birden fazla düğüm seçebilirsiniz + istatistik + Başlık (isteğe bağlı) + Alternatif metin (isteğe bağlı) + tip + Yayından + Son düzenleme + Bu belgenin düzenlendiği tarih / zaman + Dosya(ları) kaldırın + Belgeye Bağlantı + Grubun Üyesi(leri) + Grubun bir üyesi değil + Çocuk öğeleri + hedef - Click to upload - Drop your files here... - Link to media - - - Create a new member - All Members + Yüklemek için tıklayın + Burada açılan dosyaları ... + Medya Linki - Where do you want to create the new %0% - Create an item under - Choose a type and a title - "document types".]]> - "media types".]]> + Nerede yeni %0% yaratmak istiyorsun + Altında bir öğe oluşturun + Bir tür ve bir başlık seçin + "belge türleri".]]> + "ortam türleri".]]> - Browse your website - - Hide - If Umbraco isn't opening, you might need to allow popups from this site - has opened in a new window - Restart - Visit - Welcome + Web sitenizi tarayın + - gizle + CMS açılış değilse , bu siteden pop-up izin gerekebilir + Yeni bir pencere açtı + Tekrar başlat + ziyaret + hoşgeldiniz - Name - Manage hostnames - Close this window - Are you sure you want to delete - Are you sure you want to disable - Please check this box to confirm deletion of %0% item(s) - Are you sure? - Are you sure? - Cut - Edit Dictionary Item - Edit Language - Insert local link - Insert character - Insert graphic headline - Insert picture - Insert link - Click to add a Macro - Insert table - Last Edited - Link - Internal link: - When using local links, insert "#" in front of link - Open in new window? - Macro Settings - This macro does not contain any properties you can edit - Paste - Edit Permissions for - The items in the recycle bin are now being deleted. Please do not close this window while this operation takes place - The recycle bin is now empty - When items are deleted from the recycle bin, they will be gone forever - regexlib.com's webservice is currently experiencing some problems, which we have no control over. We are very sorry for this inconvenience.]]> - Search for a regular expression to add validation to a form field. Example: 'email, 'zip-code' 'url' - Remove Macro - Required Field - Site is reindexed - The website cache has been refreshed. All publish content is now up to date. While all unpublished content is still unpublished - The website cache will be refreshed. All published content will be updated, while unpublished content will stay unpublished. - Number of columns - Number of rows - Set a placeholder id by setting an ID on your placeholder you can inject content into this template from child templates, - by referring this ID using a <asp:content /> element.]]> - Select a placeholder id from the list below. You can only - choose Id's from the current template's master.]]> - Click on the image to see full size - Pick item - View Cache Item + isim + konak yönetin + Bu pencereyi kapatın + Silmek istediğine emin misin + Eğer devre dışı bırakmak istediğinizden emin misiniz + %0% öğe(lerin) silinmesi onaylamak için bu kutuyu kontrol edin + Emin misiniz? + Emin misiniz? + Kes + Düzenleme Sözlük Öğe + Dil Düzenleme + Yerel bağlantı ekleme + Karakter Ekle + Grafik başlığı ekleyin + Resim ekle + Link Ekle + Bir makro eklemek için tıklayın + Tablo Ekle + Son DÜzenleme + Bağlantı + İç Bağlantı: + Yerel bağlantıları kullanırken, bağlantının önündeki "# " insert + Yeni pencerede aç + Makro ayarları + Düzenleyebileceğiniz Bu makro herhangi bir özellikleri içermiyor + Yapıştır + İzinleri düzenle + Geri dönüşüm kutusu öğeleri şimdi siliniyor. Bu işlem gerçekleşirken bu pencereyi kapatın etmeyiniz + Geri dönüşüm kutusu artık boş + Öğeleri geri dönüşüm kutusu silindiğinde, onlar sonsuza kadar gitmiş olacak + regexlib.com's webcoder şu anda üzerinde hiçbir kontrole sahip bazı sorunları, yaşanıyor. Bu rahatsızlıktan dolayı çok üzgünüz.]]> + Bir düzenli ifade arama form alanına doğrulama ekleyin. Örnek: 'E-posta', zip code 'url' + Makro kaldır + Gerekli alan + Site yeniden indekslendi + Web sitesi yenilendi önbelleği olmuştur. Tüm içerik güncel artık yayımlamak. Tüm yayınlanmamış içeriği hala yayınlanmamış olmakla birlikte + Web sitesi önbelleği yenilenir olacaktır. Yayınlanmamış içerik yayınlanmamış kalacak ise tüm yayınlanan içerik, güncellenecektir. + Sütün sayısı + Satır sayısı + + Yer tutucu kimliği ayarla senin tutucu bir kimlik ayarlayarak Çocuğunuz şablonları bu şablon içine içerik enjekte edebilir, + Bir kullanarak bu kimliği bakarak <asp:content /> element.]]> + + + Yer tutucu kimliği seçin Aşağıdaki listeden. You can sadece +       Geçerli şablonun ustadan kimliği sitesinin seçin.]]> + + Tam boyutta görmek için resmin üzerine tıklayın + öğeyi seçin + Görünüm Önbellek Öğe - %0%' below
You can add additional languages under the 'languages' in the menu on the left - ]]>
- Culture Name + + %0%' aşağıda
Sol taraftaki menüden 'diller' başlığı altında ek dil ekleyebilirsiniz + ]]> +
+ Kültür adı - Enter your username - Enter your password - Name the %0%... - Enter a name... - Type to search... - Type to filter... - Type to add tags (press enter after each tag)... + Kullanıcı adınızı giriniz + Parolanızı giriniz + Ad %0%... + Adınızı girin... + Aramak için yazın... + Filtrelemek için yazın... + (Basın, her etiketinden sonra girin) etiket eklemek için yazın ... - - Allow at root - Only Content Types with this checked can be created at the root level of Content and Media trees - Allowed child node types - Document Type Compositions - Create - Delete tab - Description - New tab - Tab - Thumbnail - Enable list view - Configures the content item to show a sortable & searchable list of its children, the children will not be shown in the tree - Current list view - The active list view data type - Create custom list view - Remove custom list view + Root'a izin ver + Bu Sadece İçerik Türleri İçerik ve Medya ağaçların kök düzeyinde oluşturulabilir kontrol + İzin alt düğüm çeşitleri + Belge Türü kompozisyonlar + Oluştur + Sekmesini sil + Tanım + Yeni sekme + Sekme + Küçük resim + Lüste görünümü etkinleştir + Bir sıralanabilir & göstermek için içerik öğesini yapılandırır; kendi çocuklarının aranabilir liste, çocuk ağacında gösterilen olmayacak + Liste görünümü + Etkin liste görünümü veri türü + Özel liste görünüm oluşturun + Özel liste görünümü kaldır - Add prevalue - Database datatype - Property editor GUID - Property editor - Buttons - Enable advanced settings for - Enable context menu - Maximum default size of inserted images - Related stylesheets - Show label - Width and height + Ön değer ekle + Veritabanı veritürü + Mülkiyet editörü GUID + Mülkiyet editörü + Düğmeler + Gelişmiş ayarları etkinleştir... + Bağlam menüsünü etkinleştir + Eklenen görüntülerin maksimum varsayılan boyutu + İlgili stil + Etiketi göster + Yükseklik ve Genişlik - Your data has been saved, but before you can publish this page there are some errors you need to fix first: - The current membership provider does not support changing password (EnablePasswordRetrieval need to be true) - %0% already exists - There were errors: - There were errors: - The password should be a minimum of %0% characters long and contain at least %1% non-alpha numeric character(s) - %0% must be an integer - The %0% field in the %1% tab is mandatory - %0% is a mandatory field - %0% at %1% is not in a correct format - %0% is not in a correct format + Verileriniz kaydedildi, ancak bu sayfayı yayınlamak için önce ilk düzeltmek için gereken bazı hatalar vardır: + Geçerli üyelik sağlayıcısı değişen şifreyi desteklemiyor (EnablePasswordRetrieval doğru olması gerekir) + %0% zaten var + Hatalar vardı: + Hatalar vardı: + Şifre %0% karakter uzunluğunda en az olması ve en az %1% non-alfa sayısal karakter (ler) içermelidir + %0% bir tamsayı olmalıdır + %1% sekmesinde %0% alan zorunludur + %0% zorunlu bir alandır + %0% - %1% bir doğru biçimde değil + %0% Bir doğru biçimde değil - The specified file type has been disallowed by the administrator - NOTE! Even though CodeMirror is enabled by configuration, it is disabled in Internet Explorer because it's not stable enough. - Please fill both alias and name on the new property type! - There is a problem with read/write access to a specific file or folder - Error loading Partial View script (file: %0%) + Belirtilen dosya türü yönetici tarafından izin verilmeyen olmuştur + NOT! CodeMirror yapılandırma tarafından etkin olsa bile yeterince kararlı değil, çünkü Internet Explorer'da devre dışı bırakılır. + Yeni özellik tipine takma adını ve hem de doldurunuz! + Belirli bir dosya veya klasör için okuma / yazma erişimi olan bir sorun var + Error loading Partial View script (Dosya: %0%) Error loading userControl '%0%' Error loading customControl (Assembly: %0%, Type: '%1%') - Error loading MacroEngine script (file: %0%) + Error loading MacroEngine script (Dosya: %0%) "Error parsing XSLT file: %0% - "Error reading XSLT file: %0% - Please enter a title - Please choose a type - You're about to make the picture larger than the original size. Are you sure that you want to proceed? - Error in python script - The python script has not been saved, because it contained error(s) - Startnode deleted, please contact your administrator - Please mark content before changing style - No active styles available - Please place cursor at the left of the two cells you wish to merge - You cannot split a cell that hasn't been merged. - Error in XSLT source - The XSLT has not been saved, because it contained error(s) - There is a configuration error with the data type used for this property, please check the data type + "Error reading XSLT file: %0% + Lütfen bir başlık girin + Lütfen bir tür seçin + Orijinal boyutundan daha resmi büyütmek üzereyiz. Devam etmek istediğinizden emin misiniz? + Python komut dosyası hatası + O hatayı içerdiği için python komut dosyası, kaydedilmemiş (ler) + Silinen düğüm başlatın, lütfen yöneticinize başvurun + Tarzı değiştirmeden önce içerik işaretleyiniz + Henüz aktif stilleri + Birleştirmek istediğiniz iki hücre solundaki imleci Lütfen + Sen birleştirilmiş henüz bir hücreyi bölemezsiniz. + XSLT kaynak hatae + O hatayı içerdiği XSLT, kaydedilmemiş (ler)) + Bu özellik için kullanılan veri türüne sahip bir yapılandırma hatası var, veri türünü kontrol edin - About - Action - Actions - Add - Alias - Are you sure? - Border - by - Cancel - Cell margin - Choose - Close - Close Window - Comment - Confirm - Constrain proportions - Continue - Copy - Create - Database - Date - Default - Delete - Deleted - Deleting... - Design - Dimensions - Down - Download - Edit - Edited - Elements - Email - Error - Find - Height - Help - Icon - Import - Inner margin - Insert - Install - Justify - Language - Layout - Loading - Locked - Login - Log off - Logout - Macro - Move - More - Name - New - Next - No - of - OK - Open - or - Password - Path - Placeholder ID - One moment please... - Previous - Properties - Email to receive form data - Recycle Bin - Remaining - Rename - Renew - Required - Retry - Permissions - Search - Server - Show - Show page on Send - Size - Sort - Type - Type to search... - Up - Update - Upgrade - Upload - Url - User - Username - Value - View - Welcome... - Width - Yes - Folder - Search results + Hakkında + Eylem + Eylemler + Ekle + Takma ad + Emin misiniz? + Sınır + tarafında + İptal + hücre marjı + Seçim + Kapat + Pencereyi kapat + Açıklama + Onayla + oranları sınırlamak + Devam et + Kopyala + Oluştur + Veritabanı + Tarih + Standart + Sil + Silindi + Siliniyor... + Dizayn + Boyutlar + Aşağı + İndir + Düzenle + Düzenlendi + Elemanları + E-Posta + Hata + Bul + Yükseklik + Yardım + İkon + İthalat + İç Marj + Ekle + Kur + Satır Uzunluğu + Dil + Düzen + Yükleniyor + Kilitli + Giriş yap + Oturum Kapat + Çıkış yap + Makro + Taşı + Daha + Ad + Yeni + Sonraki + Hayır + arasında + TAMAM + + veya + Parola + Yol + Yer tutucu ID + Bir dakika lütfen... + Önceki + Özellikler + Form verilerini almak için e-posta + Geridönüşüm kutusu + Kalan + Adını Değiştir + Yenile + Gerekli + Tekrar dene + İzinler + Arama + Sunucu + Göster + Gönder sayfasını göster + Boyut + Sırala + Tip + Aramak için yazın... + Yukarı + Güncelle + Yükselt + Yükle + URL + Kullanıcı + Kullanıcı adı + Değer + Görünüm + Hoşgeldiniz... + Genişlik + Evet + Klasör + Arama Sonuçları - Background color - Bold - Text color - Font - Text + Arka plan rengi + Kalın + Metin Rengi + Yazı + Metin - Page + Sayfa - The installer cannot connect to the database. - Could not save the web.config file. Please modify the connection string manually. - Your database has been found and is identified as - Database configuration - install button to install the Umbraco %0% database - ]]> - Next to proceed.]]> - Database not found! Please check that the information in the "connection string" of the "web.config" file is correct.

-

To proceed, please edit the "web.config" file (using Visual Studio or your favourite text editor), scroll to the bottom, add the connection string for your database in the key named "UmbracoDbDSN" and save the file.

+ Yükleyici veritabanına bağlanamıyor. + Web.config dosyasını kaydedilemedi. El bağlantı dizesini değiştirin lütfen. + Web.config dosyasını kaydedilemedi. El bağlantı dizesini değiştirin lütfen.... + Veritabanı yapılandırması + + Kurulum için dğümeye basın %0% veritabanı + ]]> + + Sonraki Devam için.]]> + + Veritabanı bulunamadı! "Web.config" nin "bağlantı dizesinde" bilgi dosyası doğru olup olmadığını kontrol edin.

+

Devam etmek için, (Visual Studio veya sevdiğiniz metin editörü kullanarak) "web.config" dosyasını düzenlemek lütfen, altına gidin "UmbracoDbDSN" adlı anahtarı veritabanınız için bağlantı dizesini eklemek ve dosyayı kaydedin.

- Click the retry button when - done.
- More information on editing web.config here.

]]>
- - Please contact your ISP if necessary. - If you're installing on a local machine or server you might need information from your system administrator.]]> - Tekrar dene. +
+ + Burada düzenleme web.config Hakkında Daha Fazla Bilgi.

]]> +
+ + + Gerekirse ISS'nize irtibata geçiniz. + Eğer yerel makine veya sunucu üzerinde yükleme ediyorsanız, sistem yöneticinizden bilgi gerekebilir.]]> + + + - Press the upgrade button to upgrade your database to Umbraco %0%

+ CMS %0% için veritabanını yükseltme için yükseltme düğmesine basın +

- Don't worry - no content will be deleted and everything will continue working afterwards! + Merak etmeyin - hiçbir içerik silinmeyecek ve her şey sonradan çalışmaya devam edecektir!

- ]]>
- Press Next to - proceed. ]]> + ]]> +
+ + Sonraki işlem. ]]> + next to continue the configuration wizard]]> The Default users' password needs to be changed!]]> The Default user has been disabled or has no access to Umbraco!

No further actions needs to be taken. Click Next to proceed.]]> The Default user's password has been successfully changed since the installation!

No further actions needs to be taken. Click Next to proceed.]]> The password is changed! - + Umbraco creates a default user with a login ('admin') and password ('default'). It's important that the password is changed to something unique. @@ -472,48 +491,64 @@

This step will check the default user's password and suggest if it needs to be changed.

- ]]>
+ ]]> + Get a great start, watch our introduction videos By clicking the next button (or modifying the umbracoConfigurationStatus in web.config), you accept the license for this software as specified in the box below. Notice that this Umbraco distribution consists of two different licenses, the open source MIT license for the framework and the Umbraco freeware license that covers the UI. Not installed yet. Affected files and folders More information on setting up permissions for Umbraco here You need to grant ASP.NET modify permissions to the following files/folders - Your permission settings are almost perfect!

- You can run Umbraco without problems, but you will not be able to install packages which are recommended to take full advantage of Umbraco.]]>
+ + Your permission settings are almost perfect!

+ You can run Umbraco without problems, but you will not be able to install packages which are recommended to take full advantage of Umbraco.]]> +
How to Resolve Click here to read the text version video tutorial on setting up folder permissions for Umbraco or read the text version.]]> - Your permission settings might be an issue! + + Your permission settings might be an issue!

- You can run Umbraco without problems, but you will not be able to create folders or install packages which are recommended to take full advantage of Umbraco.]]>
- Your permission settings are not ready for Umbraco! + You can run Umbraco without problems, but you will not be able to create folders or install packages which are recommended to take full advantage of Umbraco.]]> + + + Your permission settings are not ready for Umbraco!

- In order to run Umbraco, you'll need to update your permission settings.]]>
- Your permission settings are perfect!

- You are ready to run Umbraco and install packages!]]>
+ In order to run Umbraco, you'll need to update your permission settings.]]> +
+ + Your permission settings are perfect!

+ You are ready to run Umbraco and install packages!]]> +
Resolving folder issue Follow this link for more information on problems with ASP.NET and creating folders Setting up folder permissions - + - I want to start from scratch - + + Baştan başlamak istiyorum + + learn how) You can still choose to install Runway later on. Please go to the Developer section and choose Packages. - ]]> + ]]> + You've just set up a clean Umbraco platform. What do you want to do next? Runway is installed - + This is our list of recommended modules, check off the ones you would like to install, or view the full list of modules - ]]> + ]]> + Only recommended for experienced users I want to start with a simple website - + "Runway" is a simple website providing some basic document types and templates. The installer can set up Runway for you automatically, but you can easily edit, extend or remove it. It's not necessary and you can perfectly use Umbraco without it. However, @@ -524,7 +559,8 @@ Included with Runway: Home page, Getting Started page, Installing Modules page.
Optional Modules: Top Navigation, Sitemap, Contact, Gallery. - ]]>
+ ]]> + What is Runway Step 1/5 Accept license Step 2/5: Database configuration @@ -532,49 +568,61 @@ Step 4/5: Check Umbraco security Step 5/5: Umbraco is ready to get you started Thank you for choosing Umbraco - Browse your new site -You installed Runway, so why not see how your new website looks.]]> - Further help and information -Get help from our award winning community, browse the documentation or watch some free videos on how to build a simple site, how to use packages and a quick guide to the Umbraco terminology]]> + + Browse your new site +You installed Runway, so why not see how your new website looks.]]> + + + Further help and information +Get help from our award winning community, browse the documentation or watch some free videos on how to build a simple site, how to use packages and a quick guide to the Umbraco terminology]]> + Umbraco %0% is installed and ready for use - /web.config file and update the AppSetting key UmbracoConfigurationStatus in the bottom to the value of '%0%'.]]> - started instantly by clicking the "Launch Umbraco" button below.
If you are new to Umbraco, -you can find plenty of resources on our getting started pages.]]>
- Launch Umbraco -To manage your website, simply open the Umbraco back office and start adding content, updating the templates and stylesheets or add new functionality]]> + + /web.config file and update the AppSetting key UmbracoConfigurationStatus in the bottom to the value of '%0%'.]]> + + + started instantly by clicking the "Launch Umbraco" button below.
If you are new to Umbraco, +you can find plenty of resources on our getting started pages.]]> +
+ + Launch Umbraco +To manage your website, simply open the Umbraco back office and start adding content, updating the templates and stylesheets or add new functionality]]> + Connection to database failed. Umbraco Version 3 Umbraco Version 4 Watch - Umbraco %0% for a fresh install or upgrading from version 3.0. + + Umbraco %0% for a fresh install or upgrading from version 3.0.

- Press "next" to start the wizard.]]>
+ Press "next" to start the wizard.]]> +
- Culture Code - Culture Name + Kültür Kodu + Kültür Adı - You've been idle and logout will automatically occur in - Renew now to save your work + Sen boşta oldum ve çıkış otomatik olarak gerçekleşecek + İşinizi kaydetmek için şimdi Yenile - Happy super Sunday - Happy manic Monday - Happy tubular Tuesday - Happy wonderful Wednesday - Happy thunderous Thursday - Happy funky Friday - Happy Caturday - Log in below - Session timed out - © 2001 - %0%
Umbraco.com

]]>
+ Pazar + Pazartesi + Salı + Çarşamba + Perşembe + Cuma + İçerik Yönetim Sistemi + Giriş Yapın + Oturum zaman aşımına uğradı + © 2015 - %0%
kayadata.com

]]>
- Dashboard - Sections - Content + Gösterge Paneli + Bölümler + İçerik Choose page above... @@ -592,7 +640,8 @@ To manage your website, simply open the Umbraco back office and start adding con Edit your notification for %0% - + - Hi %0%

+ ]]> +
+ + Hi %0%

This is an automated mail to inform you that the task '%1%' has been performed on the page '%2%' @@ -631,23 +682,28 @@ To manage your website, simply open the Umbraco back office and start adding con

Have a nice day!

Cheers from the Umbraco robot -

]]>
+

]]> + [%0%] Notification about %1% performed on %2% Notifications - + button and locating the package. Umbraco packages usually have a ".umb" or ".zip" extension. - ]]> + ]]> + Author Demonstration Documentation Package meta data Package name Package doesn't contain any items -
- You can safely remove this from the system by clicking "uninstall package" below.]]>
+ +
+ You can safely remove this from the system by clicking "uninstall package" below.]]> +
No upgrades available Package options Package readme @@ -656,9 +712,11 @@ To manage your website, simply open the Umbraco back office and start adding con Package was uninstalled The package was successfully uninstalled Uninstall package - + + Notice: any documents, media etc depending on the items you remove, will stop working, and could lead to system instability, - so uninstall with caution. If in doubt, contact the package author.]]> + so uninstall with caution. If in doubt, contact the package author.]]> + Download update from the repository Upgrade package Upgrade instructions @@ -697,38 +755,43 @@ To manage your website, simply open the Umbraco back office and start adding con %0% could not be published because the item is scheduled for release. ]]> - - + - + + + - + + + + ]]> + Include unpublished child pages Publishing in progress - please wait... %0% out of %1% pages have been published... %0% has been published %0% and subpages have been published Publish %0% and all its subpages - ok to publish %0% and thereby making its content publicly available.

+ + ok to publish %0% and thereby making its content publicly available.

You can publish this page and all it's sub-pages by checking publish all children below. - ]]>
+ ]]> +
- You have not configured any approved colors + You have not configured any approved colours enter external link choose internal page Caption Link - Open in new window - enter the display caption + New window + Enter a new caption Enter the link @@ -744,34 +807,34 @@ To manage your website, simply open the Umbraco back office and start adding con View - Edit script file + Düzenleme komut dosyası - Concierge - Content - Courier - Developer - Umbraco Configuration Wizard - Media - Members - Newsletters - Settings - Statistics - Translation - Users - Help - Forms + Kapıcı + İçerik + Kurya + Geliştirici + CMS Yapılandırma Sihirbazı + Medya + Üyeler + Haber Bültenleri + Ayarlar + İstatistik + Çeviri + Kullanıcılar + Yardım + Formlar Analytics - go to + git Help topics for Video chapters for - The best Umbraco video tutorials + Kayadata - Default template - Dictionary Key + Varsayılan şablonu + Sözlük Key To import a document type, find the ".udt" file on your computer by clicking the "Browse" button and click "Import" (you'll be asked for confirmation on the next screen) New Tab Title Node type @@ -795,11 +858,11 @@ To manage your website, simply open the Umbraco back office and start adding con
Do not close this window during sorting]]>
- Failed - Insufficient user permissions, could not complete the operation - Cancelled - Operation was cancelled by a 3rd party add-in - Publishing was cancelled by a 3rd party add-in + Hata + Kullanıcı izniniz yeterli olmadığı için, işleminiz gerçekleştirilmedi. + İptal Edildi + İşleminiz 3.Parti yazılım tarafından iptal edildi. + Sayfa yayınlama 3.Parti yazılım tarafından iptal edildi. Property type already exists Property type created DataType: %1%]]> @@ -879,7 +942,7 @@ To manage your website, simply open the Umbraco back office and start adding con Insert control - Choose a layout for this section + Choose a layout for the page below and add your first element]]> Click to embed @@ -943,10 +1006,12 @@ To manage your website, simply open the Umbraco back office and start adding con Tasks assigned to you - assigned to you. To see a detailed view including comments, click on "Details" or just the page name. + + assigned to you. To see a detailed view including comments, click on "Details" or just the page name. You can also download the page as XML directly by clicking the "Download Xml" link.
To close a translation task, please go to the Details view and click the "Close" button. - ]]>
+ ]]> +
close task Translation details Download all translation tasks as XML @@ -954,7 +1019,8 @@ To manage your website, simply open the Umbraco back office and start adding con Download XML DTD Fields Include subpages - + + ]]> + [%0%] Translation task for %1% No translator users found. Please create a translator user before you start sending content to translation Tasks created by you - created by you. To see a detailed view including comments, + + created by you. To see a detailed view including comments, click on "Details" or just the page name. You can also download the page as XML directly by clicking the "Download Xml" link. To close a translation task, please go to the Details view and click the "Close" button. - ]]> + ]]> + The page '%0%' has been send to translation Send the page '%0%' to translation Assigned by @@ -1027,47 +1096,47 @@ To manage your website, simply open the Umbraco back office and start adding con Error checking for update. Please review trace-stack for further information - Administrator - Category field - Change Your Password - Change Your Password - Confirm new password - You can change your password for accessing the Umbraco Back Office by filling out the form below and click the 'Change Password' button - Content Channel - Description field - Disable User - Document Type - Editor - Excerpt field - Language - Login - Start Node in Media Library - Sections - Disable Umbraco Access - Password - Reset password - Your password has been changed! - Please confirm the new password - Enter your new password - Your new password cannot be blank! - Current password - Invalid current password - There was a difference between the new password and the confirmed password. Please try again! - The confirmed password doesn't match the new password! - Replace child node permissions - You are currently modifying permissions for the pages: - Select pages to modify their permissions - Search all children - Start Node in Content - Name - User permissions - User type - User types - Writer + Yönetici + Kategori alanı + Şifreni değiştir + Şifreni değiştir + Yeni şifreyi onaylad + Aşağıdaki formu doldurarak CMS Geri Office'i erişmek için parolanızı değiştirmeniz ve ' Şifre Değiştir ' düğmesine tıklayabilirsiniz + İçerik Kanal + Açıklama alanı + Kullanıcıyı Devre Dışı Bırak + Belge Türü + editör + Alıntı alan + Dil + Kullanıcı adı + Medya Kütüphane düğüm başlatın + Bölümler + CMS Erişim devre dışı bırakma + Parola + Şifre sıfırlamak + Şifreniz değiştirildi! + Yeni parolayı onaylayın Lütfen + Yeni şifrenizi girin + Yeni şifre boş olamaz ! + Mevcut Şifre + Geçersiz Geçerli şifre + Yeni şifre ile teyit şifre arasında bir fark yoktu. Lütfen tekrar deneyin! + Teyit şifre yeni bir şifre eşleşmiyor ! + Alt düğümü izinlerini değiştirin + Şu anda sayfaları için izinleri değiştiriyorsunuz: + Onların izinlerini değiştirmek için sayfaları seçin + Tüm çocukların ara + içerikte Düğüm başlat + İsim + Kullanıcı izinleri + Kullanıcı türü + Kullanıcı tipleri + Yazar Translator Change - Your profile - Your recent history - Session expires in + Profiliniz + Son tarih + Oturum sona eriyor
From deb74939afb981f12cbf0b84147dd04c87e3e612 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Asbj=C3=B8rn=20Riis-Knudsen?= Date: Sat, 23 Apr 2016 17:54:37 +0200 Subject: [PATCH 017/535] U4-8365: Fix decimal property value converter to work on non EN-US cultures --- .../PropertyEditors/ValueConverters/DecimalValueConverter.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/DecimalValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/DecimalValueConverter.cs index 32fe356764..e32ff7af02 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/DecimalValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/DecimalValueConverter.cs @@ -1,4 +1,5 @@ -using Umbraco.Core.Models.PublishedContent; +using System.Globalization; +using Umbraco.Core.Models.PublishedContent; namespace Umbraco.Core.PropertyEditors.ValueConverters { @@ -20,7 +21,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters if (sourceString != null) { decimal d; - return (decimal.TryParse(sourceString, out d)) ? d : 0M; + return (decimal.TryParse(sourceString, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out d)) ? d : 0M; } // in the database an a decimal is an a decimal From fcdf212c4cbf7246901e1b9afd663d053f27417e Mon Sep 17 00:00:00 2001 From: bjarnef Date: Sun, 24 Apr 2016 18:42:46 +0200 Subject: [PATCH 018/535] Rename area alias --- .../views/common/notifications/confirmroutechange.html | 8 ++++---- src/Umbraco.Web.UI/Umbraco/config/lang/cs.xml | 2 +- src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml | 2 +- src/Umbraco.Web.UI/umbraco/config/lang/da.xml | 2 +- src/Umbraco.Web.UI/umbraco/config/lang/de.xml | 2 +- src/Umbraco.Web.UI/umbraco/config/lang/en.xml | 2 +- src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml | 2 +- src/Umbraco.Web.UI/umbraco/config/lang/es.xml | 2 +- src/Umbraco.Web.UI/umbraco/config/lang/fr.xml | 2 +- src/Umbraco.Web.UI/umbraco/config/lang/he.xml | 2 +- src/Umbraco.Web.UI/umbraco/config/lang/it.xml | 2 +- src/Umbraco.Web.UI/umbraco/config/lang/ja.xml | 2 +- src/Umbraco.Web.UI/umbraco/config/lang/ko.xml | 2 +- src/Umbraco.Web.UI/umbraco/config/lang/nl.xml | 2 +- src/Umbraco.Web.UI/umbraco/config/lang/pl.xml | 2 +- src/Umbraco.Web.UI/umbraco/config/lang/pt.xml | 2 +- src/Umbraco.Web.UI/umbraco/config/lang/ru.xml | 2 +- src/Umbraco.Web.UI/umbraco/config/lang/sv.xml | 2 +- src/Umbraco.Web.UI/umbraco/config/lang/zh.xml | 2 +- 19 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/notifications/confirmroutechange.html b/src/Umbraco.Web.UI.Client/src/views/common/notifications/confirmroutechange.html index c3b72f67a8..0b2926307c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/notifications/confirmroutechange.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/notifications/confirmroutechange.html @@ -1,7 +1,7 @@
-

You have unsaved changes

-

Are you sure you want to navigate away from this page? - you have unsaved changes

+

You have unsaved changes

+

Are you sure you want to navigate away from this page? - you have unsaved changes

- - + +
\ No newline at end of file diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/cs.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/cs.xml index 7d6c52ad9b..1ae28daafe 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/cs.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/cs.xml @@ -179,7 +179,7 @@ Navštívit Vítejte - + Stay Discard changes You have unsaved changes diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml index 47bf684818..275267e98c 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml @@ -186,7 +186,7 @@ Besøk Velkommen - + Stay Discard changes You have unsaved changes diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml index 4c3dcc749f..56d8384bb1 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml @@ -187,7 +187,7 @@ Besøg Velkommen - + Bliv Kassér ændringer Du har ikke-gemte ændringer diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/de.xml b/src/Umbraco.Web.UI/umbraco/config/lang/de.xml index a3f40cc0ea..3b4c1ee5ab 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/de.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/de.xml @@ -186,7 +186,7 @@ Besuchen Willkommen - + Stay Discard changes You have unsaved changes diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index 7b476e5e8b..0c21e157a6 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -197,7 +197,7 @@ Visit Welcome - + Stay Discard changes You have unsaved changes 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 534185e5db..4ebcad987c 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml @@ -199,7 +199,7 @@ Visit Welcome - + Stay Discard changes You have unsaved changes diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/es.xml b/src/Umbraco.Web.UI/umbraco/config/lang/es.xml index 9e79db1efa..80e39fe219 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/es.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/es.xml @@ -185,7 +185,7 @@ Visita Bienvenido - + Stay Discard changes You have unsaved changes diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/fr.xml b/src/Umbraco.Web.UI/umbraco/config/lang/fr.xml index 45153d78fa..59021956a5 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/fr.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/fr.xml @@ -181,7 +181,7 @@ Visiter Bienvenue - + Stay Discard changes You have unsaved changes diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/he.xml b/src/Umbraco.Web.UI/umbraco/config/lang/he.xml index fab17bb6a4..aa9c2112e2 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/he.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/he.xml @@ -131,7 +131,7 @@ בקר ברוכים הבאים - + Stay Discard changes You have unsaved changes diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/it.xml b/src/Umbraco.Web.UI/umbraco/config/lang/it.xml index 7c26a2538a..9c0682eba0 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/it.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/it.xml @@ -127,7 +127,7 @@ Visita Benvenuto - + Stay Discard changes You have unsaved changes diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/ja.xml b/src/Umbraco.Web.UI/umbraco/config/lang/ja.xml index 177e9d6aa5..6acfd997e1 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/ja.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/ja.xml @@ -194,7 +194,7 @@ 訪れる ようこそ - + Stay Discard changes You have unsaved changes diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/ko.xml b/src/Umbraco.Web.UI/umbraco/config/lang/ko.xml index db0aa62d11..c7178e312b 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/ko.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/ko.xml @@ -125,7 +125,7 @@ 방문 환영합니다 - + Stay Discard changes You have unsaved changes diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/nl.xml b/src/Umbraco.Web.UI/umbraco/config/lang/nl.xml index 9fb6f51402..7d1a4cc2d3 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/nl.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/nl.xml @@ -188,7 +188,7 @@ Bezoek Welkom - + Stay Discard changes You have unsaved changes diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/pl.xml b/src/Umbraco.Web.UI/umbraco/config/lang/pl.xml index 1a3058e289..c2c8b4d073 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/pl.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/pl.xml @@ -125,7 +125,7 @@ Odwiedź Witaj - + Stay Discard changes You have unsaved changes diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/pt.xml b/src/Umbraco.Web.UI/umbraco/config/lang/pt.xml index 736bb7a507..016f7c2a19 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/pt.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/pt.xml @@ -125,7 +125,7 @@ Visitar Bem Vindo(a) - + Stay Discard changes You have unsaved changes diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml b/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml index 8f039dcc71..e162dbaead 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml @@ -254,7 +254,7 @@ Посетить Рады приветствовать - + Stay Discard changes You have unsaved changes diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/sv.xml b/src/Umbraco.Web.UI/umbraco/config/lang/sv.xml index c397c735b3..ea1f0c9ef0 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/sv.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/sv.xml @@ -181,7 +181,7 @@ Välkommen Besök - + Stay Discard changes You have unsaved changes diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/zh.xml b/src/Umbraco.Web.UI/umbraco/config/lang/zh.xml index 69f938c42d..372bc480cc 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/zh.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/zh.xml @@ -166,7 +166,7 @@ 访问 欢迎 - + Stay Discard changes You have unsaved changes From 89cd2f50d7beefb395c523d5fec40aca7a35b6c3 Mon Sep 17 00:00:00 2001 From: Alexander Bryukhov Date: Sun, 24 Apr 2016 23:09:46 +0600 Subject: [PATCH 019/535] Update UI language ru.xml New area and keys for unsaved changes dialog localization (PR #1234) New keys for list view localization PR #1235 --- src/Umbraco.Web.UI/umbraco/config/lang/ru.xml | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml b/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml index 2fd54be962..1db34c7b7b 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml @@ -66,6 +66,7 @@ Полужирный + Снять выбор Уменьшить отступ Вставить поле формы Сгенерировать модели @@ -91,9 +92,10 @@ Сохранить список Выбрать Выбрать текущую папку + выбранные Предварительный просмотр Предварительный просмотр запрещен, так как документу не сопоставлен шаблон - Сделать что-нибудь еще + Другие действия Выбрать стиль Показать стили Вставить таблицу @@ -185,7 +187,7 @@ Композиции Вы не добавили ни одной вкладки Добавить вкладку - Добавитьеще вкладку + Добавить новую вкладку Унаследован от Добавить свойство Обязательная метка @@ -245,7 +247,7 @@ "Типы документов".]]> "Типы медиа-материалов".]]> Выберите тип и заголовок - Типу документа не сопоставлен шаблон + Тип документа без сопоставленного шаблона Обзор сайта @@ -853,6 +855,12 @@ Метка... Укажите описание... + + Остаться + Отменить изменения + Есть несохраненные изменения + Вы уверены, что хотите уйти с этой страницы? - на ней имеются несохраненные изменения + Расширенный: Защита на основе ролей (групп) с использованием групп участников Umbraco.]]> From 2c3c0eae12d731615ed55cdac44ef1b4a93da374 Mon Sep 17 00:00:00 2001 From: Stephan Date: Mon, 25 Apr 2016 15:37:11 +0200 Subject: [PATCH 020/535] U4-8370 - fix broken upgrade --- .../UpdateRelatedLinksData.cs | 40 ++++---- .../Migrations/MigrationIssuesTests.cs | 94 +++++++++++++++++++ src/Umbraco.Tests/Umbraco.Tests.csproj | 1 + 3 files changed, 116 insertions(+), 19 deletions(-) create mode 100644 src/Umbraco.Tests/Migrations/MigrationIssuesTests.cs diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSeven/UpdateRelatedLinksData.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSeven/UpdateRelatedLinksData.cs index 684196c2e6..63df98795b 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSeven/UpdateRelatedLinksData.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSeven/UpdateRelatedLinksData.cs @@ -32,17 +32,19 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSeven { if (database != null) { - var dtSql = new Sql().Select("nodeId").From().Where(dto => dto.PropertyEditorAlias == Constants.PropertyEditors.RelatedLinksAlias); + var dtSql = new Sql().Select("nodeId") + .From(SqlSyntax) + .Where(dto => dto.PropertyEditorAlias == Constants.PropertyEditors.RelatedLinksAlias); + var dataTypeIds = database.Fetch(dtSql); + if (dataTypeIds.Any() == false) return string.Empty; - if (!dataTypeIds.Any()) return string.Empty; - - // need to use dynamic, as PropertyDataDto has new properties + // need to use dynamic, as PropertyDataDto has new properties (eg decimal...) in further versions that don't exist yet var propertyData = database.Fetch("SELECT * FROM cmsPropertyData" - + " WHERE propertyTypeId in (SELECT id from cmsPropertyType where dataTypeID IN (@dataTypeIds))", new { dataTypeIds = dataTypeIds }); - if (!propertyData.Any()) return string.Empty; + + " WHERE propertyTypeId in (SELECT id from cmsPropertyType where dataTypeID IN (@dataTypeIds))", new { /*dataTypeIds =*/ dataTypeIds }); + if (propertyData.Any() == false) return string.Empty; - var nodesIdsWithProperty = propertyData.Select(x => x.NodeId).Distinct().ToArray(); + var nodesIdsWithProperty = propertyData.Select(x => (int) x.contentNodeId).Distinct().ToArray(); var cmsContentXmlEntries = new List(); //We're doing an "IN" query here but SQL server only supports 2100 query parameters so we're going to split on that @@ -54,32 +56,32 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSeven cmsContentXmlEntries.AddRange(database.Fetch("WHERE nodeId in (@nodeIds)", new { nodeIds = batch })); } - var propertyTypeIds = propertyData.Select(x => x.PropertyTypeId).Distinct(); + var propertyTypeIds = propertyData.Select(x => (int) x.propertytypeid).Distinct(); //NOTE: We are writing the full query because we've added a column to the PropertyTypeDto in later versions so one of the columns // won't exist yet var propertyTypes = database.Fetch("SELECT * FROM cmsPropertyType WHERE id in (@propertyTypeIds)", new { propertyTypeIds = propertyTypeIds }); - + foreach (var data in propertyData) { - if (string.IsNullOrEmpty(data.Text) == false) + if (string.IsNullOrEmpty(data.dataNtext) == false) { XmlDocument xml; //fetch the current data (that's in xml format) try { xml = new XmlDocument(); - xml.LoadXml(data.Text); + xml.LoadXml(data.dataNtext); } catch (Exception ex) { int dataId = data.id; - int dataNodeId = data.nodeId; - string dataText = data.dataNText; - Logger.Error("The data stored for property id " + dataId + " on document " + dataNodeId + + int dataNodeId = data.contentNodeId; + string dataText = data.dataNtext; + Logger.Error("The data stored for property id " + dataId + " on document " + dataNodeId + " is not valid XML, the data will be removed because it cannot be converted to the new format. The value was: " + dataText, ex); - data.dataNText = ""; + data.dataNtext = ""; database.Update("cmsPropertyData", "id", data, new[] { "dataNText" }); UpdateXmlTable(propertyTypes, data, cmsContentXmlEntries, database); @@ -113,7 +115,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSeven } //store the serialized data - data.dataNText = JsonConvert.SerializeObject(links); + data.dataNtext = JsonConvert.SerializeObject(links); database.Update("cmsPropertyData", "id", data, new[] { "dataNText" }); @@ -130,13 +132,13 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSeven throw new DataLossException("Cannot downgrade from a version 7 database to a prior version, the database schema has already been modified"); } - private static void UpdateXmlTable(List propertyTypes, PropertyDataDto data, List cmsContentXmlEntries, Database database) + private static void UpdateXmlTable(List propertyTypes, dynamic data, List cmsContentXmlEntries, Database database) { //now we need to update the cmsContentXml table - var propertyType = propertyTypes.SingleOrDefault(x => x.Id == data.PropertyTypeId); + var propertyType = propertyTypes.SingleOrDefault(x => x.Id == data.propertytypeid); if (propertyType != null) { - var xmlItem = cmsContentXmlEntries.SingleOrDefault(x => x.NodeId == data.NodeId); + var xmlItem = cmsContentXmlEntries.SingleOrDefault(x => x.NodeId == data.contentNodeId); if (xmlItem != null) { var x = XElement.Parse(xmlItem.Xml); diff --git a/src/Umbraco.Tests/Migrations/MigrationIssuesTests.cs b/src/Umbraco.Tests/Migrations/MigrationIssuesTests.cs new file mode 100644 index 0000000000..55d60eed66 --- /dev/null +++ b/src/Umbraco.Tests/Migrations/MigrationIssuesTests.cs @@ -0,0 +1,94 @@ +using System; +using System.Linq; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Core.Models.Rdbms; +using Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSeven; +using Umbraco.Tests.TestHelpers; + +namespace Umbraco.Tests.Migrations +{ + [TestFixture] + [DatabaseTestBehavior(DatabaseBehavior.NewDbFileAndSchemaPerTest)] + public class MigrationIssuesTests : BaseDatabaseFactoryTest + { + [Test] + public void Issue8370Test() + { + // fixme maybe we need to create some content? + // yes otherwise cannot get it to fail! + + var n = new NodeDto + { + Text = "text", + CreateDate = DateTime.Now, + Path = "-1", + ParentId = -1, + UniqueId = Guid.NewGuid() + }; + DatabaseContext.Database.Insert(n); + var ct = new ContentTypeDto + { + Alias = "alias", + NodeId = n.NodeId, + Thumbnail = "thumb" + }; + DatabaseContext.Database.Insert(ct); + n = new NodeDto + { + Text = "text", + CreateDate = DateTime.Now, + Path = "-1", + ParentId = -1, + UniqueId = Guid.NewGuid() + }; + DatabaseContext.Database.Insert(n); + var dt = new DataTypeDto + { + PropertyEditorAlias = Constants.PropertyEditors.RelatedLinksAlias, + DbType = "x", + DataTypeId = n.NodeId + }; + DatabaseContext.Database.Insert(dt); + var pt = new PropertyTypeDto + { + Alias = "alias", + ContentTypeId = ct.NodeId, + DataTypeId = dt.DataTypeId + }; + DatabaseContext.Database.Insert(pt); + n = new NodeDto + { + Text = "text", + CreateDate = DateTime.Now, + Path = "-1", + ParentId = -1, + UniqueId = Guid.NewGuid() + }; + DatabaseContext.Database.Insert(n); + var data = new PropertyDataDto + { + NodeId = n.NodeId, + PropertyTypeId = pt.Id, + Text = "text" + }; + DatabaseContext.Database.Insert(data); + data = new PropertyDataDto + { + NodeId = n.NodeId, + PropertyTypeId = pt.Id, + Text = "" + }; + DatabaseContext.Database.Insert(data); + + var migration = new UpdateRelatedLinksData(SqlSyntax, Logger); + migration.UpdateRelatedLinksDataDo(DatabaseContext.Database); + + data = DatabaseContext.Database.Fetch("SELECT * FROM cmsPropertyData WHERE id=" + data.Id).FirstOrDefault(); + Assert.IsNotNull(data); + Console.WriteLine(data.Text); + Assert.AreEqual("[{\"title\":\"\",\"caption\":\"\",\"link\":\"\",\"newWindow\":false,\"type\":\"external\",\"internal\":null,\"edit\":false,\"isInternal\":false}]", + data.Text); + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Tests/Umbraco.Tests.csproj b/src/Umbraco.Tests/Umbraco.Tests.csproj index bb87abc83b..d8657cc515 100644 --- a/src/Umbraco.Tests/Umbraco.Tests.csproj +++ b/src/Umbraco.Tests/Umbraco.Tests.csproj @@ -175,6 +175,7 @@ + From 066ef6809be155ef2e79957dbfdb1ce82e6811f6 Mon Sep 17 00:00:00 2001 From: Chriztian Steinmeier Date: Tue, 26 Apr 2016 23:36:42 +0200 Subject: [PATCH 021/535] Change the language keys necessary for the fix --- src/Umbraco.Web.UI/umbraco/config/lang/en.xml | 6 +++--- src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index 08521f4580..2e4137dd17 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -812,14 +812,14 @@ To manage your website, simply open the Umbraco back office and start adding con - Include unpublished child pages + Include unpublished subpages Publishing in progress - please wait... %0% out of %1% pages have been published... %0% has been published %0% and subpages have been published Publish %0% and all its subpages - ok to publish %0% and thereby making its content publicly available.

- You can publish this page and all it's sub-pages by checking publish all children below. + Publish to publish %0% and thereby making its content publicly available.

+ You can publish this page and all its subpages by checking Include unpublished subpages below. ]]>
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 6b78e66e7f..af142aafae 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml @@ -811,14 +811,14 @@ To manage your website, simply open the Umbraco back office and start adding con - Include unpublished child pages + Include unpublished subpages Publishing in progress - please wait... %0% out of %1% pages have been published... %0% has been published %0% and subpages have been published Publish %0% and all its subpages - ok to publish %0% and thereby making its content publicly available.

- You can publish this page and all it's sub-pages by checking publish all children below. + Publish to publish %0% and thereby making its content publicly available.

+ You can publish this page and all its subpages by checking Include unpublished subpages below. ]]>
From 6dea69c5a1c4e0278c8059d38e19ad2e07b279bd Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 27 Apr 2016 19:09:49 +0200 Subject: [PATCH 022/535] U4-2508 - improve culture detection in 404 situation --- .../Routing/ContentFinderByLegacy404.cs | 34 ++++++++++++-- .../Routing/NotFoundHandlerHelper.cs | 47 ++++++------------- 2 files changed, 45 insertions(+), 36 deletions(-) diff --git a/src/Umbraco.Web/Routing/ContentFinderByLegacy404.cs b/src/Umbraco.Web/Routing/ContentFinderByLegacy404.cs index 22c4364891..6922510de8 100644 --- a/src/Umbraco.Web/Routing/ContentFinderByLegacy404.cs +++ b/src/Umbraco.Web/Routing/ContentFinderByLegacy404.cs @@ -1,5 +1,7 @@ -using System.Linq; +using System.Globalization; +using System.Linq; using System.Web; +using Umbraco.Core; using Umbraco.Core.Configuration; using Umbraco.Core.Logging; using Umbraco.Core.Models; @@ -20,15 +22,39 @@ namespace Umbraco.Web.Routing { LogHelper.Debug("Looking for a page to handle 404."); + // try to find a culture as best as we can + var errorCulture = CultureInfo.CurrentUICulture; + if (pcr.HasDomain) + { + errorCulture = CultureInfo.GetCultureInfo(pcr.UmbracoDomain.LanguageIsoCode); + } + else + { + var route = pcr.Uri.GetAbsolutePathDecoded(); + var pos = route.LastIndexOf('/'); + IPublishedContent node = null; + while (pos > 1) + { + route = route.Substring(0, pos); + node = pcr.RoutingContext.UmbracoContext.ContentCache.GetByRoute(route); + if (node != null) break; + pos = route.LastIndexOf('/'); + } + if (node != null) + { + var d = DomainHelper.FindWildcardDomainInPath(pcr.RoutingContext.UmbracoContext.Application.Services.DomainService.GetAll(true), node.Path, null); + if (d != null && string.IsNullOrWhiteSpace(d.LanguageIsoCode) == false) + errorCulture = CultureInfo.GetCultureInfo(d.LanguageIsoCode); + } + } + // TODO - replace the whole logic var error404 = NotFoundHandlerHelper.GetCurrentNotFoundPageId( //TODO: The IContentSection should be ctor injected into this class in v8! UmbracoConfig.For.UmbracoSettings().Content.Error404Collection.ToArray(), - //TODO: Is there a better way to extract this value? at least we're not relying on singletons here though - pcr.RoutingContext.UmbracoContext.HttpContext.Request.ServerVariables["SERVER_NAME"], pcr.RoutingContext.UmbracoContext.Application.Services.EntityService, new PublishedContentQuery(pcr.RoutingContext.UmbracoContext.ContentCache, pcr.RoutingContext.UmbracoContext.MediaCache), - pcr.RoutingContext.UmbracoContext.Application.Services.DomainService); + errorCulture); IPublishedContent content = null; diff --git a/src/Umbraco.Web/Routing/NotFoundHandlerHelper.cs b/src/Umbraco.Web/Routing/NotFoundHandlerHelper.cs index 50497ba032..94da38e210 100644 --- a/src/Umbraco.Web/Routing/NotFoundHandlerHelper.cs +++ b/src/Umbraco.Web/Routing/NotFoundHandlerHelper.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Web; using System.Xml; @@ -232,47 +233,29 @@ namespace Umbraco.Web.Routing /// /// internal static int? GetCurrentNotFoundPageId( - IContentErrorPage[] error404Collection, - string requestServerName, + IContentErrorPage[] error404Collection, + string requestServerName, IEntityService entityService, ITypedPublishedContentQuery publishedContentQuery, IDomainService domainService) { - if (error404Collection.Count() > 1) + throw new NotImplementedException(); + } + + internal static int? GetCurrentNotFoundPageId( + IContentErrorPage[] error404Collection, + IEntityService entityService, + ITypedPublishedContentQuery publishedContentQuery, + CultureInfo errorCulture) + { + if (error404Collection.Length > 1) { - // try to get the 404 based on current culture (via domain) - IContentErrorPage cultureErr; - - var d = domainService.GetByName(requestServerName); - - if (d != null && d.LanguageId.HasValue) - { - // test if a 404 page exists with current culture - cultureErr = error404Collection - .FirstOrDefault(x => x.Culture == d.LanguageIsoCode); - - if (cultureErr != null) - { - return GetContentIdFromErrorPageConfig(cultureErr, entityService, publishedContentQuery); - } - } - // test if a 404 page exists with current culture thread - cultureErr = error404Collection - .FirstOrDefault(x => x.Culture == System.Threading.Thread.CurrentThread.CurrentUICulture.Name); - if (cultureErr != null) - { - return GetContentIdFromErrorPageConfig(cultureErr, entityService, publishedContentQuery); - } - - // there should be a default one! - cultureErr = error404Collection - .FirstOrDefault(x => x.Culture == "default"); + var cultureErr = error404Collection.FirstOrDefault(x => x.Culture == errorCulture.Name) + ?? error404Collection.FirstOrDefault(x => x.Culture == "default"); // there should be a default one! if (cultureErr != null) - { return GetContentIdFromErrorPageConfig(cultureErr, entityService, publishedContentQuery); - } } else { From 029e50dd3ce23ef312cfde99214e2a6aaa1a28a4 Mon Sep 17 00:00:00 2001 From: "rs@merchello.com" Date: Mon, 2 May 2016 13:17:13 -0700 Subject: [PATCH 023/535] Appends comment and forum reference to developer comment for reference when evaluating code removal. --- .../ValueConverters/MultipleTextStringValueConverter.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/MultipleTextStringValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/MultipleTextStringValueConverter.cs index 6725257888..39bcf85b12 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/MultipleTextStringValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/MultipleTextStringValueConverter.cs @@ -35,6 +35,9 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters // as xml in the database, it's always been new line delimited. Will ask Stephen about this. // In the meantime, we'll do this xml check, see if it parses and if not just continue with // splitting by newline + // + // RS: SD/Stephan Please consider post before deciding to remove + //// https://our.umbraco.org/forum/contributing-to-umbraco-cms/76989-keep-the-xml-values-in-the-multipletextstringvalueconverter var values = new List(); var pos = sourceString.IndexOf("", StringComparison.Ordinal); while (pos >= 0) From febaddaaef29295eba1290c801146d12bf88b798 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 2 May 2016 23:05:46 +0200 Subject: [PATCH 024/535] U4-8394 When persisting the xml cache file it double loads the full xml structure into memory before writing it to a file --- .../XmlCacheFilePersister.cs | 26 ++------- .../umbraco.presentation/content.cs | 54 +++---------------- 2 files changed, 11 insertions(+), 69 deletions(-) diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlCacheFilePersister.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlCacheFilePersister.cs index 3fa11a0dc2..bdf02ba5ca 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlCacheFilePersister.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/XmlCacheFilePersister.cs @@ -148,34 +148,14 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache } } - public override async Task RunAsync(CancellationToken token) + public override Task RunAsync(CancellationToken token) { - lock (_locko) - { - _logger.Logger.Debug("Run now (async)."); - // just make sure - in case the runner is running the task on shutdown - _released = true; - } - - // http://stackoverflow.com/questions/13489065/best-practice-to-call-configureawait-for-all-server-side-code - // http://blog.stephencleary.com/2012/07/dont-block-on-async-code.html - // do we really need that ConfigureAwait here? - - // - In theory, no, because we are already executing on a background thread because we know it is there and - // there won't be any SynchronizationContext to resume to, however this is 'library' code and - // who are we to say that this will never be executed in a sync context... this is best practice to be sure - // it won't cause problems. - // .... so yes we want it. - - using (await _runLock.LockAsync()) - { - await _content.SaveXmlToFileAsync().ConfigureAwait(false); - } + throw new NotImplementedException(); } public override bool IsAsync { - get { return true; } + get { return false; } } public override void Run() diff --git a/src/Umbraco.Web/umbraco.presentation/content.cs b/src/Umbraco.Web/umbraco.presentation/content.cs index 054ee7cbe6..f51686d21d 100644 --- a/src/Umbraco.Web/umbraco.presentation/content.cs +++ b/src/Umbraco.Web/umbraco.presentation/content.cs @@ -1040,8 +1040,7 @@ order by umbracoNode.level, umbracoNode.sortOrder"; // save using (var fs = new FileStream(_xmlFileName, FileMode.Create, FileAccess.Write, FileShare.Read, bufferSize: 4096, useAsync: true)) { - var bytes = Encoding.UTF8.GetBytes(SaveXmlToString(xml)); - fs.Write(bytes, 0, bytes.Length); + SaveXmlToStream(xml, fs); } LogHelper.Info("Saved Xml to file."); @@ -1055,47 +1054,7 @@ order by umbracoNode.level, umbracoNode.sortOrder"; } } - // invoked by XmlCacheFilePersister ONLY and that one manages the MainDom, ie it - // will NOT try to save once the current app domain is not the main domain anymore - // (no need to test _released) - internal async Task SaveXmlToFileAsync() - { - LogHelper.Info("Save Xml to file..."); - - try - { - var xml = _xmlContent; // capture (atomic + volatile), immutable anyway - if (xml == null) return; - - // delete existing file, if any - DeleteXmlFile(); - - // ensure cache directory exists - var directoryName = Path.GetDirectoryName(_xmlFileName); - if (directoryName == null) - throw new Exception(string.Format("Invalid XmlFileName \"{0}\".", _xmlFileName)); - if (File.Exists(_xmlFileName) == false && Directory.Exists(directoryName) == false) - Directory.CreateDirectory(directoryName); - - // save - using (var fs = new FileStream(_xmlFileName, FileMode.Create, FileAccess.Write, FileShare.Read, bufferSize: 4096, useAsync: true)) - { - var bytes = Encoding.UTF8.GetBytes(SaveXmlToString(xml)); - await fs.WriteAsync(bytes, 0, bytes.Length); - } - - LogHelper.Info("Saved Xml to file."); - } - catch (Exception e) - { - // if something goes wrong remove the file - DeleteXmlFile(); - - LogHelper.Error("Failed to save Xml to file.", e); - } - } - - private string SaveXmlToString(XmlDocument xml) + private void SaveXmlToStream(XmlDocument xml, Stream writeStream) { // using that one method because we want to have proper indent // and in addition, writing async is never fully async because @@ -1109,8 +1068,12 @@ order by umbracoNode.level, umbracoNode.sortOrder"; // so ImportContent must also make sure of ignoring whitespaces! - var sb = new StringBuilder(); - using (var xmlWriter = XmlWriter.Create(sb, new XmlWriterSettings + if (writeStream.CanSeek) + { + writeStream.Position = 0; + } + + using (var xmlWriter = XmlWriter.Create(writeStream, new XmlWriterSettings { Indent = true, Encoding = Encoding.UTF8, @@ -1120,7 +1083,6 @@ order by umbracoNode.level, umbracoNode.sortOrder"; //xmlWriter.WriteProcessingInstruction("xml", "version=\"1.0\" encoding=\"utf-8\""); xml.WriteTo(xmlWriter); // already contains the xml declaration } - return sb.ToString(); } private XmlDocument LoadXmlFromFile() From 20b67e47be845adc85b191e583cae29b48c6aee8 Mon Sep 17 00:00:00 2001 From: Claus Date: Tue, 3 May 2016 12:54:22 +0200 Subject: [PATCH 025/535] Fixed property name to match property of the dynamic. --- .../Upgrades/TargetVersionSeven/UpdateRelatedLinksData.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSeven/UpdateRelatedLinksData.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSeven/UpdateRelatedLinksData.cs index 63df98795b..749996ea36 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSeven/UpdateRelatedLinksData.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSeven/UpdateRelatedLinksData.cs @@ -145,7 +145,7 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSeven var prop = x.Element(propertyType.Alias); if (prop != null) { - prop.ReplaceAll(new XCData(data.Text)); + prop.ReplaceAll(new XCData(data.dataNtext)); database.Update(xmlItem); } } From 67996cdb64427b4b5230ebf41aed8b442a5de522 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 4 May 2016 08:45:50 +0200 Subject: [PATCH 026/535] U4-8406 - restart app pool by unloading domain and support read-only web.config --- .../ApplicationContextExtensions.cs | 34 ++++++++----------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/src/Umbraco.Web/ApplicationContextExtensions.cs b/src/Umbraco.Web/ApplicationContextExtensions.cs index fcbcab1628..1756da5f3c 100644 --- a/src/Umbraco.Web/ApplicationContextExtensions.cs +++ b/src/Umbraco.Web/ApplicationContextExtensions.cs @@ -1,30 +1,24 @@ -using System; -using System.IO; -using System.Web; +using System.Web; using Umbraco.Core; namespace Umbraco.Web { public static class ApplicationContextExtensions { - /// - /// This will restart the application pool - /// - /// - /// - public static void RestartApplicationPool(this ApplicationContext appContext, HttpContextBase http) - { + /// + /// Restarts the application pool by unloading the application domain. + /// + /// + /// + public static void RestartApplicationPool(this ApplicationContext appContext, HttpContextBase http) + { + // we're going to put an application wide flag to show that the application is about to restart. + // we're doing this because if there is a script checking if the app pool is fully restarted, then + // it can check if this flag exists... if it does it means the app pool isn't restarted yet. + http.Application.Add("AppPoolRestarting", true); - //we're going to put an application wide flag to show that the application is about to restart. - //we're doing this because if there is a script checking if the app pool is fully restarted, then - //it can check if this flag exists... if it does it means the app pool isn't restarted yet. - http.Application.Add("AppPoolRestarting", true); - - //NOTE: this real way only works in full trust :( - //HttpRuntime.UnloadAppDomain(); - //so we'll do the dodgy hack instead - var configPath = http.Request.PhysicalApplicationPath + "\\web.config"; - File.SetLastWriteTimeUtc(configPath, DateTime.UtcNow); + // unload app domain + HttpRuntime.UnloadAppDomain(); } } } From 5f8747b4d3770ea2585a86f080a582f1826c3160 Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 4 May 2016 12:45:20 +0200 Subject: [PATCH 027/535] U4-1780 - detect colliding urls (#1243) * U4-1780 - detect colliding urls * U4-1780 - fix error message * U4-1780 - fix XmlHelper issue with sortOrder * U4-1780 - bugfix --- src/Umbraco.Core/XmlHelper.cs | 10 +++- src/Umbraco.Web.UI/umbraco/config/lang/en.xml | 1 + .../umbraco/config/lang/en_us.xml | 3 +- src/Umbraco.Web/Models/ContentExtensions.cs | 2 + .../PublishedContentCache.cs | 57 +++++++++++++++---- src/Umbraco.Web/Routing/DefaultUrlProvider.cs | 12 ++++ .../Routing/UrlProviderExtensions.cs | 24 ++++++++ 7 files changed, 93 insertions(+), 16 deletions(-) diff --git a/src/Umbraco.Core/XmlHelper.cs b/src/Umbraco.Core/XmlHelper.cs index 1978c329ab..d45f0cac3b 100644 --- a/src/Umbraco.Core/XmlHelper.cs +++ b/src/Umbraco.Core/XmlHelper.cs @@ -210,6 +210,9 @@ namespace Umbraco.Core var childNodesAndOrder = parentNode.SelectNodes(childNodesXPath).Cast() .Select(x => Tuple.Create(x, orderBy(x))).ToArray(); + // only one node = node is in the right place already, obviously + if (childNodesAndOrder.Length == 1) return false; + // find the first node with a sortOrder > node.sortOrder var i = 0; while (i < childNodesAndOrder.Length && childNodesAndOrder[i].Item2 <= nodeSortOrder) @@ -220,17 +223,18 @@ namespace Umbraco.Core { // and node is just before, we're done already // else we need to move it right before the node that was found - if (i > 0 && childNodesAndOrder[i - 1].Item1 != node) + if (i == 0 || childNodesAndOrder[i - 1].Item1 != node) { parentNode.InsertBefore(node, childNodesAndOrder[i].Item1); return true; } } - else + else // i == childNodesAndOrder.Length && childNodesAndOrder.Length > 1 { // and node is the last one, we're done already // else we need to append it as the last one - if (i > 0 && childNodesAndOrder[i - 1].Item1 != node) + // (and i > 1, see above) + if (childNodesAndOrder[i - 1].Item1 != node) { parentNode.AppendChild(node); return true; diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index e62cbd7ed4..94963cddb1 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -147,6 +147,7 @@ Properties This document is published but is not visible because the parent '%0%' is unpublished Oops: this document is published but is not in the cache (internal error) + Oops: this document is published but its url would collide with content %0% Publish Publication Status Publish at 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 c313d7ad6a..9743d3166e 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml @@ -148,6 +148,7 @@ Properties This document is published but is not visible because the parent '%0%' is unpublished Oops: this document is published but is not in the cache (internal error) + Oops: this document is published but its url would collide with content %0% Publish Publication Status Publish at @@ -676,7 +677,7 @@ To manage your website, simply open the Umbraco back office and start adding con Umbraco: Reset Password Your username to login to the Umbraco back-office is: %0%

Click here to reset your password or copy/paste this URL into your browser:

%1%

]]> -
+
Dashboard diff --git a/src/Umbraco.Web/Models/ContentExtensions.cs b/src/Umbraco.Web/Models/ContentExtensions.cs index 0d280c4c49..cfee14a2a8 100644 --- a/src/Umbraco.Web/Models/ContentExtensions.cs +++ b/src/Umbraco.Web/Models/ContentExtensions.cs @@ -48,6 +48,8 @@ namespace Umbraco.Web.Models ? null // for tests only : umbracoContext.ContentCache.GetRouteById(contentId); // cached + if (route != null && route.StartsWith("err/")) route = null; + var domainHelper = new DomainHelper(domainService); IDomain domain; diff --git a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs index d16133f170..8e9b529b7f 100644 --- a/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs +++ b/src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs @@ -55,19 +55,28 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache // cache if we have a content and not previewing if (content != null && preview == false) - { - var domainRootNodeId = route.StartsWith("/") ? -1 : int.Parse(route.Substring(0, route.IndexOf('/'))); - var iscanon = - UnitTesting == false - && DomainHelper.ExistsDomainInPath(umbracoContext.Application.Services.DomainService.GetAll(false), content.Path, domainRootNodeId) == false; - // and only if this is the canonical url (the one GetUrl would return) - if (iscanon) - _routesCache.Store(content.Id, route); - } + AddToCacheIfDeepestRoute(umbracoContext, content, route); return content; } + private void AddToCacheIfDeepestRoute(UmbracoContext umbracoContext, IPublishedContent content, string route) + { + var domainRootNodeId = route.StartsWith("/") ? -1 : int.Parse(route.Substring(0, route.IndexOf('/'))); + + // so we have a route that maps to a content... say "1234/path/to/content" - however, there could be a + // domain set on "to" and route "4567/content" would also map to the same content - and due to how + // urls computing work (by walking the tree up to the first domain we find) it is that second route + // that would be returned - the "deepest" route - and that is the route we want to cache, *not* the + // longer one - so make sure we don't cache the wrong route + + var deepest = UnitTesting == false + && DomainHelper.ExistsDomainInPath(umbracoContext.Application.Services.DomainService.GetAll(false), content.Path, domainRootNodeId) == false; + + if (deepest) + _routesCache.Store(content.Id, route); + } + public virtual string GetRouteById(UmbracoContext umbracoContext, bool preview, int contentId) { // try to get from cache if not previewing @@ -80,11 +89,35 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache // else actually determine the route route = DetermineRouteById(umbracoContext, preview, contentId); - // cache if we have a route and not previewing - if (route != null && preview == false) + // node not found + if (route == null) + return null; + + // find the content back, detect routes collisions: we should find ourselves back, + // else it means that another content with "higher priority" is sharing the same route. + // perf impact: + // - non-colliding, adds one complete "by route" lookup, only on the first time a url is computed (then it's cached anyways) + // - colliding, adds one "by route" lookup, the first time the url is computed, then one dictionary looked each time it is computed again + // assuming no collisions, the impact is one complete "by route" lookup the first time each url is computed + var loopId = preview ? 0 : _routesCache.GetNodeId(route); // might be cached already in case of collision + if (loopId == 0) + { + var content = DetermineIdByRoute(umbracoContext, preview, route, GlobalSettings.HideTopLevelNodeFromPath); + + // add the other route to cache so next time we have it already + if (content != null && preview == false) + AddToCacheIfDeepestRoute(umbracoContext, content, route); + + loopId = content == null ? 0 : content.Id; // though... 0 here would be quite weird? + } + + // cache if we have a route and not previewing and it's not a colliding route + // (the result of DetermineRouteById is always the deepest route) + if (/*route != null &&*/ preview == false && loopId == contentId) _routesCache.Store(contentId, route); - return route; + // return route if no collision, else report collision + return loopId == contentId ? route : ("err/" + loopId); } IPublishedContent DetermineIdByRoute(UmbracoContext umbracoContext, bool preview, string route, bool hideTopLevelNode) diff --git a/src/Umbraco.Web/Routing/DefaultUrlProvider.cs b/src/Umbraco.Web/Routing/DefaultUrlProvider.cs index f15c485560..915636889d 100644 --- a/src/Umbraco.Web/Routing/DefaultUrlProvider.cs +++ b/src/Umbraco.Web/Routing/DefaultUrlProvider.cs @@ -52,6 +52,7 @@ namespace Umbraco.Web.Routing // will not use cache if previewing var route = umbracoContext.ContentCache.GetRouteById(id); + if (string.IsNullOrWhiteSpace(route)) { LogHelper.Debug( @@ -60,6 +61,14 @@ namespace Umbraco.Web.Routing return null; } + if (route.StartsWith("err/")) + { + LogHelper.Debug( + "Page with nodeId={0} has a colliding url with page with nodeId={1}.", + () => id, () => route.Substring(4)); + return "#err-" + route.Substring(4); + } + var domainHelper = new DomainHelper(umbracoContext.Application.Services.DomainService); // extract domainUri and path @@ -102,6 +111,9 @@ namespace Umbraco.Web.Routing return null; } + if (route.StartsWith("err/")) + return null; + var domainHelper = new DomainHelper(umbracoContext.Application.Services.DomainService); // extract domainUri and path diff --git a/src/Umbraco.Web/Routing/UrlProviderExtensions.cs b/src/Umbraco.Web/Routing/UrlProviderExtensions.cs index 91860e03e6..0a20f51da7 100644 --- a/src/Umbraco.Web/Routing/UrlProviderExtensions.cs +++ b/src/Umbraco.Web/Routing/UrlProviderExtensions.cs @@ -48,6 +48,30 @@ namespace Umbraco.Web.Routing else urls.Add(ui.Text("content", "parentNotPublished", parent.Name, umbracoContext.Security.CurrentUser)); } + else if (url.StartsWith("#err-")) + { + // route error, report + var id = int.Parse(url.Substring(5)); + var o = umbracoContext.ContentCache.GetById(id); + string s; + if (o == null) + { + s = "(unknown)"; + } + else + { + var l = new List(); + while (o != null) + { + l.Add(o.Name); + o = o.Parent; + } + l.Reverse(); + s = "/" + string.Join("/", l) + " (id=" + id + ")"; + + } + urls.Add(ui.Text("content", "routeError", s, umbracoContext.Security.CurrentUser)); + } else { urls.Add(url); From 0d11b15b3f716bdb90b75585a3cca2ba037dad55 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 4 May 2016 16:36:43 +0200 Subject: [PATCH 028/535] This fixes the LoadContentFromDatabase method - before this was storing every single xml node in memory in dictionaries (x2) and then performing the re-organization of all nodes afterwords to construct a document, now we just read each row and organize the document accordingly, --- .../umbraco.presentation/content.cs | 274 ++++-------------- 1 file changed, 59 insertions(+), 215 deletions(-) diff --git a/src/Umbraco.Web/umbraco.presentation/content.cs b/src/Umbraco.Web/umbraco.presentation/content.cs index f51686d21d..bdd8c91f18 100644 --- a/src/Umbraco.Web/umbraco.presentation/content.cs +++ b/src/Umbraco.Web/umbraco.presentation/content.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Globalization; using System.IO; using System.Text; @@ -7,6 +8,8 @@ using System.Threading; using System.Threading.Tasks; using System.Web; using System.Xml; +using System.Xml.Linq; +using System.Xml.XPath; using umbraco.BusinessLogic; using umbraco.cms.businesslogic; using umbraco.cms.businesslogic.web; @@ -243,10 +246,6 @@ namespace umbraco /// The parent node identifier. public void SortNodes(int parentId) { - var childNodesXPath = UmbracoConfig.For.UmbracoSettings().Content.UseLegacyXmlSchema - ? "./node" - : "./* [@id]"; - using (var safeXml = GetSafeXmlWriter(false)) { var parentNode = parentId == -1 @@ -257,7 +256,7 @@ namespace umbraco var sorted = XmlHelper.SortNodesIfNeeded( parentNode, - childNodesXPath, + ChildNodesXPath, x => x.AttributeValue("sortOrder")); if (sorted == false) return; @@ -489,119 +488,71 @@ namespace umbraco { // Try to log to the DB LogHelper.Info("Loading content from database..."); - - var hierarchy = new Dictionary>(); - var nodeIndex = new Dictionary(); - + try { LogHelper.Debug("Republishing starting"); lock (DbReadSyncLock) { + //TODO: This is what we should do , but converting to use XDocument would be breaking unless we convert + // to XmlDocument at the end of this, but again, this would be bad for memory... though still not nearly as + // bad as what is happening before! + // We'll keep using XmlDocument for now though, but XDocument xml generation is much faster: + // https://blogs.msdn.microsoft.com/codejunkie/2008/10/08/xmldocument-vs-xelement-performance/ + // I think we already have code in here to convert XDocument to XmlDocument but in case we don't here + // it is: https://blogs.msdn.microsoft.com/marcelolr/2009/03/13/fast-way-to-convert-xmldocument-into-xdocument/ - // Lets cache the DTD to save on the DB hit on the subsequent use - string dtd = DocumentType.GenerateDtd(); + //// Prepare an XmlDocument with an appropriate inline DTD to match + //// the expected content + //var parent = new XElement("root", new XAttribute("id", "-1")); + //var xmlDoc = new XDocument( + // new XDocumentType("root", null, null, DocumentType.GenerateDtd()), + // parent); - // Prepare an XmlDocument with an appropriate inline DTD to match - // the expected content var xmlDoc = new XmlDocument(); - InitializeXml(xmlDoc, dtd); + var doctype = xmlDoc.CreateDocumentType("root", null, null, + ApplicationContext.Current.Services.ContentTypeService.GetContentTypesDtd()); + xmlDoc.AppendChild(doctype); + var parent = xmlDoc.CreateElement("root"); + var pIdAtt = xmlDoc.CreateAttribute("id"); + pIdAtt.Value = "-1"; + parent.Attributes.Append(pIdAtt); + xmlDoc.AppendChild(parent); // Esben Carlsen: At some point we really need to put all data access into to a tier of its own. // CLN - added checks that document xml is for a document that is actually published. - string sql = - @"select umbracoNode.id, umbracoNode.parentId, umbracoNode.sortOrder, cmsContentXml.xml from umbracoNode + const string sql = @"select umbracoNode.id, umbracoNode.parentID, umbracoNode.sortOrder, cmsContentXml.xml, umbracoNode.level from umbracoNode inner join cmsContentXml on cmsContentXml.nodeId = umbracoNode.id and umbracoNode.nodeObjectType = @type where umbracoNode.id in (select cmsDocument.nodeId from cmsDocument where cmsDocument.published = 1) -order by umbracoNode.level, umbracoNode.sortOrder"; +order by umbracoNode.level, umbracoNode.parentID, umbracoNode.sortOrder"; - - - using ( - IRecordsReader dr = SqlHelper.ExecuteReader(sql, - SqlHelper.CreateParameter("@type", - new Guid( - Constants.ObjectTypes.Document))) - ) + XmlElement last = null; + var db = ApplicationContext.Current.DatabaseContext.Database; + //NOTE: Query creates a reader - does not load all into memory + foreach (var row in db.Query(sql, new { type = new Guid(Constants.ObjectTypes.Document)})) { - while (dr.Read()) + string parentId = ((int)row.parentID).ToInvariantString(); + string xml = row.xml; + + //if the parentid is changing + if (last != null && last.GetAttribute("parentID") != parentId) { - int currentId = dr.GetInt("id"); - int parentId = dr.GetInt("parentId"); - string xml = dr.GetString("xml"); - - // fix sortOrder - see notes in UpdateSortOrder - var tmp = new XmlDocument(); - tmp.LoadXml(xml); - var attr = tmp.DocumentElement.GetAttributeNode("sortOrder"); - attr.Value = dr.GetInt("sortOrder").ToString(); - xml = tmp.InnerXml; - - // Call the eventhandler to allow modification of the string - var e1 = new ContentCacheLoadNodeEventArgs(); - FireAfterContentCacheDatabaseLoadXmlString(ref xml, e1); - // check if a listener has canceled the event - if (!e1.Cancel) - { - // and parse it into a DOM node - xmlDoc.LoadXml(xml); - XmlNode node = xmlDoc.FirstChild; - // same event handler loader form the xml node - var e2 = new ContentCacheLoadNodeEventArgs(); - FireAfterContentCacheLoadNodeFromDatabase(node, e2); - // and checking if it was canceled again - if (!e1.Cancel) - { - nodeIndex.Add(currentId, node); - - // verify if either of the handlers canceled the children to load - if (!e1.CancelChildren && !e2.CancelChildren) - { - // Build the content hierarchy - List children; - if (!hierarchy.TryGetValue(parentId, out children)) - { - // No children for this parent, so add one - children = new List(); - hierarchy.Add(parentId, children); - } - children.Add(currentId); - } - } - } + parent = xmlDoc.GetElementById(parentId); + if (parent == null) throw new InvalidOperationException("No parent node found in xml doc with id " + parentId); } + + var xmlDocFragment = xmlDoc.CreateDocumentFragment(); + xmlDocFragment.InnerXml = xml; + + last = (XmlElement)parent.AppendChild(xmlDocFragment); } - LogHelper.Debug("Xml Pages loaded"); + LogHelper.Debug("Done republishing Xml Index"); - try - { - // If we got to here we must have successfully retrieved the content from the DB so - // we can safely initialise and compose the final content DOM. - // Note: We are reusing the XmlDocument used to create the xml nodes above so - // we don't have to import them into a new XmlDocument - - // Initialise the document ready for the final composition of content - InitializeXml(xmlDoc, dtd); - - // Start building the content tree recursively from the root (-1) node - GenerateXmlDocument(hierarchy, nodeIndex, -1, xmlDoc.DocumentElement); - - LogHelper.Debug("Done republishing Xml Index"); - - return xmlDoc; - } - catch (Exception ee) - { - LogHelper.Error("Error while generating XmlDocument from database", ee); - } + return xmlDoc; } - } - catch (OutOfMemoryException ee) - { - LogHelper.Error(string.Format("Error Republishing: Out Of Memory. Parents: {0}, Nodes: {1}", hierarchy.Count, nodeIndex.Count), ee); - } + } catch (Exception ee) { LogHelper.Error("Error Republishing", ee); @@ -617,64 +568,11 @@ order by umbracoNode.level, umbracoNode.sortOrder"; return null; } - private static void GenerateXmlDocument(IDictionary> hierarchy, - IDictionary nodeIndex, int parentId, XmlNode parentNode) - { - List children; - - if (hierarchy.TryGetValue(parentId, out children)) - { - XmlNode childContainer = UmbracoConfig.For.UmbracoSettings().Content.UseLegacyXmlSchema || - String.IsNullOrEmpty(UmbracoSettings.TEMP_FRIENDLY_XML_CHILD_CONTAINER_NODENAME) - ? parentNode - : parentNode.SelectSingleNode( - UmbracoSettings.TEMP_FRIENDLY_XML_CHILD_CONTAINER_NODENAME); - - if (!UmbracoConfig.For.UmbracoSettings().Content.UseLegacyXmlSchema && - !String.IsNullOrEmpty(UmbracoSettings.TEMP_FRIENDLY_XML_CHILD_CONTAINER_NODENAME)) - { - if (childContainer == null) - { - childContainer = xmlHelper.addTextNode(parentNode.OwnerDocument, - UmbracoSettings. - TEMP_FRIENDLY_XML_CHILD_CONTAINER_NODENAME, ""); - parentNode.AppendChild(childContainer); - } - } - - foreach (int childId in children) - { - XmlNode childNode = nodeIndex[childId]; - - if (UmbracoConfig.For.UmbracoSettings().Content.UseLegacyXmlSchema || - String.IsNullOrEmpty(UmbracoSettings.TEMP_FRIENDLY_XML_CHILD_CONTAINER_NODENAME)) - { - parentNode.AppendChild(childNode); - } - else - { - childContainer.AppendChild(childNode); - } - - // Recursively build the content tree under the current child - GenerateXmlDocument(hierarchy, nodeIndex, childId, childNode); - } - } - } - [Obsolete("This method should not be used and does nothing, xml file persistence is done in a queue using a BackgroundTaskRunner")] public void PersistXmlToFile() { } - - /// - /// Adds a task to the xml cache file persister - /// - //private void QueueXmlForPersistence() - //{ - // _persisterTask = _persisterTask.Touch(); - //} - + internal DateTime GetCacheFileUpdateTime() { //TODO: Should there be a try/catch here in case the file is being written to while this is trying to be executed? @@ -723,31 +621,7 @@ order by umbracoNode.level, umbracoNode.sortOrder"; private static bool UseLegacySchema { get { return UmbracoConfig.For.UmbracoSettings().Content.UseLegacyXmlSchema; } - } - - // whether to keep version of everything (incl. medias & members) in cmsPreviewXml - // for audit purposes - false by default, not in umbracoSettings.config - // whether to... no idea what that one does - // it is false by default and not in UmbracoSettings.config anymore - ignoring - /* - private static bool GlobalPreviewStorageEnabled - { - get { return UmbracoConfig.For.UmbracoSettings().Content.GlobalPreviewStorageEnabled; } - } - */ - - // ensures config is valid - private void EnsureConfigurationIsValid() - { - if (SyncToXmlFile && SyncFromXmlFile) - throw new Exception("Cannot run with both ContinouslyUpdateXmlDiskCache and XmlContentCheckForDiskChanges being true."); - - if (XmlIsImmutable == false) - //LogHelper.Warn("Running with CloneXmlContent being false is a bad idea."); - LogHelper.Warn("CloneXmlContent is false - ignored, we always clone."); - - // note: if SyncFromXmlFile then we should also disable / warn that local edits are going to cause issues... - } + } #endregion @@ -842,13 +716,6 @@ order by umbracoNode.level, umbracoNode.sortOrder"; return xml2; } - private static void InitializeXml(XmlDocument xml, string dtd) - { - // prime the xml document with an inline dtd and a root element - xml.LoadXml(String.Format("{0}{1}{0}", - Environment.NewLine, dtd)); - } - // try to load from file, otherwise database // assumes xml lock (file is always locked) private void LoadXmlLocked(SafeXmlReaderWriter safeXml, out bool registerXmlChange) @@ -966,7 +833,7 @@ order by umbracoNode.level, umbracoNode.sortOrder"; _releaser = null; } } - + private static string ChildNodesXPath { get @@ -1264,6 +1131,11 @@ order by umbracoNode.level, umbracoNode.sortOrder"; publishedNode.Attributes.RemoveAll(); // remove all data nodes from the published node + //TODO: This could be faster, might as well just iterate all children and filter + // instead of selecting matching children (i.e. iterating all) and then iterating the + // filtered items to remove, this also allocates more memory to store the list of children. + // Below we also then do another filtering of child nodes, if we just iterate all children we + // can perform both functions more efficiently var dataNodes = publishedNode.SelectNodes(DataNodesXPath); if (dataNodes == null) throw new Exception("oops"); foreach (XmlNode n in dataNodes) @@ -1417,24 +1289,10 @@ order by umbracoNode.level, umbracoNode.sortOrder"; } } - /// - /// Occurs when [after loading the xml string from the database]. - /// + [Obsolete("This is no used, do not use this for any reason")] + [EditorBrowsable(EditorBrowsableState.Never)] public static event ContentCacheDatabaseLoadXmlStringEventHandler AfterContentCacheDatabaseLoadXmlString; - /// - /// Fires the before when creating the document cache from database - /// - /// The sender. - /// The instance containing the event data. - internal static void FireAfterContentCacheDatabaseLoadXmlString(ref string xml, ContentCacheLoadNodeEventArgs e) - { - if (AfterContentCacheDatabaseLoadXmlString != null) - { - AfterContentCacheDatabaseLoadXmlString(ref xml, e); - } - } - /// /// Occurs when [before when creating the document cache from database]. /// @@ -1453,24 +1311,10 @@ order by umbracoNode.level, umbracoNode.sortOrder"; } } - /// - /// Occurs when [after loading document cache xml node from database]. - /// + [Obsolete("This is no used, do not use this for any reason")] + [EditorBrowsable(EditorBrowsableState.Never)] public static event ContentCacheLoadNodeEventHandler AfterContentCacheLoadNodeFromDatabase; - /// - /// Fires the after loading document cache xml node from database - /// - /// The sender. - /// The instance containing the event data. - internal static void FireAfterContentCacheLoadNodeFromDatabase(XmlNode node, ContentCacheLoadNodeEventArgs e) - { - if (AfterContentCacheLoadNodeFromDatabase != null) - { - AfterContentCacheLoadNodeFromDatabase(node, e); - } - } - /// /// Occurs when [before a publish action updates the content cache]. /// From 7858521c8b116418cbdcfdaf53a0b21aeb7adc17 Mon Sep 17 00:00:00 2001 From: AndyButland Date: Sun, 8 May 2016 22:05:23 +0200 Subject: [PATCH 029/535] Converted usage of property editor value type strings to constants --- .../PropertyEditorAttribute.cs | 4 +- .../PropertyEditorValueTypes.cs | 25 ++++++++++++ .../PropertyEditors/PropertyValueEditor.cs | 4 +- .../RequiredManifestValueValidator.cs | 2 +- .../ValueConverters/JsonValueConverter.cs | 2 +- src/Umbraco.Core/Umbraco.Core.csproj | 1 + .../PropertyEditorValueEditorTests.cs | 38 +++++++++---------- .../ContentPickerPropertyEditor.cs | 2 +- .../PropertyEditors/DatePropertyEditor.cs | 2 +- .../PropertyEditors/DateTimePropertyEditor.cs | 2 +- .../PropertyEditors/DecimalPropertyEditor.cs | 2 +- .../PropertyEditors/DropDownPropertyEditor.cs | 2 +- .../DropDownWithKeysPropertyEditor.cs | 2 +- .../PropertyEditors/GridPropertyEditor.cs | 2 +- .../ImageCropperPropertyEditor.cs | 2 +- .../PropertyEditors/IntegerPropertyEditor.cs | 2 +- .../MacroContainerPropertyEditor.cs | 2 +- .../PropertyEditors/MarkdownPropertyEditor.cs | 2 +- .../MediaPickerPropertyEditor.cs | 2 +- .../MemberPickerPropertyEditor.cs | 2 +- .../MultipleTextStringPropertyEditor.cs | 2 +- .../RadioButtonsPropertyEditor.cs | 2 +- .../RelatedLinksPropertyEditor.cs | 2 +- .../PropertyEditors/RichTextPropertyEditor.cs | 2 +- .../PropertyEditors/TextAreaPropertyEditor.cs | 2 +- .../TrueFalsePropertyEditor.cs | 2 +- .../UserPickerPropertyEditor.cs | 2 +- 27 files changed, 71 insertions(+), 45 deletions(-) create mode 100644 src/Umbraco.Core/PropertyEditors/PropertyEditorValueTypes.cs diff --git a/src/Umbraco.Core/PropertyEditors/PropertyEditorAttribute.cs b/src/Umbraco.Core/PropertyEditors/PropertyEditorAttribute.cs index 2f225f1764..dadbe5173f 100644 --- a/src/Umbraco.Core/PropertyEditors/PropertyEditorAttribute.cs +++ b/src/Umbraco.Core/PropertyEditors/PropertyEditorAttribute.cs @@ -19,7 +19,7 @@ namespace Umbraco.Core.PropertyEditors EditorView = editorView; //defaults - ValueType = "string"; + ValueType = PropertyEditorValueTypes.StringType; Icon = Constants.Icons.PropertyEditor; Group = "common"; } @@ -33,7 +33,7 @@ namespace Umbraco.Core.PropertyEditors Name = name; //defaults - ValueType = "string"; + ValueType = PropertyEditorValueTypes.StringType; Icon = Constants.Icons.PropertyEditor; Group = "common"; } diff --git a/src/Umbraco.Core/PropertyEditors/PropertyEditorValueTypes.cs b/src/Umbraco.Core/PropertyEditors/PropertyEditorValueTypes.cs new file mode 100644 index 0000000000..073e4388ca --- /dev/null +++ b/src/Umbraco.Core/PropertyEditors/PropertyEditorValueTypes.cs @@ -0,0 +1,25 @@ +namespace Umbraco.Core.PropertyEditors +{ + public static class PropertyEditorValueTypes + { + public const string DateType = "DATE"; + + public const string DateTimeType = "DATETIME"; + + public const string DecimalType = "DECIMAL"; + + public const string IntegerType = "INT"; + + public const string IntegerTypeAlternative = "INTEGER"; + + public const string JsonType = "JSON"; + + public const string TextType = "TEXT"; + + public const string TimeType = "TIME"; + + public const string StringType = "STRING"; + + public const string XmlType = "XML"; + } +} diff --git a/src/Umbraco.Core/PropertyEditors/PropertyValueEditor.cs b/src/Umbraco.Core/PropertyEditors/PropertyValueEditor.cs index af3a560837..eb08b07d43 100644 --- a/src/Umbraco.Core/PropertyEditors/PropertyValueEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/PropertyValueEditor.cs @@ -25,7 +25,7 @@ namespace Umbraco.Core.PropertyEditors /// public PropertyValueEditor() { - ValueType = "string"; + ValueType = PropertyEditorValueTypes.StringType; //set a default for validators Validators = new List(); } @@ -238,7 +238,7 @@ namespace Umbraco.Core.PropertyEditors public virtual object ConvertEditorToDb(ContentPropertyData editorValue, object currentValue) { //if it's json but it's empty json, then return null - if (ValueType.InvariantEquals("JSON") && editorValue.Value != null && editorValue.Value.ToString().DetectIsEmptyJson()) + if (ValueType.InvariantEquals(PropertyEditorValueTypes.JsonType) && editorValue.Value != null && editorValue.Value.ToString().DetectIsEmptyJson()) { return null; } diff --git a/src/Umbraco.Core/PropertyEditors/RequiredManifestValueValidator.cs b/src/Umbraco.Core/PropertyEditors/RequiredManifestValueValidator.cs index 33c2c02cb6..842184d9ae 100644 --- a/src/Umbraco.Core/PropertyEditors/RequiredManifestValueValidator.cs +++ b/src/Umbraco.Core/PropertyEditors/RequiredManifestValueValidator.cs @@ -22,7 +22,7 @@ namespace Umbraco.Core.PropertyEditors { var asString = value.ToString(); - if (editor.ValueEditor.ValueType.InvariantEquals("JSON")) + if (editor.ValueEditor.ValueType.InvariantEquals(PropertyEditorValueTypes.JsonType)) { if (asString.DetectIsEmptyJson()) { diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/JsonValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/JsonValueConverter.cs index e5ed8b8b94..60c2d7f667 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/JsonValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/JsonValueConverter.cs @@ -26,7 +26,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters { var propertyEditor = PropertyEditorResolver.Current.GetByAlias(propertyType.PropertyEditorAlias); if (propertyEditor == null) return false; - return propertyEditor.ValueEditor.ValueType.InvariantEquals("json"); + return propertyEditor.ValueEditor.ValueType.InvariantEquals(PropertyEditorValueTypes.JsonType); } public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview) diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index ce34b6ef8f..a7505957ff 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -476,6 +476,7 @@ + diff --git a/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs b/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs index 26f1665fe2..eaa37b1f60 100644 --- a/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs +++ b/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs @@ -41,8 +41,8 @@ namespace Umbraco.Tests.PropertyEditors var valueEditor = new PropertyValueEditor { - ValueType = "STRING" - }; + ValueType = PropertyEditorValueTypes.StringType + }; var result = valueEditor.ConvertDbToEditor(prop, prop.PropertyType, new Mock().Object); Assert.AreEqual(isOk, !(result is string)); @@ -73,7 +73,7 @@ namespace Umbraco.Tests.PropertyEditors { var valueEditor = new PropertyValueEditor { - ValueType = "DECIMAL" + ValueType = PropertyEditorValueTypes.DecimalType }; var result = valueEditor.TryConvertValueToCrlType("12.34"); @@ -86,7 +86,7 @@ namespace Umbraco.Tests.PropertyEditors { var valueEditor = new PropertyValueEditor { - ValueType = "DECIMAL" + ValueType = PropertyEditorValueTypes.DecimalType }; var result = valueEditor.TryConvertValueToCrlType("12,34"); @@ -99,7 +99,7 @@ namespace Umbraco.Tests.PropertyEditors { var valueEditor = new PropertyValueEditor { - ValueType = "DECIMAL" + ValueType = PropertyEditorValueTypes.DecimalType }; var result = valueEditor.TryConvertValueToCrlType(string.Empty); @@ -112,20 +112,20 @@ namespace Umbraco.Tests.PropertyEditors { var valueEditor = new PropertyValueEditor { - ValueType = "DATE" - }; + ValueType = PropertyEditorValueTypes.DateType + }; var result = valueEditor.TryConvertValueToCrlType("2010-02-05"); Assert.IsTrue(result.Success); Assert.AreEqual(new DateTime(2010, 2, 5), result.Result); } - [TestCase("STRING", "hello", "hello")] - [TestCase("TEXT", "hello", "hello")] - [TestCase("INT", 123, "123")] - [TestCase("INTEGER", 123, "123")] - [TestCase("INTEGER", "", "")] //test empty string for int - [TestCase("DATETIME", "", "")] //test empty string for date + [TestCase(PropertyEditorValueTypes.StringType, "hello", "hello")] + [TestCase(PropertyEditorValueTypes.TextType, "hello", "hello")] + [TestCase(PropertyEditorValueTypes.IntegerType, 123, "123")] + [TestCase(PropertyEditorValueTypes.IntegerTypeAlternative, 123, "123")] + [TestCase(PropertyEditorValueTypes.IntegerType, "", "")] //test empty string for int + [TestCase(PropertyEditorValueTypes.DateTimeType, "", "")] //test empty string for date public void Value_Editor_Can_Serialize_Value(string valueType, object val, string expected) { var prop = new Property(1, Guid.NewGuid(), new PropertyType("test", DataTypeDatabaseType.Nvarchar), val); @@ -145,8 +145,8 @@ namespace Umbraco.Tests.PropertyEditors var value = 12.34M; var valueEditor = new PropertyValueEditor { - ValueType = "DECIMAL" - }; + ValueType = PropertyEditorValueTypes.DecimalType + }; var prop = new Property(1, Guid.NewGuid(), new PropertyType("test", DataTypeDatabaseType.Decimal), value); @@ -159,8 +159,8 @@ namespace Umbraco.Tests.PropertyEditors { var valueEditor = new PropertyValueEditor { - ValueType = "DECIMAL" - }; + ValueType = PropertyEditorValueTypes.DecimalType + }; var prop = new Property(1, Guid.NewGuid(), new PropertyType("test", DataTypeDatabaseType.Decimal), string.Empty); @@ -174,8 +174,8 @@ namespace Umbraco.Tests.PropertyEditors var now = DateTime.Now; var valueEditor = new PropertyValueEditor { - ValueType = "DATE" - }; + ValueType = PropertyEditorValueTypes.DateType + }; var prop = new Property(1, Guid.NewGuid(), new PropertyType("test", DataTypeDatabaseType.Date), now); diff --git a/src/Umbraco.Web/PropertyEditors/ContentPickerPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/ContentPickerPropertyEditor.cs index 8e5bd20964..22c35e9b8c 100644 --- a/src/Umbraco.Web/PropertyEditors/ContentPickerPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/ContentPickerPropertyEditor.cs @@ -4,7 +4,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.ContentPickerAlias, "Content Picker", "INT", "contentpicker", IsParameterEditor = true, Group = "Pickers")] + [PropertyEditor(Constants.PropertyEditors.ContentPickerAlias, "Content Picker", PropertyEditorValueTypes.IntegerType, "contentpicker", IsParameterEditor = true, Group = "Pickers")] public class ContentPickerPropertyEditor : PropertyEditor { diff --git a/src/Umbraco.Web/PropertyEditors/DatePropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/DatePropertyEditor.cs index 56877a8b22..9cb8d5fec8 100644 --- a/src/Umbraco.Web/PropertyEditors/DatePropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/DatePropertyEditor.cs @@ -9,7 +9,7 @@ using Umbraco.Core.Services; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.DateAlias, "Date", "DATE", "datepicker", Icon="icon-calendar")] + [PropertyEditor(Constants.PropertyEditors.DateAlias, "Date", PropertyEditorValueTypes.DateType, "datepicker", Icon="icon-calendar")] public class DatePropertyEditor : PropertyEditor { public DatePropertyEditor() diff --git a/src/Umbraco.Web/PropertyEditors/DateTimePropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/DateTimePropertyEditor.cs index 38674de14e..1c6d7ce9d4 100644 --- a/src/Umbraco.Web/PropertyEditors/DateTimePropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/DateTimePropertyEditor.cs @@ -5,7 +5,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.DateTimeAlias, "Date/Time", "datepicker", ValueType = "DATETIME", Icon="icon-time")] + [PropertyEditor(Constants.PropertyEditors.DateTimeAlias, "Date/Time", "datepicker", ValueType = PropertyEditorValueTypes.DateTimeType, Icon="icon-time")] public class DateTimePropertyEditor : PropertyEditor { public DateTimePropertyEditor() diff --git a/src/Umbraco.Web/PropertyEditors/DecimalPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/DecimalPropertyEditor.cs index f636e8cdb2..6a1a7d73a8 100644 --- a/src/Umbraco.Web/PropertyEditors/DecimalPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/DecimalPropertyEditor.cs @@ -3,7 +3,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.DecimalAlias, "Decimal", "decimal", "decimal", IsParameterEditor = true)] + [PropertyEditor(Constants.PropertyEditors.DecimalAlias, "Decimal", PropertyEditorValueTypes.DecimalType, "decimal", IsParameterEditor = true)] public class DecimalPropertyEditor : PropertyEditor { /// diff --git a/src/Umbraco.Web/PropertyEditors/DropDownPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/DropDownPropertyEditor.cs index 4b8812b622..4a6f5321b8 100644 --- a/src/Umbraco.Web/PropertyEditors/DropDownPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/DropDownPropertyEditor.cs @@ -16,7 +16,7 @@ namespace Umbraco.Web.PropertyEditors /// as INT and we have logic in here to ensure it is formatted correctly including ensuring that the string value is published /// in cache and not the int ID. /// - [PropertyEditor(Constants.PropertyEditors.DropDownListAlias, "Dropdown list", "dropdown", ValueType = "STRING", Group = "lists", Icon = "icon-indent")] + [PropertyEditor(Constants.PropertyEditors.DropDownListAlias, "Dropdown list", "dropdown", ValueType = PropertyEditorValueTypes.StringType, Group = "lists", Icon = "icon-indent")] public class DropDownPropertyEditor : DropDownWithKeysPropertyEditor { /// diff --git a/src/Umbraco.Web/PropertyEditors/DropDownWithKeysPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/DropDownWithKeysPropertyEditor.cs index cc590a0402..6c947f4bad 100644 --- a/src/Umbraco.Web/PropertyEditors/DropDownWithKeysPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/DropDownWithKeysPropertyEditor.cs @@ -11,7 +11,7 @@ namespace Umbraco.Web.PropertyEditors /// as INT and we have logic in here to ensure it is formatted correctly including ensuring that the INT ID value is published /// in cache and not the string value. /// - [PropertyEditor(Constants.PropertyEditors.DropdownlistPublishingKeysAlias, "Dropdown list, publishing keys", "dropdown", ValueType = "INT", Group = "lists", Icon = "icon-indent")] + [PropertyEditor(Constants.PropertyEditors.DropdownlistPublishingKeysAlias, "Dropdown list, publishing keys", "dropdown", ValueType = PropertyEditorValueTypes.IntegerType, Group = "lists", Icon = "icon-indent")] public class DropDownWithKeysPropertyEditor : PropertyEditor { diff --git a/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs index 5228bde1a5..e137d7d1b9 100644 --- a/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs @@ -9,7 +9,7 @@ using Umbraco.Core.Services; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Core.Constants.PropertyEditors.GridAlias, "Grid layout", "grid", HideLabel = true, IsParameterEditor = false, ValueType = "JSON", Group="rich content", Icon="icon-layout")] + [PropertyEditor(Core.Constants.PropertyEditors.GridAlias, "Grid layout", "grid", HideLabel = true, IsParameterEditor = false, ValueType = PropertyEditorValueTypes.JsonType, Group="rich content", Icon="icon-layout")] public class GridPropertyEditor : PropertyEditor { /// diff --git a/src/Umbraco.Web/PropertyEditors/ImageCropperPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/ImageCropperPropertyEditor.cs index 9858217a5b..b4fa34a670 100644 --- a/src/Umbraco.Web/PropertyEditors/ImageCropperPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/ImageCropperPropertyEditor.cs @@ -15,7 +15,7 @@ using Umbraco.Core.Services; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.ImageCropperAlias, "Image Cropper", "imagecropper", ValueType = "JSON", HideLabel = false, Group="media", Icon="icon-crop")] + [PropertyEditor(Constants.PropertyEditors.ImageCropperAlias, "Image Cropper", "imagecropper", ValueType = PropertyEditorValueTypes.JsonType, HideLabel = false, Group="media", Icon="icon-crop")] public class ImageCropperPropertyEditor : PropertyEditor { diff --git a/src/Umbraco.Web/PropertyEditors/IntegerPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/IntegerPropertyEditor.cs index 7e0ac8443f..f569905810 100644 --- a/src/Umbraco.Web/PropertyEditors/IntegerPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/IntegerPropertyEditor.cs @@ -3,7 +3,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.IntegerAlias, "Numeric", "integer", IsParameterEditor = true, ValueType = "integer")] + [PropertyEditor(Constants.PropertyEditors.IntegerAlias, "Numeric", "integer", IsParameterEditor = true, ValueType = PropertyEditorValueTypes.IntegerTypeAlternative)] public class IntegerPropertyEditor : PropertyEditor { /// diff --git a/src/Umbraco.Web/PropertyEditors/MacroContainerPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/MacroContainerPropertyEditor.cs index 7a8e26aa56..ffe42b8603 100644 --- a/src/Umbraco.Web/PropertyEditors/MacroContainerPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/MacroContainerPropertyEditor.cs @@ -9,7 +9,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.MacroContainerAlias, "Macro container", "macrocontainer", ValueType = "TEXT", Group="rich content", Icon="icon-settings-alt")] + [PropertyEditor(Constants.PropertyEditors.MacroContainerAlias, "Macro container", "macrocontainer", ValueType = PropertyEditorValueTypes.TextType, Group="rich content", Icon="icon-settings-alt")] public class MacroContainerPropertyEditor : PropertyEditor { /// diff --git a/src/Umbraco.Web/PropertyEditors/MarkdownPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/MarkdownPropertyEditor.cs index 3260d1d1f4..1da9ac57c6 100644 --- a/src/Umbraco.Web/PropertyEditors/MarkdownPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/MarkdownPropertyEditor.cs @@ -3,7 +3,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.MarkdownEditorAlias, "Markdown editor", "markdowneditor", ValueType = "TEXT", Icon="icon-code", Group="rich content")] + [PropertyEditor(Constants.PropertyEditors.MarkdownEditorAlias, "Markdown editor", "markdowneditor", ValueType = PropertyEditorValueTypes.TextType, Icon="icon-code", Group="rich content")] public class MarkdownPropertyEditor : PropertyEditor { protected override PreValueEditor CreatePreValueEditor() diff --git a/src/Umbraco.Web/PropertyEditors/MediaPickerPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/MediaPickerPropertyEditor.cs index 1ace077a32..d9a86da778 100644 --- a/src/Umbraco.Web/PropertyEditors/MediaPickerPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/MediaPickerPropertyEditor.cs @@ -9,7 +9,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.MediaPickerAlias, "Legacy Media Picker", "INT", "mediapicker", Group="media", Icon="icon-picture")] + [PropertyEditor(Constants.PropertyEditors.MediaPickerAlias, "Legacy Media Picker", PropertyEditorValueTypes.IntegerType, "mediapicker", Group="media", Icon="icon-picture")] public class MediaPickerPropertyEditor : PropertyEditor { public MediaPickerPropertyEditor() diff --git a/src/Umbraco.Web/PropertyEditors/MemberPickerPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/MemberPickerPropertyEditor.cs index 3f4674e636..b35e4f7675 100644 --- a/src/Umbraco.Web/PropertyEditors/MemberPickerPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/MemberPickerPropertyEditor.cs @@ -8,7 +8,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.MemberPickerAlias, "Member Picker", "INT", "memberpicker", Group = "People", Icon = "icon-user")] + [PropertyEditor(Constants.PropertyEditors.MemberPickerAlias, "Member Picker", PropertyEditorValueTypes.IntegerType, "memberpicker", Group = "People", Icon = "icon-user")] public class MemberPickerPropertyEditor : PropertyEditor { } diff --git a/src/Umbraco.Web/PropertyEditors/MultipleTextStringPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/MultipleTextStringPropertyEditor.cs index 1e48529ccb..81885c8c55 100644 --- a/src/Umbraco.Web/PropertyEditors/MultipleTextStringPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/MultipleTextStringPropertyEditor.cs @@ -14,7 +14,7 @@ using Umbraco.Core.Services; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.MultipleTextstringAlias, "Repeatable textstrings", "multipletextbox", ValueType = "TEXT", Icon="icon-ordered-list", Group="lists")] + [PropertyEditor(Constants.PropertyEditors.MultipleTextstringAlias, "Repeatable textstrings", "multipletextbox", ValueType = PropertyEditorValueTypes.TextType, Icon="icon-ordered-list", Group="lists")] public class MultipleTextStringPropertyEditor : PropertyEditor { protected override PropertyValueEditor CreateValueEditor() diff --git a/src/Umbraco.Web/PropertyEditors/RadioButtonsPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/RadioButtonsPropertyEditor.cs index 99fd992fff..7704a4c178 100644 --- a/src/Umbraco.Web/PropertyEditors/RadioButtonsPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/RadioButtonsPropertyEditor.cs @@ -11,7 +11,7 @@ namespace Umbraco.Web.PropertyEditors /// as INT and we have logic in here to ensure it is formatted correctly including ensuring that the INT ID value is published /// in cache and not the string value. /// - [PropertyEditor(Constants.PropertyEditors.RadioButtonListAlias, "Radio button list", "radiobuttons", ValueType = "INT", Group="lists", Icon="icon-target")] + [PropertyEditor(Constants.PropertyEditors.RadioButtonListAlias, "Radio button list", "radiobuttons", ValueType = PropertyEditorValueTypes.IntegerType, Group="lists", Icon="icon-target")] public class RadioButtonsPropertyEditor : DropDownWithKeysPropertyEditor { diff --git a/src/Umbraco.Web/PropertyEditors/RelatedLinksPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/RelatedLinksPropertyEditor.cs index 1fc4d7f471..61faa6827f 100644 --- a/src/Umbraco.Web/PropertyEditors/RelatedLinksPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/RelatedLinksPropertyEditor.cs @@ -8,7 +8,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.RelatedLinksAlias, "Related links", "relatedlinks", ValueType ="JSON", Icon="icon-thumbnail-list", Group="pickers")] + [PropertyEditor(Constants.PropertyEditors.RelatedLinksAlias, "Related links", "relatedlinks", ValueType = PropertyEditorValueTypes.JsonType, Icon="icon-thumbnail-list", Group="pickers")] public class RelatedLinksPropertyEditor : PropertyEditor { protected override PreValueEditor CreatePreValueEditor() diff --git a/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs index fb6c813bf9..e069d09783 100644 --- a/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs @@ -7,7 +7,7 @@ using Umbraco.Core.Services; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.TinyMCEAlias, "Rich Text Editor", "rte", ValueType = "TEXT", HideLabel = false, Group="Rich Content", Icon="icon-browser-window")] + [PropertyEditor(Constants.PropertyEditors.TinyMCEAlias, "Rich Text Editor", "rte", ValueType = PropertyEditorValueTypes.TextType, HideLabel = false, Group="Rich Content", Icon="icon-browser-window")] public class RichTextPropertyEditor : PropertyEditor { /// diff --git a/src/Umbraco.Web/PropertyEditors/TextAreaPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/TextAreaPropertyEditor.cs index 33dea851ab..3f7c6559b8 100644 --- a/src/Umbraco.Web/PropertyEditors/TextAreaPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/TextAreaPropertyEditor.cs @@ -3,7 +3,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.TextboxMultipleAlias, "Textarea", "textarea", IsParameterEditor = true, ValueType = "TEXT", Icon="icon-application-window-alt")] + [PropertyEditor(Constants.PropertyEditors.TextboxMultipleAlias, "Textarea", "textarea", IsParameterEditor = true, ValueType = PropertyEditorValueTypes.TextType, Icon="icon-application-window-alt")] public class TextAreaPropertyEditor : PropertyEditor { } diff --git a/src/Umbraco.Web/PropertyEditors/TrueFalsePropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/TrueFalsePropertyEditor.cs index ab9e906911..012167a99c 100644 --- a/src/Umbraco.Web/PropertyEditors/TrueFalsePropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/TrueFalsePropertyEditor.cs @@ -3,7 +3,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.TrueFalseAlias, "True/False", "INT", "boolean", IsParameterEditor = true, Group = "Common", Icon="icon-checkbox")] + [PropertyEditor(Constants.PropertyEditors.TrueFalseAlias, "True/False", PropertyEditorValueTypes.IntegerType, "boolean", IsParameterEditor = true, Group = "Common", Icon="icon-checkbox")] public class TrueFalsePropertyEditor : PropertyEditor { protected override PreValueEditor CreatePreValueEditor() diff --git a/src/Umbraco.Web/PropertyEditors/UserPickerPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/UserPickerPropertyEditor.cs index 8f66d24425..4c08b26770 100644 --- a/src/Umbraco.Web/PropertyEditors/UserPickerPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/UserPickerPropertyEditor.cs @@ -6,7 +6,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.UserPickerAlias, "User picker", "INT", "entitypicker", Group="People", Icon="icon-user")] + [PropertyEditor(Constants.PropertyEditors.UserPickerAlias, "User picker", PropertyEditorValueTypes.IntegerType, "entitypicker", Group="People", Icon="icon-user")] public class UserPickerPropertyEditor : PropertyEditor { private IDictionary _defaultPreValues; From 7b6bcd24ae8f91fb3bffe3ec75d738592423379f Mon Sep 17 00:00:00 2001 From: AndyButland Date: Sun, 8 May 2016 23:39:47 +0200 Subject: [PATCH 030/535] Added value type as a pre-value to the label property editor --- .../src/views/prevalueeditors/valuetype.html | 7 ++ .../PropertyEditors/LabelPropertyEditor.cs | 83 ++++++++++++++++--- 2 files changed, 79 insertions(+), 11 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/views/prevalueeditors/valuetype.html diff --git a/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/valuetype.html b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/valuetype.html new file mode 100644 index 0000000000..59b7c55c19 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/prevalueeditors/valuetype.html @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/src/Umbraco.Web/PropertyEditors/LabelPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/LabelPropertyEditor.cs index 325c570344..1132fcfacd 100644 --- a/src/Umbraco.Web/PropertyEditors/LabelPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/LabelPropertyEditor.cs @@ -1,17 +1,15 @@ using System.Collections.Generic; -using System.ComponentModel; using System.Linq; -using System.Web.Mvc; +using Newtonsoft.Json.Linq; using Umbraco.Core; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.NoEditAlias, "Label", "readonlyvalue", Icon="icon-readonly")] + [PropertyEditor(Constants.PropertyEditors.NoEditAlias, "Label", "readonlyvalue", Icon = "icon-readonly")] public class LabelPropertyEditor : PropertyEditor { - protected override PropertyValueEditor CreateValueEditor() { return new LabelPropertyValueEditor(base.CreateValueEditor()); @@ -43,19 +41,27 @@ namespace Umbraco.Web.PropertyEditors internal class LabelPreValueEditor : PreValueEditor { + private const string ValueTypeKey = "valueType"; + private const string LegacyPropertyEditorValuesKey = "values"; + public LabelPreValueEditor() { Fields.Add(new PreValueField() { HideLabel = true, View = "readonlykeyvalues", - Key = "values" + Key = LegacyPropertyEditorValuesKey }); + + ValueType = PropertyEditorValueTypes.StringType; } + [PreValueField(ValueTypeKey, "Value type", "valuetype")] + public string ValueType { get; set; } + /// - /// Chuck all the values into one field so devs can see what is stored there - we want this in case we've converted a legacy proeprty editor over to a label - /// we should still show the pre-values stored for the data type. + /// Other than for the pre-value fields defined on this property editor, chuck all the values into one field so devs can see what is stored there. + /// We want this in case we've converted a legacy property editor over to a label as we should still show the pre-values stored for the data type. /// /// /// @@ -63,12 +69,67 @@ namespace Umbraco.Web.PropertyEditors public override IDictionary ConvertDbToEditor(IDictionary defaultPreVals, PreValueCollection persistedPreVals) { var existing = base.ConvertDbToEditor(defaultPreVals, persistedPreVals); - //convert to a list, easier to enumerate on the editor - var asList = existing.Select(e => new KeyValuePair(e.Key, e.Value)).ToList(); - var result = new Dictionary { { "values", asList } }; + + // Check for a saved value type. If not found set to default string type. + var valueType = PropertyEditorValueTypes.StringType; + if (existing.ContainsKey(ValueTypeKey)) + { + valueType = (string)existing[ValueTypeKey]; + } + + // Convert any other values from a legacy property editor to a list, easier to enumerate on the editor. + // Make sure to exclude values defined on the label property editor itself. + var asList = existing + .Select(e => new KeyValuePair(e.Key, e.Value)) + .Where(e => e.Key != ValueTypeKey) + .ToList(); + + var result = new Dictionary { { ValueTypeKey, valueType } }; + if (asList.Any()) + { + result.Add("values", asList); + } + return result; } - } + /// + /// When saving we want to avoid saving an empty "legacy property editor values" field if there are none. + /// + /// + /// + /// + public override IDictionary ConvertEditorToDb(IDictionary editorValue, PreValueCollection currentValue) + { + if (editorValue.ContainsKey(LegacyPropertyEditorValuesKey)) + { + // If provided value contains an empty legacy property editor values, don't save it + if (editorValue[LegacyPropertyEditorValuesKey] == null) + { + editorValue.Remove(LegacyPropertyEditorValuesKey); + } + else + { + // If provided value contains legacy property editor values, unwrap the value to save so it doesn't get repeatedly nested on saves. + // This is a bit funky - but basically needing to parse out the original value from a JSON structure that is passed in + // looking like: + // Value = {[ + // { + // "Key": "values", + // "Value": { + // + // }} + // ]} + var values = editorValue[LegacyPropertyEditorValuesKey] as JArray; + if (values != null && values.Count == 1 && values.First.Values().Count() == 2) + { + editorValue[LegacyPropertyEditorValuesKey] = values.First.Values().Last(); + } + } + } + + return base.ConvertEditorToDb(editorValue, currentValue); + } + } } } \ No newline at end of file From 50e92b80f993e47634b8d10494ed2b12a29baa7d Mon Sep 17 00:00:00 2001 From: Simon Busborg Date: Mon, 9 May 2016 14:35:55 +0200 Subject: [PATCH 031/535] Changed from int to Nvarchar for the multimediapicker --- .../Persistence/Migrations/Initial/BaseDataCreation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs b/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs index 038c1c3c1c..fa3c60ffa1 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs @@ -237,8 +237,8 @@ namespace Umbraco.Core.Persistence.Migrations.Initial _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 14, DataTypeId = -42, PropertyEditorAlias = Constants.PropertyEditors.DropDownListAlias, DbType = "Integer" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 15, DataTypeId = -43, PropertyEditorAlias = Constants.PropertyEditors.CheckBoxListAlias, DbType = "Nvarchar" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 16, DataTypeId = 1034, PropertyEditorAlias = Constants.PropertyEditors.ContentPickerAlias, DbType = "Integer" }); - _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 17, DataTypeId = 1035, PropertyEditorAlias = Constants.PropertyEditors.MultipleMediaPickerAlias, DbType = "Integer" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 18, DataTypeId = 1036, PropertyEditorAlias = Constants.PropertyEditors.MemberPickerAlias, DbType = "Integer" }); + _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 17, DataTypeId = 1035, PropertyEditorAlias = Constants.PropertyEditors.MultipleMediaPickerAlias, DbType = "Nvarchar" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 21, DataTypeId = 1040, PropertyEditorAlias = Constants.PropertyEditors.RelatedLinksAlias, DbType = "Ntext" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 22, DataTypeId = 1041, PropertyEditorAlias = Constants.PropertyEditors.TagsAlias, DbType = "Ntext" }); _database.Insert("cmsDataType", "pk", false, new DataTypeDto { PrimaryKey = 24, DataTypeId = 1043, PropertyEditorAlias = Constants.PropertyEditors.ImageCropperAlias, DbType = "Ntext" }); From 4f3d82cf107f7b9897fdc3c336cbfe2f143e23c6 Mon Sep 17 00:00:00 2001 From: AndyButland Date: Tue, 10 May 2016 10:50:59 +0200 Subject: [PATCH 032/535] Change field to which data is saved for a data type if provided in prevalues and handle potential mis-matched types on display --- src/Umbraco.Core/Constants-PropertyEditors.cs | 6 +++ .../Models/DataTypeDatabaseType.cs | 4 -- src/Umbraco.Core/Models/Property.cs | 52 +++++++++++++++++-- src/Umbraco.Core/Models/PropertyType.cs | 14 +++++ .../PropertyEditors/PropertyValueEditor.cs | 20 +++---- src/Umbraco.Core/Services/DataTypeService.cs | 32 ++++++++++++ .../PropertyEditors/LabelPropertyEditor.cs | 11 ++-- 7 files changed, 115 insertions(+), 24 deletions(-) diff --git a/src/Umbraco.Core/Constants-PropertyEditors.cs b/src/Umbraco.Core/Constants-PropertyEditors.cs index 2f7d247b36..358ca0e5d7 100644 --- a/src/Umbraco.Core/Constants-PropertyEditors.cs +++ b/src/Umbraco.Core/Constants-PropertyEditors.cs @@ -419,6 +419,12 @@ namespace Umbraco.Core /// Alias for the email address property editor /// public const string EmailAddressAlias = "Umbraco.EmailAddress"; + + /// + /// Pre-value name used to indicate a field that can be used to override the database field to which data for the associated + /// property is saved + /// + public const string DataValueTypePreValueKey = "umbracoDataValueType"; } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Models/DataTypeDatabaseType.cs b/src/Umbraco.Core/Models/DataTypeDatabaseType.cs index 1db8ac65cb..2fccdc0645 100644 --- a/src/Umbraco.Core/Models/DataTypeDatabaseType.cs +++ b/src/Umbraco.Core/Models/DataTypeDatabaseType.cs @@ -6,10 +6,6 @@ namespace Umbraco.Core.Models /// /// Enum of the various DbTypes for which the Property values are stored /// - /// - /// Object is added to support complex values from PropertyEditors, - /// but will be saved under the Ntext column. - /// [Serializable] [DataContract] public enum DataTypeDatabaseType diff --git a/src/Umbraco.Core/Models/Property.cs b/src/Umbraco.Core/Models/Property.cs index d7c2eb92a8..f3fbefda4f 100644 --- a/src/Umbraco.Core/Models/Property.cs +++ b/src/Umbraco.Core/Models/Property.cs @@ -124,10 +124,54 @@ namespace Umbraco.Core.Models bool typeValidation = _propertyType.IsPropertyTypeValid(value); if (typeValidation == false) - throw new Exception( - string.Format( - "Type validation failed. The value type: '{0}' does not match the DataType in PropertyType with alias: '{1}'", - value == null ? "null" : value.GetType().Name, Alias)); + { + // Normally we'll throw an exception here. However if the property is of a type that can have it's data field (dataInt, dataVarchar etc.) + // changed, we might have a value of the now "wrong" type. As of May 2016 Label is the only built-in property editor that supports this. + // In that case we should try to parse the value and return null if that's not possible rather than throwing an exception. + if (value != null && _propertyType.CanHaveDataValueTypeChanged()) + { + var stringValue = value.ToString(); + switch (_propertyType.DataTypeDatabaseType) + { + case DataTypeDatabaseType.Nvarchar: + case DataTypeDatabaseType.Ntext: + value = stringValue; + break; + case DataTypeDatabaseType.Integer: + int integerValue; + if (int.TryParse(stringValue, out integerValue) == false) + { + // Edge case, but if changed from decimal --> integer, the above tryparse will fail. So we'll try going + // via decimal too to return the integer value rather than zero. + decimal decimalForIntegerValue; + if (decimal.TryParse(stringValue, out decimalForIntegerValue)) + { + integerValue = (int)decimalForIntegerValue; + } + } + + value = integerValue; + break; + case DataTypeDatabaseType.Decimal: + decimal decimalValue; + decimal.TryParse(stringValue, out decimalValue); + value = decimalValue; + break; + case DataTypeDatabaseType.Date: + DateTime dateValue; + DateTime.TryParse(stringValue, out dateValue); + value = dateValue; + break; + } + } + else + { + throw new Exception( + string.Format( + "Type validation failed. The value type: '{0}' does not match the DataType in PropertyType with alias: '{1}'", + value == null ? "null" : value.GetType().Name, Alias)); + } + } SetPropertyValueAndDetectChanges(o => { diff --git a/src/Umbraco.Core/Models/PropertyType.cs b/src/Umbraco.Core/Models/PropertyType.cs index 0649801a0c..00e7fc8d13 100644 --- a/src/Umbraco.Core/Models/PropertyType.cs +++ b/src/Umbraco.Core/Models/PropertyType.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics; +using System.Linq; using System.Reflection; using System.Runtime.Serialization; using System.Text.RegularExpressions; @@ -425,6 +426,19 @@ namespace Umbraco.Core.Models return false; } + /// + /// Checks the underlying property editor prevalues to see if the one that allows changing of the database field + /// to which data is saved (dataInt, dataVarchar etc.) is included. If so that means the field could be changed when the data + /// type is saved. + /// + /// + internal bool CanHaveDataValueTypeChanged() + { + var propertyEditor = PropertyEditorResolver.Current.GetByAlias(_propertyEditorAlias); + return propertyEditor.PreValueEditor.Fields + .SingleOrDefault(x => x.Key == Constants.PropertyEditors.DataValueTypePreValueKey) != null; + } + /// /// Validates the Value from a Property according to the validation settings /// diff --git a/src/Umbraco.Core/PropertyEditors/PropertyValueEditor.cs b/src/Umbraco.Core/PropertyEditors/PropertyValueEditor.cs index eb08b07d43..a7154d7d67 100644 --- a/src/Umbraco.Core/PropertyEditors/PropertyValueEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/PropertyValueEditor.cs @@ -130,20 +130,20 @@ namespace Umbraco.Core.PropertyEditors { switch (ValueType.ToUpper(CultureInfo.InvariantCulture)) { - case "INT": - case "INTEGER": + case PropertyEditorValueTypes.IntegerType: + case PropertyEditorValueTypes.IntegerTypeAlternative: return DataTypeDatabaseType.Integer; - case "DECIMAL": + case PropertyEditorValueTypes.DecimalType: return DataTypeDatabaseType.Decimal; - case "STRING": + case PropertyEditorValueTypes.StringType: return DataTypeDatabaseType.Nvarchar; - case "TEXT": - case "JSON": - case "XML": + case PropertyEditorValueTypes.TextType: + case PropertyEditorValueTypes.JsonType: + case PropertyEditorValueTypes.XmlType: return DataTypeDatabaseType.Ntext; - case "DATETIME": - case "DATE": - case "TIME": + case PropertyEditorValueTypes.DateTimeType: + case PropertyEditorValueTypes.DateType: + case PropertyEditorValueTypes.TimeType: return DataTypeDatabaseType.Date; default: throw new FormatException("The ValueType does not match a known value type"); diff --git a/src/Umbraco.Core/Services/DataTypeService.cs b/src/Umbraco.Core/Services/DataTypeService.cs index 035cfd0ab6..75234fa3ab 100644 --- a/src/Umbraco.Core/Services/DataTypeService.cs +++ b/src/Umbraco.Core/Services/DataTypeService.cs @@ -504,6 +504,8 @@ namespace Umbraco.Core.Services if (Saving.IsRaisedEventCancelled(new SaveEventArgs(dataTypeDefinition), this)) return; + OverrideDatabaseTypeIfProvidedInPreValues(dataTypeDefinition, values); + var uow = UowProvider.GetUnitOfWork(); using (var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow)) { @@ -523,6 +525,36 @@ namespace Umbraco.Core.Services Audit(AuditType.Save, string.Format("Save DataTypeDefinition performed by user"), userId, dataTypeDefinition.Id); } + /// + /// If the database data field is provided in the pre-values update the data type definition to that instead of the + /// default for the property editor + /// + /// + /// + private static void OverrideDatabaseTypeIfProvidedInPreValues(IDataTypeDefinition dataTypeDefinition, IDictionary values) + { + if (values != null && values.ContainsKey(Constants.PropertyEditors.DataValueTypePreValueKey)) + { + switch (values[Constants.PropertyEditors.DataValueTypePreValueKey].Value) + { + case PropertyEditorValueTypes.StringType: + dataTypeDefinition.DatabaseType = DataTypeDatabaseType.Nvarchar; + break; + case PropertyEditorValueTypes.IntegerType: + dataTypeDefinition.DatabaseType = DataTypeDatabaseType.Integer; + break; + case PropertyEditorValueTypes.DecimalType: + dataTypeDefinition.DatabaseType = DataTypeDatabaseType.Decimal; + break; + case PropertyEditorValueTypes.DateTimeType: + dataTypeDefinition.DatabaseType = DataTypeDatabaseType.Date; + break; + case PropertyEditorValueTypes.TextType: + dataTypeDefinition.DatabaseType = DataTypeDatabaseType.Ntext; + break; + } + } + } /// /// Deletes an diff --git a/src/Umbraco.Web/PropertyEditors/LabelPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/LabelPropertyEditor.cs index 1132fcfacd..fab9d0bba3 100644 --- a/src/Umbraco.Web/PropertyEditors/LabelPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/LabelPropertyEditor.cs @@ -41,7 +41,6 @@ namespace Umbraco.Web.PropertyEditors internal class LabelPreValueEditor : PreValueEditor { - private const string ValueTypeKey = "valueType"; private const string LegacyPropertyEditorValuesKey = "values"; public LabelPreValueEditor() @@ -56,7 +55,7 @@ namespace Umbraco.Web.PropertyEditors ValueType = PropertyEditorValueTypes.StringType; } - [PreValueField(ValueTypeKey, "Value type", "valuetype")] + [PreValueField(Constants.PropertyEditors.DataValueTypePreValueKey, "Value type", "valuetype")] public string ValueType { get; set; } /// @@ -72,19 +71,19 @@ namespace Umbraco.Web.PropertyEditors // Check for a saved value type. If not found set to default string type. var valueType = PropertyEditorValueTypes.StringType; - if (existing.ContainsKey(ValueTypeKey)) + if (existing.ContainsKey(Constants.PropertyEditors.DataValueTypePreValueKey)) { - valueType = (string)existing[ValueTypeKey]; + valueType = (string)existing[Constants.PropertyEditors.DataValueTypePreValueKey]; } // Convert any other values from a legacy property editor to a list, easier to enumerate on the editor. // Make sure to exclude values defined on the label property editor itself. var asList = existing .Select(e => new KeyValuePair(e.Key, e.Value)) - .Where(e => e.Key != ValueTypeKey) + .Where(e => e.Key != Constants.PropertyEditors.DataValueTypePreValueKey) .ToList(); - var result = new Dictionary { { ValueTypeKey, valueType } }; + var result = new Dictionary { { Constants.PropertyEditors.DataValueTypePreValueKey, valueType } }; if (asList.Any()) { result.Add("values", asList); From 271f4e7a4a60ddd75ddb3b0c7eef5ef88d7db84d Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 10 May 2016 12:29:13 +0200 Subject: [PATCH 033/535] U4-8413 - fix missing ServersLock object --- src/Umbraco.Core/Constants-ObjectTypes.cs | 5 +- .../Migrations/Initial/BaseDataCreation.cs | 7 ++- .../EnsureServersLockObject.cs | 54 +++++++++++++++++++ src/Umbraco.Core/Umbraco.Core.csproj | 1 + .../config/ClientDependency.config | 2 +- .../config/umbracoSettings.config | 2 + 6 files changed, 67 insertions(+), 4 deletions(-) create mode 100644 src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenFiveZero/EnsureServersLockObject.cs diff --git a/src/Umbraco.Core/Constants-ObjectTypes.cs b/src/Umbraco.Core/Constants-ObjectTypes.cs index 560cd4b306..7ec45db7be 100644 --- a/src/Umbraco.Core/Constants-ObjectTypes.cs +++ b/src/Umbraco.Core/Constants-ObjectTypes.cs @@ -143,7 +143,10 @@ namespace Umbraco.Core /// public const string LockObject = "87A9F1FF-B1E4-4A25-BABB-465A4A47EC41"; - + /// + /// Guid for a Lock object. + /// + public static readonly Guid LockObjectGuid = new Guid(LockObject); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs b/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs index fa3c60ffa1..8046de454b 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Initial/BaseDataCreation.cs @@ -134,13 +134,16 @@ namespace Umbraco.Core.Persistence.Migrations.Initial _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1043, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1043", SortOrder = 2, UniqueId = new Guid("1df9f033-e6d4-451f-b8d2-e0cbc50a836f"), Text = "Image Cropper", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1044, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1044", SortOrder = 0, UniqueId = new Guid("d59be02f-1df9-4228-aa1e-01917d806cda"), Text = Constants.Conventions.MemberTypes.DefaultAlias, NodeObjectType = new Guid(Constants.ObjectTypes.MemberType), CreateDate = DateTime.Now }); _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1045, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1045", SortOrder = 2, UniqueId = new Guid("7E3962CC-CE20-4FFC-B661-5897A894BA7E"), Text = "Multiple Media Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); - + //TODO: We're not creating these for 7.0 //_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1039, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1039", SortOrder = 2, UniqueId = new Guid("06f349a9-c949-4b6a-8660-59c10451af42"), Text = "Ultimate Picker", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); //_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1038, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1038", SortOrder = 2, UniqueId = new Guid("1251c96c-185c-4e9b-93f4-b48205573cbd"), Text = "Simple Editor", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); - + //_database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = 1042, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1,1042", SortOrder = 2, UniqueId = new Guid("0a452bd5-83f9-4bc3-8403-1286e13fb77e"), Text = "Macro Container", NodeObjectType = new Guid(Constants.ObjectTypes.DataType), CreateDate = DateTime.Now }); + + // all lock objects + _database.Insert("umbracoNode", "id", false, new NodeDto { NodeId = Constants.System.ServersLock, Trashed = false, ParentId = -1, UserId = 0, Level = 1, Path = "-1," + Constants.System.ServersLock, SortOrder = 1, UniqueId = new Guid("0AF5E610-A310-4B6F-925F-E928D5416AF7"), Text = "LOCK: Servers", NodeObjectType = Constants.ObjectTypes.LockObjectGuid, CreateDate = DateTime.Now }); } private void CreateCmsContentTypeData() diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenFiveZero/EnsureServersLockObject.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenFiveZero/EnsureServersLockObject.cs new file mode 100644 index 0000000000..6542bf4798 --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenFiveZero/EnsureServersLockObject.cs @@ -0,0 +1,54 @@ +using System; +using Umbraco.Core.Configuration; +using Umbraco.Core.Logging; +using Umbraco.Core.Models.Rdbms; +using Umbraco.Core.Persistence.SqlSyntax; + +namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenFiveZero +{ + [Migration("7.5.0", 10, GlobalSettings.UmbracoMigrationName)] + public class EnsureServersLockObject : MigrationBase + { + public EnsureServersLockObject(ISqlSyntaxProvider sqlSyntax, ILogger logger) + : base(sqlSyntax, logger) + { } + + public override void Up() + { + // that lock object should have been part of BaseDataCreation since 7.3.0 but + // for some reason it was not, so it was created during migrations but not during + // new installs, so for ppl that upgrade, make sure they have it + + EnsureLockObject(Constants.System.ServersLock, "0AF5E610-A310-4B6F-925F-E928D5416AF7", "LOCK: Servers"); + } + + public override void Down() + { + // not implemented + } + + private void EnsureLockObject(int id, string uniqueId, string text) + { + var exists = Context.Database.Exists(id); + if (exists) return; + + Insert + .IntoTable("umbracoNode") + .EnableIdentityInsert() + .Row(new + { + id = id, // NodeId + trashed = false, + parentId = -1, + nodeUser = 0, + level = 1, + path = "-1," + id, + sortOrder = 0, + uniqueId = new Guid(uniqueId), + text = text, + nodeObjectType = new Guid(Constants.ObjectTypes.LockObject), + createDate = DateTime.Now + }); + } + } +} diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index ce34b6ef8f..2bbf4a7c7b 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -415,6 +415,7 @@ + diff --git a/src/Umbraco.Web.UI/config/ClientDependency.config b/src/Umbraco.Web.UI/config/ClientDependency.config index 72cb97f698..2115c540b7 100644 --- a/src/Umbraco.Web.UI/config/ClientDependency.config +++ b/src/Umbraco.Web.UI/config/ClientDependency.config @@ -10,7 +10,7 @@ NOTES: * Compression/Combination/Minification is not enabled unless debug="false" is specified on the 'compiliation' element in the web.config * A new version will invalidate both client and server cache and create new persisted files --> - + 1 + 1079 + 1080 From 7ae1060f504f58e9fd2e0238444e0b81c7371521 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 10 May 2016 18:25:18 +0200 Subject: [PATCH 034/535] U4-7295 Examine search with the data in the grid should be easier OOTB --- .../PropertyEditors/GridPropertyEditor.cs | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs index 5228bde1a5..e69c3ae94a 100644 --- a/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs @@ -3,15 +3,103 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using Examine; +using Lucene.Net.Documents; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Umbraco.Core; +using Umbraco.Core.Logging; using Umbraco.Core.Models; using Umbraco.Core.PropertyEditors; using Umbraco.Core.Services; +using UmbracoExamine; namespace Umbraco.Web.PropertyEditors { [PropertyEditor(Core.Constants.PropertyEditors.GridAlias, "Grid layout", "grid", HideLabel = true, IsParameterEditor = false, ValueType = "JSON", Group="rich content", Icon="icon-layout")] public class GridPropertyEditor : PropertyEditor { + /// + /// We're going to bind to the Examine events so we can ensure grid data is index nicely + /// + /// + /// I think this kind of logic belongs on this property editor, putting this inside of the indexer certainly doesn't seem right + /// + static GridPropertyEditor() + { + foreach (var i in ExamineManager.Instance.IndexProviderCollection.OfType()) + { + i.DocumentWriting += DocumentWriting; + } + } + + private static void DocumentWriting(object sender, Examine.LuceneEngine.DocumentWritingEventArgs e) + { + var indexer = (BaseUmbracoIndexer)sender; + foreach (var field in indexer.IndexerData.UserFields) + { + if (e.Fields.ContainsKey(field.Name)) + { + if (e.Fields[field.Name].DetectIsJson()) + { + try + { + var json = JsonConvert.DeserializeObject(e.Fields[field.Name]); + + //check if this is formatted for grid json + JToken name; + JToken sections; + if (json.HasValues && json.TryGetValue("name", out name) && json.TryGetValue("sections", out sections)) + { + //get all values and put them into a single field (using JsonPath) + var sb = new StringBuilder(); + foreach (var row in json.SelectTokens("$.sections[*].rows[*]")) + { + var rowName = row["name"].Value(); + var areaVals = row.SelectTokens("$.areas[*].controls[*].value"); + + foreach (var areaVal in areaVals) + { + var str = areaVal.Value(); + str = XmlHelper.CouldItBeXml(str) ? str.StripHtml() : str; + sb.Append(str); + sb.Append(" "); + + //add the row name as an individual field + e.Document.Add( + new Field( + string.Format("{0}.{1}", field.Name, rowName), str, Field.Store.YES, Field.Index.ANALYZED)); + } + } + + if (sb.Length > 0) + { + //First save the raw value to a raw field + e.Document.Add( + new Field( + string.Format("{0}{1}", UmbracoContentIndexer.RawFieldPrefix, field.Name), + e.Fields[field.Name], Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS, Field.TermVector.NO)); + + //now replace the original value with the combined/cleaned value + e.Document.RemoveField(field.Name); + e.Document.Add( + new Field( + field.Name, + sb.ToString(), Field.Store.YES, Field.Index.ANALYZED)); + } + } + } + catch (JsonException) + { + //swallow...on purpose, there's a chance that this isn't json and we don't want that to affect + // the website. + } + + } + } + } + } + /// /// Overridden to ensure that the value is validated /// From fb55b0a60b2e9f89c7c50413548603967759d7c9 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 10 May 2016 18:32:32 +0200 Subject: [PATCH 035/535] U4-8371 Dont ship with the {machinename} token for Examine --- src/Umbraco.Web.UI/config/ExamineIndex.config | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI/config/ExamineIndex.config b/src/Umbraco.Web.UI/config/ExamineIndex.config index 7212053ca0..a853847ecb 100644 --- a/src/Umbraco.Web.UI/config/ExamineIndex.config +++ b/src/Umbraco.Web.UI/config/ExamineIndex.config @@ -9,10 +9,10 @@ More information and documentation can be found on CodePlex: http://umbracoexami - + - + @@ -25,6 +25,6 @@ More information and documentation can be found on CodePlex: http://umbracoexami - + \ No newline at end of file From 02ffaa9ee84ff125a031056874b052b9ad361dde Mon Sep 17 00:00:00 2001 From: Dennis Aaen Date: Tue, 10 May 2016 20:33:03 +0200 Subject: [PATCH 036/535] Fixed issue: U4-8435 so the link is correct in settingsdashboardintro dashboard --- .../src/views/dashboard/settings/settingsdashboardintro.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/settingsdashboardintro.html b/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/settingsdashboardintro.html index fa9849022c..3a45776872 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/settingsdashboardintro.html +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/settings/settingsdashboardintro.html @@ -9,6 +9,6 @@
  • Download the Editors Manual for details on working with the Umbraco UI
  • Ask a question in the Community Forum
  • Watch our tutorial videos (some are free, some require a subscription)
  • -
  • Find out about our productivity boosting tools and commercial support
  • +
  • Find out about our productivity boosting tools and commercial support
  • Find out about real-life training and certification opportunities
  • From 597b4c3dd280a7013a46c10f77d0504d7b446f76 Mon Sep 17 00:00:00 2001 From: Lars-Erik Aabech Date: Wed, 11 May 2016 21:44:22 +0200 Subject: [PATCH 037/535] Added button to create only available doctype Hides dropdown when listViewAllowedTypes.length > 1 Shows button for single when listViewAllowedTypes.length === 1 --- .../src/views/propertyeditors/listview/listview.html | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html index 904939b75f..be31221522 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.html @@ -11,7 +11,7 @@ -
    + + From 4d0dc90042600002a788657178726865a2584265 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 12 May 2016 11:16:39 +0200 Subject: [PATCH 038/535] Revert "RteMacroRenderingValueConverter should return an IHtmlString" This reverts commit 7e9a14be83fc0fd8c82f03ed27d10a387dbba5e6. --- .../ValueConverters/RteMacroRenderingValueConverter.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs b/src/Umbraco.Web/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs index d6e866e06a..2802a4d631 100644 --- a/src/Umbraco.Web/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs +++ b/src/Umbraco.Web/PropertyEditors/ValueConverters/RteMacroRenderingValueConverter.cs @@ -15,7 +15,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters { /// - /// A value converter for TinyMCE that will ensure any macro content is rendered properly even when + /// A value converter for TinyMCE that will ensure any macro content is rendered properly even when /// used dynamically. /// // because that version of RTE converter parses {locallink} and executes macros, when going from @@ -38,7 +38,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters UmbracoContext.Current.InPreviewMode = preview; var sb = new StringBuilder(); - + try { var umbracoHelper = new UmbracoHelper(UmbracoContext.Current); @@ -55,7 +55,7 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters finally { // restore - UmbracoContext.Current.InPreviewMode = inPreviewMode; + UmbracoContext.Current.InPreviewMode = inPreviewMode; } return sb.ToString(); @@ -109,12 +109,12 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters if (modified) { - return new HtmlString(doc.DocumentNode.OuterHtml); + return doc.DocumentNode.OuterHtml; } } } - return new HtmlString(sourceString ?? string.Empty); + return sourceString; } } } \ No newline at end of file From f130e86c88210d49015827a2d2c2378346ce2d32 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 12 May 2016 12:27:02 +0200 Subject: [PATCH 039/535] U4-8448 Background task runner missing a null check during shutdown --- src/Umbraco.Web/Scheduling/BackgroundTaskRunner.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web/Scheduling/BackgroundTaskRunner.cs b/src/Umbraco.Web/Scheduling/BackgroundTaskRunner.cs index adb9c6c0dd..d63fbb4606 100644 --- a/src/Umbraco.Web/Scheduling/BackgroundTaskRunner.cs +++ b/src/Umbraco.Web/Scheduling/BackgroundTaskRunner.cs @@ -305,7 +305,9 @@ namespace Umbraco.Web.Scheduling // tasks in the queue will be executed... if (wait == false) return; - _runningTask.Wait(); // wait for whatever is running to end... + + if (_runningTask != null) + _runningTask.Wait(); // wait for whatever is running to end... } /// From 4752a8313529b68b476ee8c28e72449cd08115dd Mon Sep 17 00:00:00 2001 From: Simon Busborg Date: Tue, 17 May 2016 11:02:01 +0200 Subject: [PATCH 040/535] Fixes: U4-8362 Inserting image in a grid with Firefox shows full-size rather than scaled image --- .../src/less/property-editors.less | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/Umbraco.Web.UI.Client/src/less/property-editors.less b/src/Umbraco.Web.UI.Client/src/less/property-editors.less index a06484b8a0..96deaef09a 100644 --- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less +++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less @@ -201,6 +201,15 @@ ul.color-picker li a { margin: 5px; background: white; border: 1px solid #f8f8f8; + + max-width: 100%; +} + + +.umb-mediapicker .umb-sortable-thumbnails li { + flex-direction: column; + margin: 0; + padding: 5px; } @@ -384,6 +393,7 @@ ul.color-picker li a { } .umb-cropper-gravity .viewport, .umb-cropper-gravity, .umb-cropper-imageholder { display: inline-block; + max-width: 100%; } .umb-cropper-imageholder { From d826f04b548ce9e10ac34662fd478eb8e382234f Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 17 May 2016 12:17:05 +0200 Subject: [PATCH 041/535] Ensures sort order is accurate to what is in the database --- src/Umbraco.Web/umbraco.presentation/content.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web/umbraco.presentation/content.cs b/src/Umbraco.Web/umbraco.presentation/content.cs index bdd8c91f18..dc303c809d 100644 --- a/src/Umbraco.Web/umbraco.presentation/content.cs +++ b/src/Umbraco.Web/umbraco.presentation/content.cs @@ -528,12 +528,14 @@ where umbracoNode.id in (select cmsDocument.nodeId from cmsDocument where cmsDoc order by umbracoNode.level, umbracoNode.parentID, umbracoNode.sortOrder"; XmlElement last = null; + var db = ApplicationContext.Current.DatabaseContext.Database; //NOTE: Query creates a reader - does not load all into memory foreach (var row in db.Query(sql, new { type = new Guid(Constants.ObjectTypes.Document)})) { string parentId = ((int)row.parentID).ToInvariantString(); string xml = row.xml; + int sortOrder = row.sortOrder; //if the parentid is changing if (last != null && last.GetAttribute("parentID") != parentId) @@ -544,8 +546,11 @@ order by umbracoNode.level, umbracoNode.parentID, umbracoNode.sortOrder"; var xmlDocFragment = xmlDoc.CreateDocumentFragment(); xmlDocFragment.InnerXml = xml; - + last = (XmlElement)parent.AppendChild(xmlDocFragment); + + // fix sortOrder - see notes in UpdateSortOrder + last.Attributes["sortOrder"].Value = sortOrder.ToInvariantString(); } LogHelper.Debug("Done republishing Xml Index"); From 1e468cda5d440f676b6563667219251c5a68dfa1 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 17 May 2016 13:26:47 +0200 Subject: [PATCH 042/535] Removes unused method, ensures that Cloning only occurs once per request (sort of hacky). Before if you have a few nodes that are published but have pending changes, then perform a sort, then the xml will be cloned for as many times as there were content changes. --- .../umbraco.presentation/content.cs | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/Umbraco.Web/umbraco.presentation/content.cs b/src/Umbraco.Web/umbraco.presentation/content.cs index dc303c809d..7a53f38ccf 100644 --- a/src/Umbraco.Web/umbraco.presentation/content.cs +++ b/src/Umbraco.Web/umbraco.presentation/content.cs @@ -120,6 +120,7 @@ namespace umbraco private static readonly object DbReadSyncLock = new object(); private const string XmlContextContentItemKey = "UmbracoXmlContextContent"; + private const string XmlContextClonedContentItemKey = "UmbracoXmlContextContent.cloned"; private static string _umbracoXmlDiskCacheFileName = string.Empty; private volatile XmlDocument _xmlContent; @@ -685,11 +686,6 @@ order by umbracoNode.level, umbracoNode.parentID, umbracoNode.sortOrder"; _persisterTask = _persisterTask.Touch(); // _persisterTask != null because SyncToXmlFile == true } - private static XmlDocument Clone(XmlDocument xmlDoc) - { - return xmlDoc == null ? null : (XmlDocument)xmlDoc.CloneNode(true); - } - private static XmlDocument EnsureSchema(string contentTypeAlias, XmlDocument xml) { string subset = null; @@ -750,13 +746,6 @@ order by umbracoNode.level, umbracoNode.parentID, umbracoNode.sortOrder"; return SafeXmlReaderWriter.GetReader(this, releaser); } - // gets a locked safe read accses to the main xml - private async Task GetSafeXmlReaderAsync() - { - var releaser = await _xmlLock.LockAsync(); - return SafeXmlReaderWriter.GetReader(this, releaser); - } - // gets a locked safe write access to the main xml (cloned) private SafeXmlReaderWriter GetSafeXmlWriter(bool auto = true) { @@ -837,6 +826,28 @@ order by umbracoNode.level, umbracoNode.parentID, umbracoNode.sortOrder"; _releaser.Dispose(); _releaser = null; } + + /// + /// This will clone the xml document - but we will try to only clone one time in a request + /// + /// + /// + private XmlDocument Clone(XmlDocument xmlDoc) + { + if (UmbracoContext.Current == null || UmbracoContext.Current.HttpContext == null) + { + //in this case we'll always clone + return xmlDoc == null ? null : (XmlDocument)xmlDoc.CloneNode(true); + } + + var clone = UmbracoContext.Current.HttpContext.Items[XmlContextClonedContentItemKey]; + if (clone == null) + { + UmbracoContext.Current.HttpContext.Items[XmlContextClonedContentItemKey] = xmlDoc == null ? null : (XmlDocument)xmlDoc.CloneNode(true); + } + + return (XmlDocument)UmbracoContext.Current.HttpContext.Items[XmlContextClonedContentItemKey]; + } } private static string ChildNodesXPath From 512c19a13208ab7091c34174479fad10255b6f4a Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 17 May 2016 13:27:45 +0200 Subject: [PATCH 043/535] U4-8461 ERROR umbraco.presentation.webservices.nodeSorter - Could not update content sort order --- .../umbraco/webservices/nodeSorter.asmx.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/nodeSorter.asmx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/nodeSorter.asmx.cs index 1ab2346054..e383e658aa 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/nodeSorter.asmx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/webservices/nodeSorter.asmx.cs @@ -192,7 +192,10 @@ namespace umbraco.presentation.webservices //content.Instance.SortNodes(parentId); //send notifications! TODO: This should be put somewhere centralized instead of hard coded directly here - ApplicationContext.Services.NotificationService.SendNotification(contentService.GetById(parentId), ActionSort.Instance, UmbracoContext, ApplicationContext); + if (parentId > 0) + { + ApplicationContext.Services.NotificationService.SendNotification(contentService.GetById(parentId), ActionSort.Instance, UmbracoContext, ApplicationContext); + } } catch (Exception ex) From 95871fde7c9c7ec71c7a89f774b3f316564b30bd Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 19 May 2016 15:22:49 +0200 Subject: [PATCH 044/535] updates naming conventions --- .../TestHelpers/BaseDatabaseFactoryTest.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs b/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs index d24a411f73..996b7e2fff 100644 --- a/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs +++ b/src/Umbraco.Tests/TestHelpers/BaseDatabaseFactoryTest.cs @@ -57,7 +57,7 @@ namespace Umbraco.Tests.TestHelpers private string _dbPath; //used to store (globally) the pre-built db with schema and initial data private static Byte[] _dbBytes; - private DefaultDatabaseFactory dbFactory; + private DefaultDatabaseFactory _dbFactory; [SetUp] public override void Initialize() @@ -67,7 +67,7 @@ namespace Umbraco.Tests.TestHelpers var path = TestHelper.CurrentAssemblyDirectory; AppDomain.CurrentDomain.SetData("DataDirectory", path); - dbFactory = new DefaultDatabaseFactory( + _dbFactory = new DefaultDatabaseFactory( GetDbConnectionString(), GetDbProviderName(), Logger); @@ -79,7 +79,7 @@ namespace Umbraco.Tests.TestHelpers { //TODO: Somehow make this faster - takes 5s + - DatabaseContext.Initialize(dbFactory.ProviderName, dbFactory.ConnectionString); + DatabaseContext.Initialize(_dbFactory.ProviderName, _dbFactory.ConnectionString); CreateSqlCeDatabase(); InitializeDatabase(); @@ -98,9 +98,9 @@ namespace Umbraco.Tests.TestHelpers var evtMsgs = new TransientMessagesFactory(); _appContext = new ApplicationContext( //assign the db context - new DatabaseContext(dbFactory, Logger, SqlSyntax, "System.Data.SqlServerCe.4.0"), + new DatabaseContext(_dbFactory, Logger, SqlSyntax, "System.Data.SqlServerCe.4.0"), //assign the service context - new ServiceContext(repositoryFactory, new PetaPocoUnitOfWorkProvider(dbFactory), new FileUnitOfWorkProvider(), new PublishingStrategy(evtMsgs, Logger), cacheHelper, Logger, evtMsgs), + new ServiceContext(repositoryFactory, new PetaPocoUnitOfWorkProvider(_dbFactory), new FileUnitOfWorkProvider(), new PublishingStrategy(evtMsgs, Logger), cacheHelper, Logger, evtMsgs), cacheHelper, ProfilingLogger) { From 06ae15ee7c40a527d0c0d8f8b1c4dce990a55515 Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 19 May 2016 16:12:12 +0200 Subject: [PATCH 045/535] reverts the cloning change --- .../umbraco.presentation/content.cs | 28 ++++--------------- 1 file changed, 6 insertions(+), 22 deletions(-) diff --git a/src/Umbraco.Web/umbraco.presentation/content.cs b/src/Umbraco.Web/umbraco.presentation/content.cs index 7a53f38ccf..1e013da452 100644 --- a/src/Umbraco.Web/umbraco.presentation/content.cs +++ b/src/Umbraco.Web/umbraco.presentation/content.cs @@ -686,6 +686,11 @@ order by umbracoNode.level, umbracoNode.parentID, umbracoNode.sortOrder"; _persisterTask = _persisterTask.Touch(); // _persisterTask != null because SyncToXmlFile == true } + private static XmlDocument Clone(XmlDocument xmlDoc) + { + return xmlDoc == null ? null : (XmlDocument)xmlDoc.CloneNode(true); + } + private static XmlDocument EnsureSchema(string contentTypeAlias, XmlDocument xml) { string subset = null; @@ -826,28 +831,7 @@ order by umbracoNode.level, umbracoNode.parentID, umbracoNode.sortOrder"; _releaser.Dispose(); _releaser = null; } - - /// - /// This will clone the xml document - but we will try to only clone one time in a request - /// - /// - /// - private XmlDocument Clone(XmlDocument xmlDoc) - { - if (UmbracoContext.Current == null || UmbracoContext.Current.HttpContext == null) - { - //in this case we'll always clone - return xmlDoc == null ? null : (XmlDocument)xmlDoc.CloneNode(true); - } - - var clone = UmbracoContext.Current.HttpContext.Items[XmlContextClonedContentItemKey]; - if (clone == null) - { - UmbracoContext.Current.HttpContext.Items[XmlContextClonedContentItemKey] = xmlDoc == null ? null : (XmlDocument)xmlDoc.CloneNode(true); - } - - return (XmlDocument)UmbracoContext.Current.HttpContext.Items[XmlContextClonedContentItemKey]; - } + } private static string ChildNodesXPath From e54d374eb29b71edb84701fcdccd994302573296 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Fri, 20 May 2016 15:54:39 +0200 Subject: [PATCH 046/535] Add cmsPreviewXml table if it doesn't yet exist --- .../AddPreviewXmlTable.cs | 32 +++++++++++++++++++ src/Umbraco.Core/Umbraco.Core.csproj | 1 + 2 files changed, 33 insertions(+) create mode 100644 src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionFourOneZero/AddPreviewXmlTable.cs diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionFourOneZero/AddPreviewXmlTable.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionFourOneZero/AddPreviewXmlTable.cs new file mode 100644 index 0000000000..4e8d3165fb --- /dev/null +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionFourOneZero/AddPreviewXmlTable.cs @@ -0,0 +1,32 @@ +using System.Linq; +using Umbraco.Core.Configuration; +using Umbraco.Core.Logging; +using Umbraco.Core.Persistence.SqlSyntax; + +namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionFourOneZero +{ + [Migration("4.1.0", 0, GlobalSettings.UmbracoMigrationName)] + public class AddPreviewXmlTable : MigrationBase + { + public AddPreviewXmlTable(ISqlSyntaxProvider sqlSyntax, ILogger logger) + : base(sqlSyntax, logger) + { + } + + public override void Up() + { + var tableName = "cmsPreviewXml"; + var tables = SqlSyntax.GetTablesInSchema(Context.Database).ToArray(); + if (tables.InvariantContains(tableName)) return; + + Create.Table(tableName) + .WithColumn("nodeId").AsInt32().NotNullable() + .WithColumn("versionId").AsGuid().NotNullable() + .WithColumn("timestamp").AsDateTime().NotNullable() + .WithColumn("xml").AsString(); + } + + public override void Down() + { } + } +} \ No newline at end of file diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 2bbf4a7c7b..055be82ff1 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -415,6 +415,7 @@ + From 8c7390280e03f91936622636e2bb6db7d32b6e6c Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Fri, 20 May 2016 16:36:22 +0200 Subject: [PATCH 047/535] Updates this migration to only run when upgrading from 7.3.0 and higher --- .../TargetVersionSevenFiveZero/EnsureServersLockObject.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenFiveZero/EnsureServersLockObject.cs b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenFiveZero/EnsureServersLockObject.cs index 6542bf4798..6f9d74e5db 100644 --- a/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenFiveZero/EnsureServersLockObject.cs +++ b/src/Umbraco.Core/Persistence/Migrations/Upgrades/TargetVersionSevenFiveZero/EnsureServersLockObject.cs @@ -6,7 +6,10 @@ using Umbraco.Core.Persistence.SqlSyntax; namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenFiveZero { - [Migration("7.5.0", 10, GlobalSettings.UmbracoMigrationName)] + // This migration exists for 7.3.0 but it seems like it was not always running properly + // if you're upgrading from 7.3.0 or higher than we add this migration, if you're upgrading + // from 7.3.0 or lower then you will already get this migration in the migration to get to 7.3.0 + [Migration("7.3.0", "7.5.0", 10, GlobalSettings.UmbracoMigrationName)] public class EnsureServersLockObject : MigrationBase { public EnsureServersLockObject(ISqlSyntaxProvider sqlSyntax, ILogger logger) From 2ffbdec14bc6b870b5d355d89e3a66f29b60d798 Mon Sep 17 00:00:00 2001 From: Gerard Konings Date: Fri, 20 May 2016 22:40:26 +0200 Subject: [PATCH 048/535] Removed required attribute from slider-handle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removed required attribute. Slider defaults to round, so doesn’t need to be required --- .../src/views/propertyeditors/slider/handle.prevalues.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/slider/handle.prevalues.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/slider/handle.prevalues.html index e12cb2a869..ae5deb099c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/slider/handle.prevalues.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/slider/handle.prevalues.html @@ -1,5 +1,5 @@ 
    - From 3897d0f764b83a80e887f128367d9cd38994179d Mon Sep 17 00:00:00 2001 From: Gerard Konings Date: Fri, 20 May 2016 22:44:18 +0200 Subject: [PATCH 049/535] disable submitbutton disable submitbutton on overlay, so you can enable it later on --- .../src/views/components/overlays/umb-overlay.html | 1 + 1 file changed, 1 insertion(+) 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 9bc0839122..472408468b 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 @@ -66,6 +66,7 @@ label="{{model.submitButtonLabel}}" ng-if="model.submit && model.hideSubmitButton !== true" type="button" + disabled="model.disableSubmitButton" action="submitForm(model)">
    From d7cb79513f808e4b12ccd9f8d7aac6e24e5d6feb Mon Sep 17 00:00:00 2001 From: bjarnef Date: Sat, 21 May 2016 21:49:00 +0200 Subject: [PATCH 050/535] Adjust login for narrow screen sizes. --- .../src/less/pages/login.less | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/pages/login.less b/src/Umbraco.Web.UI.Client/src/less/pages/login.less index 6805783a86..51cb5aae38 100644 --- a/src/Umbraco.Web.UI.Client/src/less/pages/login.less +++ b/src/Umbraco.Web.UI.Client/src/less/pages/login.less @@ -13,7 +13,9 @@ left: 0; margin: 0 !important; padding: 0; + border: none; border-radius: 0; + overflow-y: auto; } @@ -50,7 +52,7 @@ } .login-overlay .form { - position:fixed; + position:relative; display: block; top: 100px; left: 165px; @@ -78,11 +80,25 @@ margin-top: 10px; } +@media (max-width: 767px) and (max-height: 420px){ + .login-overlay .form { + top: 60px; + } +} + @media (max-width: 565px) { // Remove padding on login-form on smaller devices .login-overlay .form { + top: 60px; + right: 25px; left: inherit; - right:25px; + padding-left: 25px; + padding-right:25px; + width: auto; + + input[type="text"], input[type="password"] { + width: 250px; + } } } From a8712fb4cf236d5664cd0908d628b9d2d9c6227e Mon Sep 17 00:00:00 2001 From: bjarnef Date: Sat, 21 May 2016 21:51:28 +0200 Subject: [PATCH 051/535] Added a comment --- src/Umbraco.Web.UI.Client/src/less/pages/login.less | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI.Client/src/less/pages/login.less b/src/Umbraco.Web.UI.Client/src/less/pages/login.less index 51cb5aae38..acd3df2556 100644 --- a/src/Umbraco.Web.UI.Client/src/less/pages/login.less +++ b/src/Umbraco.Web.UI.Client/src/less/pages/login.less @@ -81,6 +81,7 @@ } @media (max-width: 767px) and (max-height: 420px){ + // Move form closer to top on narrow screen sizes .login-overlay .form { top: 60px; } From ccd42ad1d42d554861afd88a97cc1cb66ae9c3f4 Mon Sep 17 00:00:00 2001 From: bjarnef Date: Sat, 21 May 2016 22:42:58 +0200 Subject: [PATCH 052/535] Fix some issues in landscape mode --- src/Umbraco.Web.UI.Client/src/less/pages/login.less | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/pages/login.less b/src/Umbraco.Web.UI.Client/src/less/pages/login.less index acd3df2556..892977180e 100644 --- a/src/Umbraco.Web.UI.Client/src/less/pages/login.less +++ b/src/Umbraco.Web.UI.Client/src/less/pages/login.less @@ -80,10 +80,10 @@ margin-top: 10px; } -@media (max-width: 767px) and (max-height: 420px){ +@media (max-width: 767px) and (max-height: 420px) and (orientation: landscape) { // Move form closer to top on narrow screen sizes .login-overlay .form { - top: 60px; + top: 50px; } } @@ -96,9 +96,13 @@ padding-left: 25px; padding-right:25px; width: auto; + } +} +@media (max-width: 339px) { + .login-overlay .form { input[type="text"], input[type="password"] { - width: 250px; + width: 250px; } } } From 3c9de3b20c371a4d1d44b90573388ec3961789ce Mon Sep 17 00:00:00 2001 From: bjarnef Date: Sat, 21 May 2016 23:43:37 +0200 Subject: [PATCH 053/535] Ensure correct font is used for icon-check --- src/Umbraco.Web.UI.Client/src/less/tree.less | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/tree.less b/src/Umbraco.Web.UI.Client/src/less/tree.less index 86c9e4d081..dcbae04995 100644 --- a/src/Umbraco.Web.UI.Client/src/less/tree.less +++ b/src/Umbraco.Web.UI.Client/src/less/tree.less @@ -208,7 +208,9 @@ content: "\e165"; } -.umb-tree .umb-tree-node-checked i { +.umb-tree .umb-tree-node-checked i[class^="icon-"], +.umb-tree .umb-tree-node-checked i[class*=" icon-"] { + font-family: icomoon !important; color:@blue !important; } .umb-tree .umb-tree-node-checked i:before { From b74bf661b829d7d8eda3e0fe601baec0676eda5f Mon Sep 17 00:00:00 2001 From: bjarnef Date: Sat, 21 May 2016 23:57:30 +0200 Subject: [PATCH 054/535] Added quotes --- src/Umbraco.Web.UI.Client/src/less/tree.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/tree.less b/src/Umbraco.Web.UI.Client/src/less/tree.less index dcbae04995..d809418f2c 100644 --- a/src/Umbraco.Web.UI.Client/src/less/tree.less +++ b/src/Umbraco.Web.UI.Client/src/less/tree.less @@ -210,7 +210,7 @@ .umb-tree .umb-tree-node-checked i[class^="icon-"], .umb-tree .umb-tree-node-checked i[class*=" icon-"] { - font-family: icomoon !important; + font-family: 'icomoon' !important; color:@blue !important; } .umb-tree .umb-tree-node-checked i:before { From 5fab1ca207db4d82ac064b22741ad16f74a4809a Mon Sep 17 00:00:00 2001 From: bjarnef Date: Sun, 22 May 2016 13:46:48 +0200 Subject: [PATCH 055/535] Localize move and copy overlay titles opened from listview actions. Prepare localization of bulk messages. --- .../src/views/common/overlays/copy/copy.html | 2 +- .../listview/listview.controller.js | 95 ++++++++++++++++--- src/Umbraco.Web.UI/Umbraco/config/lang/cs.xml | 28 ++++++ src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml | 28 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/da.xml | 59 +++++++++++- src/Umbraco.Web.UI/umbraco/config/lang/de.xml | 28 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/en.xml | 28 ++++++ .../umbraco/config/lang/en_us.xml | 28 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/es.xml | 28 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/fr.xml | 28 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/he.xml | 28 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/it.xml | 28 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/ja.xml | 28 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/ko.xml | 28 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/nl.xml | 28 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/pl.xml | 28 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/pt.xml | 28 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/ru.xml | 28 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/sv.xml | 28 ++++++ src/Umbraco.Web.UI/umbraco/config/lang/zh.xml | 28 ++++++ 20 files changed, 615 insertions(+), 17 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/common/overlays/copy/copy.html b/src/Umbraco.Web.UI.Client/src/views/common/overlays/copy/copy.html index adb57b4af0..c0e22c4d27 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/overlays/copy/copy.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/overlays/copy/copy.html @@ -31,8 +31,8 @@
    - diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js index 518c27d110..2ea325b451 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js @@ -208,7 +208,7 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie $timeout(function () { $scope.bulkStatus = ""; $scope.actionInProgress = false; - }, 500); + }, 0); if (reload === true) { $scope.reloadView($scope.contentId); @@ -220,7 +220,9 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie } } else if (successMsg) { - notificationsService.success("Done", successMsg); + localizationService.localize("bulk_done").then(function (v) { + notificationsService.success(v, successMsg); + }); } } @@ -368,28 +370,67 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie $scope.delete = function () { applySelected( function (selected, index) { return deleteItemCallback(getIdCallback(selected[index])); }, - function (count, total) { return "Deleted " + count + " out of " + total + " item" + (total > 1 ? "s" : ""); }, - function (total) { return "Deleted " + total + " item" + (total > 1 ? "s" : ""); }, + function (count, total) { + return "Deleted " + count + " out of " + total + " item" + (total > 1 ? "s" : ""); + //var key = (total === 1 ? "bulk_deletedItemOfItem" : "bulk_deletedItemOfItems"); + //localizationService.localize(key, [count, total]).then(function (value) { + // return value; + //}); + }, + function (total) { + return "Deleted " + total + " item" + (total > 1 ? "s" : ""); + //var key = (total === 1 ? "bulk_deletedItem" : "bulk_deletedItems"); + //localizationService.localize(key, [total]).then(function (value) { + // return value; + //}); + }, + //localizationService.localize("defaultdialogs_confirmdelete") + "?" "Sure you want to delete?"); }; - $scope.publish = function () { + $scope.publish = function () { applySelected( function (selected, index) { return contentResource.publishById(getIdCallback(selected[index])); }, - function (count, total) { return "Published " + count + " out of " + total + " item" + (total > 1 ? "s" : ""); }, - function (total) { return "Published " + total + " item" + (total > 1 ? "s" : ""); }); + function (count, total) { + return "Published " + count + " out of " + total + " item" + (total > 1 ? "s" : ""); + //var key = (total === 1 ? "bulk_publishedItemOfItem" : "bulk_publishedItemOfItems"); + //localizationService.localize(key, [count, total]).then(function (value) { + // console.log(key, value); + // return value; + //}); + }, + function (total) { + return "Published " + total + " item" + (total > 1 ? "s" : ""); + //var key = (total === 1 ? "bulk_publishedItem" : "bulk_publishedItems"); + //localizationService.localize(key, [total]).then(function (value) { + // console.log(key, value); + // return value; + //}); + }); }; $scope.unpublish = function () { applySelected( function (selected, index) { return contentResource.unPublish(getIdCallback(selected[index])); }, - function (count, total) { return "Unpublished " + count + " out of " + total + " item" + (total > 1 ? "s" : ""); }, - function (total) { return "Unpublished " + total + " item" + (total > 1 ? "s" : ""); }); + function (count, total) { + return "Unpublished " + count + " out of " + total + " item" + (total > 1 ? "s" : ""); + //var key = (total === 1 ? "bulk_unpublishedItemOfItem" : "bulk_unpublishedItemOfItems"); + //localizationService.localize(key, [count, total]).then(function (value) { + // return value; + //}); + }, + function (total) { + return "Unpublished " + total + " item" + (total > 1 ? "s" : ""); + //var key = (total === 1 ? "bulk_unpublishedItem" : "bulk_unpublishedItems"); + //localizationService.localize(key, [total]).then(function (value) { + // return value; + //}); + }); }; $scope.move = function () { $scope.moveDialog = {}; - $scope.moveDialog.title = "Move"; + $scope.moveDialog.title = localizationService.localize("general_move"); $scope.moveDialog.section = $scope.entityType; $scope.moveDialog.currentNode = $scope.contentId; $scope.moveDialog.view = "move"; @@ -416,13 +457,25 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie applySelected( function (selected, index) { return contentResource.move({ parentId: target.id, id: getIdCallback(selected[index]) }); }, - function (count, total) { return "Moved " + count + " out of " + total + " item" + (total > 1 ? "s" : ""); }, - function (total) { return "Moved " + total + " item" + (total > 1 ? "s" : ""); }); + function (count, total) { + return "Moved " + count + " out of " + total + " item" + (total > 1 ? "s" : ""); + //var key = (total === 1 ? "bulk_movedItemOfItem" : "bulk_movedItemOfItems"); + //localizationService.localize(key, [count, total]).then(function (value) { + // return value; + //}); + }, + function (total) { + return "Moved " + total + " item" + (total > 1 ? "s" : ""); + //var key = (total === 1 ? "bulk_movedItem" : "bulk_movedItems"); + //localizationService.localize(key, [total]).then(function (value) { + // return value; + //}); + }); } $scope.copy = function () { $scope.copyDialog = {}; - $scope.copyDialog.title = "Copy"; + $scope.copyDialog.title = localizationService.localize("general_copy"); $scope.copyDialog.section = $scope.entityType; $scope.copyDialog.currentNode = $scope.contentId; $scope.copyDialog.view = "copy"; @@ -447,8 +500,20 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie function performCopy(target, relateToOriginal) { applySelected( function (selected, index) { return contentResource.copy({ parentId: target.id, id: getIdCallback(selected[index]), relateToOriginal: relateToOriginal }); }, - function (count, total) { return "Copied " + count + " out of " + total + " item" + (total > 1 ? "s" : ""); }, - function (total) { return "Copied " + total + " item" + (total > 1 ? "s" : ""); }); + function (count, total) { + return "Copied " + count + " out of " + total + " item" + (total > 1 ? "s" : ""); + //var key = (total === 1 ? "bulk_copiedItemOfItem" : "bulk_copiedItemOfItems"); + //localizationService.localize(key, [count, total]).then(function (value) { + // return value; + //}); + }, + function (total) { + return "Copied " + total + " item" + (total > 1 ? "s" : ""); + //var key = (total === 1 ? "bulk_copiedItem" : "bulk_copiedItems"); + //localizationService.localize(key, [total]).then(function (value) { + // return value; + //}); + }); } function getCustomPropertyValue(alias, properties) { diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/cs.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/cs.xml index 1ae28daafe..50d5c0d911 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/cs.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/cs.xml @@ -185,6 +185,34 @@ You have unsaved changes Are you sure you want to navigate away from this page? - you have unsaved changes + + Done + + Deleted %0% item + Deleted %0% items + Deleted %0% out of %1% item + Deleted %0% out of %1% items + + Published %0% item + Published %0% items + Published %0% out of %1% item + Published %0% out of %1% items + + Unpublished %0% item + Unpublished %0% items + Unpublished %0% out of %1% item + Unpublished %0% out of %1% items + + Moved %0% item + Moved %0% items + Moved %0% out of %1% item + Moved %0% out of %1% items + + Copied %0% item + Copied %0% items + Copied %0% out of %1% item + Copied %0% out of %1% items + Název Spravovat názvy hostitelů diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml index 275267e98c..f3701c706a 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml @@ -191,6 +191,34 @@ Discard changes You have unsaved changes Are you sure you want to navigate away from this page? - you have unsaved changes + + + Done + + Deleted %0% item + Deleted %0% items + Deleted %0% out of %1% item + Deleted %0% out of %1% items + + Published %0% item + Published %0% items + Published %0% out of %1% item + Published %0% out of %1% items + + Unpublished %0% item + Unpublished %0% items + Unpublished %0% out of %1% item + Unpublished %0% out of %1% items + + Moved %0% item + Moved %0% items + Moved %0% out of %1% item + Moved %0% out of %1% items + + Copied %0% item + Copied %0% items + Copied %0% out of %1% item + Copied %0% out of %1% items Navn på lokal link diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml index 0280a46e05..d68e21daf7 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml @@ -198,6 +198,34 @@ Du har ikke-gemte ændringer Er du sikker på du vil navigere væk fra denne side? - du har ikke-gemte ændringer + + Færdig + + Slettede %0% element + Slettede %0% elementer + Slettede %0% ud af %1% element + Slettede %0% ud af %1% elementer + + Udgav %0% element + Udgav %0% elementer + Udgav %0% ud af %1% element + Udgav %0% ud af %1% elementer + + Fjernede %0% element fra udgivelse + Fjernede %0% elementer fra udgivelse + Fjernede %0% ud af %1% element fra udgivelse + Fjernede %0% ud af %1% elementer fra udgivelse + + Flyttede %0% element + Flyttede %0% elementer + Flyttede %0% ud af %1% element + Flyttede %0% ud af %1% elementer + + Kopierede %0% element + Kopierede %0% elementer + Kopierede %0% ud af %1% element + Kopierede %0% ud af %1% elementer + Navn på lokalt link Rediger domæner @@ -242,7 +270,36 @@ Vælg et placeholder id fra listen herunder. Du kan kun vælge id'er fra den nuværende masterskabelon.]]> Klik på billedet for at se den fulde størrelse Vælg - Se Cache Item + Se cache element + Opret mappe... + + Relatér til original + + Link til side + + Åbner det linket dokument i et nyt vindue eller fane + Åbner det linket dokument i fuld visning af vinduet + Åbner det linket dokument i "parent frame" + + Link til medie + + Vælg medie + Vælg ikon + Vælg item + Vælg link + Vælg makro + Vælg indhold + Vælg medlem + Vælg medlemsgruppe + + Der er ingen parametre for denne makro + + Link dit + Fjern link fra dit + + konto + + Vælg editor Rediger de forskellige sprogversioner for ordbogselementet '%0%' herunder. Du tilføjer flere sprog under 'sprog' i menuen til venstre diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/de.xml b/src/Umbraco.Web.UI/umbraco/config/lang/de.xml index 3b4c1ee5ab..d7f2c320b9 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/de.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/de.xml @@ -192,6 +192,34 @@ You have unsaved changes Are you sure you want to navigate away from this page? - you have unsaved changes + + Done + + Deleted %0% item + Deleted %0% items + Deleted %0% out of %1% item + Deleted %0% out of %1% items + + Published %0% item + Published %0% items + Published %0% out of %1% item + Published %0% out of %1% items + + Unpublished %0% item + Unpublished %0% items + Unpublished %0% out of %1% item + Unpublished %0% out of %1% items + + Moved %0% item + Moved %0% items + Moved %0% out of %1% item + Moved %0% out of %1% items + + Copied %0% item + Copied %0% items + Copied %0% out of %1% item + Copied %0% out of %1% items + Name Hostnamen verwalten diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml index 84dedbb364..2353929a4c 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en.xml @@ -205,6 +205,34 @@ You have unsaved changes Are you sure you want to navigate away from this page? - you have unsaved changes + + Done + + Deleted %0% item + Deleted %0% items + Deleted %0% out of %1% item + Deleted %0% out of %1% items + + Published %0% item + Published %0% items + Published %0% out of %1% item + Published %0% out of %1% items + + Unpublished %0% item + Unpublished %0% items + Unpublished %0% out of %1% item + Unpublished %0% out of %1% items + + Moved %0% item + Moved %0% items + Moved %0% out of %1% item + Moved %0% out of %1% items + + Copied %0% item + Copied %0% items + Copied %0% out of %1% item + Copied %0% out of %1% items + Name Manage hostnames 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 ec41299b25..528830d86a 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/en_us.xml @@ -207,6 +207,34 @@ You have unsaved changes Are you sure you want to navigate away from this page? - you have unsaved changes + + Done + + Deleted %0% item + Deleted %0% items + Deleted %0% out of %1% item + Deleted %0% out of %1% items + + Published %0% item + Published %0% items + Published %0% out of %1% item + Published %0% out of %1% items + + Unpublished %0% item + Unpublished %0% items + Unpublished %0% out of %1% item + Unpublished %0% out of %1% items + + Moved %0% item + Moved %0% items + Moved %0% out of %1% item + Moved %0% out of %1% items + + Copied %0% item + Copied %0% items + Copied %0% out of %1% item + Copied %0% out of %1% items + Name Manage hostnames diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/es.xml b/src/Umbraco.Web.UI/umbraco/config/lang/es.xml index 80e39fe219..09af60593f 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/es.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/es.xml @@ -191,6 +191,34 @@ You have unsaved changes Are you sure you want to navigate away from this page? - you have unsaved changes + + Done + + Deleted %0% item + Deleted %0% items + Deleted %0% out of %1% item + Deleted %0% out of %1% items + + Published %0% item + Published %0% items + Published %0% out of %1% item + Published %0% out of %1% items + + Unpublished %0% item + Unpublished %0% items + Unpublished %0% out of %1% item + Unpublished %0% out of %1% items + + Moved %0% item + Moved %0% items + Moved %0% out of %1% item + Moved %0% out of %1% items + + Copied %0% item + Copied %0% items + Copied %0% out of %1% item + Copied %0% out of %1% items + Nombre Administrar dominios diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/fr.xml b/src/Umbraco.Web.UI/umbraco/config/lang/fr.xml index 59021956a5..4affcf02f0 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/fr.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/fr.xml @@ -187,6 +187,34 @@ You have unsaved changes Are you sure you want to navigate away from this page? - you have unsaved changes + + Done + + Deleted %0% item + Deleted %0% items + Deleted %0% out of %1% item + Deleted %0% out of %1% items + + Published %0% item + Published %0% items + Published %0% out of %1% item + Published %0% out of %1% items + + Unpublished %0% item + Unpublished %0% items + Unpublished %0% out of %1% item + Unpublished %0% out of %1% items + + Moved %0% item + Moved %0% items + Moved %0% out of %1% item + Moved %0% out of %1% items + + Copied %0% item + Copied %0% items + Copied %0% out of %1% item + Copied %0% out of %1% items + Name Gérer les noms d'hôtes diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/he.xml b/src/Umbraco.Web.UI/umbraco/config/lang/he.xml index aa9c2112e2..02d8311c14 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/he.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/he.xml @@ -137,6 +137,34 @@ You have unsaved changes Are you sure you want to navigate away from this page? - you have unsaved changes + + Done + + Deleted %0% item + Deleted %0% items + Deleted %0% out of %1% item + Deleted %0% out of %1% items + + Published %0% item + Published %0% items + Published %0% out of %1% item + Published %0% out of %1% items + + Unpublished %0% item + Unpublished %0% items + Unpublished %0% out of %1% item + Unpublished %0% out of %1% items + + Moved %0% item + Moved %0% items + Moved %0% out of %1% item + Moved %0% out of %1% items + + Copied %0% item + Copied %0% items + Copied %0% out of %1% item + Copied %0% out of %1% items + שם ניהול שם מתחם diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/it.xml b/src/Umbraco.Web.UI/umbraco/config/lang/it.xml index 9c0682eba0..8be7261a8d 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/it.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/it.xml @@ -133,6 +133,34 @@ You have unsaved changes Are you sure you want to navigate away from this page? - you have unsaved changes + + Done + + Deleted %0% item + Deleted %0% items + Deleted %0% out of %1% item + Deleted %0% out of %1% items + + Published %0% item + Published %0% items + Published %0% out of %1% item + Published %0% out of %1% items + + Unpublished %0% item + Unpublished %0% items + Unpublished %0% out of %1% item + Unpublished %0% out of %1% items + + Moved %0% item + Moved %0% items + Moved %0% out of %1% item + Moved %0% out of %1% items + + Copied %0% item + Copied %0% items + Copied %0% out of %1% item + Copied %0% out of %1% items + Nome Gestione alias Hostnames diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/ja.xml b/src/Umbraco.Web.UI/umbraco/config/lang/ja.xml index 6acfd997e1..beced6eb79 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/ja.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/ja.xml @@ -200,6 +200,34 @@ You have unsaved changes Are you sure you want to navigate away from this page? - you have unsaved changes + + Done + + Deleted %0% item + Deleted %0% items + Deleted %0% out of %1% item + Deleted %0% out of %1% items + + Published %0% item + Published %0% items + Published %0% out of %1% item + Published %0% out of %1% items + + Unpublished %0% item + Unpublished %0% items + Unpublished %0% out of %1% item + Unpublished %0% out of %1% items + + Moved %0% item + Moved %0% items + Moved %0% out of %1% item + Moved %0% out of %1% items + + Copied %0% item + Copied %0% items + Copied %0% out of %1% item + Copied %0% out of %1% items + 名前 ドメインの割り当て diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/ko.xml b/src/Umbraco.Web.UI/umbraco/config/lang/ko.xml index c7178e312b..b72503e987 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/ko.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/ko.xml @@ -131,6 +131,34 @@ You have unsaved changes Are you sure you want to navigate away from this page? - you have unsaved changes + + Done + + Deleted %0% item + Deleted %0% items + Deleted %0% out of %1% item + Deleted %0% out of %1% items + + Published %0% item + Published %0% items + Published %0% out of %1% item + Published %0% out of %1% items + + Unpublished %0% item + Unpublished %0% items + Unpublished %0% out of %1% item + Unpublished %0% out of %1% items + + Moved %0% item + Moved %0% items + Moved %0% out of %1% item + Moved %0% out of %1% items + + Copied %0% item + Copied %0% items + Copied %0% out of %1% item + Copied %0% out of %1% items + 이름 호스트네임 관리 diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/nl.xml b/src/Umbraco.Web.UI/umbraco/config/lang/nl.xml index 7d1a4cc2d3..2955ce716a 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/nl.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/nl.xml @@ -194,6 +194,34 @@ You have unsaved changes Are you sure you want to navigate away from this page? - you have unsaved changes + + Done + + Deleted %0% item + Deleted %0% items + Deleted %0% out of %1% item + Deleted %0% out of %1% items + + Published %0% item + Published %0% items + Published %0% out of %1% item + Published %0% out of %1% items + + Unpublished %0% item + Unpublished %0% items + Unpublished %0% out of %1% item + Unpublished %0% out of %1% items + + Moved %0% item + Moved %0% items + Moved %0% out of %1% item + Moved %0% out of %1% items + + Copied %0% item + Copied %0% items + Copied %0% out of %1% item + Copied %0% out of %1% items + Naam Beheer domeinnamen diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/pl.xml b/src/Umbraco.Web.UI/umbraco/config/lang/pl.xml index c2c8b4d073..97dcf9ef38 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/pl.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/pl.xml @@ -131,6 +131,34 @@ You have unsaved changes Are you sure you want to navigate away from this page? - you have unsaved changes + + Done + + Deleted %0% item + Deleted %0% items + Deleted %0% out of %1% item + Deleted %0% out of %1% items + + Published %0% item + Published %0% items + Published %0% out of %1% item + Published %0% out of %1% items + + Unpublished %0% item + Unpublished %0% items + Unpublished %0% out of %1% item + Unpublished %0% out of %1% items + + Moved %0% item + Moved %0% items + Moved %0% out of %1% item + Moved %0% out of %1% items + + Copied %0% item + Copied %0% items + Copied %0% out of %1% item + Copied %0% out of %1% items + Nazwa Zarządzaj nazwami hostów diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/pt.xml b/src/Umbraco.Web.UI/umbraco/config/lang/pt.xml index 016f7c2a19..e67a4c4b15 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/pt.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/pt.xml @@ -131,6 +131,34 @@ You have unsaved changes Are you sure you want to navigate away from this page? - you have unsaved changes + + Done + + Deleted %0% item + Deleted %0% items + Deleted %0% out of %1% item + Deleted %0% out of %1% items + + Published %0% item + Published %0% items + Published %0% out of %1% item + Published %0% out of %1% items + + Unpublished %0% item + Unpublished %0% items + Unpublished %0% out of %1% item + Unpublished %0% out of %1% items + + Moved %0% item + Moved %0% items + Moved %0% out of %1% item + Moved %0% out of %1% items + + Copied %0% item + Copied %0% items + Copied %0% out of %1% item + Copied %0% out of %1% items + Nome Gerenciar hostnames diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml b/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml index e162dbaead..84b87b872f 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/ru.xml @@ -260,6 +260,34 @@ You have unsaved changes Are you sure you want to navigate away from this page? - you have unsaved changes + + Done + + Deleted %0% item + Deleted %0% items + Deleted %0% out of %1% item + Deleted %0% out of %1% items + + Published %0% item + Published %0% items + Published %0% out of %1% item + Published %0% out of %1% items + + Unpublished %0% item + Unpublished %0% items + Unpublished %0% out of %1% item + Unpublished %0% out of %1% items + + Moved %0% item + Moved %0% items + Moved %0% out of %1% item + Moved %0% out of %1% items + + Copied %0% item + Copied %0% items + Copied %0% out of %1% item + Copied %0% out of %1% items + Название Управление доменами diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/sv.xml b/src/Umbraco.Web.UI/umbraco/config/lang/sv.xml index ea1f0c9ef0..10e882f260 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/sv.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/sv.xml @@ -187,6 +187,34 @@ You have unsaved changes Are you sure you want to navigate away from this page? - you have unsaved changes + + Done + + Deleted %0% item + Deleted %0% items + Deleted %0% out of %1% item + Deleted %0% out of %1% items + + Published %0% item + Published %0% items + Published %0% out of %1% item + Published %0% out of %1% items + + Unpublished %0% item + Unpublished %0% items + Unpublished %0% out of %1% item + Unpublished %0% out of %1% items + + Moved %0% item + Moved %0% items + Moved %0% out of %1% item + Moved %0% out of %1% items + + Copied %0% item + Copied %0% items + Copied %0% out of %1% item + Copied %0% out of %1% items + Namn Hantera domännamn diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/zh.xml b/src/Umbraco.Web.UI/umbraco/config/lang/zh.xml index 372bc480cc..b8c933c101 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/zh.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/zh.xml @@ -171,6 +171,34 @@ Discard changes You have unsaved changes Are you sure you want to navigate away from this page? - you have unsaved changes + + + Done + + Deleted %0% item + Deleted %0% items + Deleted %0% out of %1% item + Deleted %0% out of %1% items + + Published %0% item + Published %0% items + Published %0% out of %1% item + Published %0% out of %1% items + + Unpublished %0% item + Unpublished %0% items + Unpublished %0% out of %1% item + Unpublished %0% out of %1% items + + Moved %0% item + Moved %0% items + Moved %0% out of %1% item + Moved %0% out of %1% items + + Copied %0% item + Copied %0% items + Copied %0% out of %1% item + Copied %0% out of %1% items 锚点名称 From e2aee08959874ed1647caf3585e321d86a2b7b64 Mon Sep 17 00:00:00 2001 From: bjarnef Date: Sun, 22 May 2016 13:52:02 +0200 Subject: [PATCH 056/535] Change back to original timeout value. --- .../src/views/propertyeditors/listview/listview.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js index 2ea325b451..5f3810723a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js @@ -208,7 +208,7 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie $timeout(function () { $scope.bulkStatus = ""; $scope.actionInProgress = false; - }, 0); + }, 500); if (reload === true) { $scope.reloadView($scope.contentId); From e39f818389d306852755336c3f42d5ed2f19449a Mon Sep 17 00:00:00 2001 From: bjarnef Date: Sun, 22 May 2016 13:53:43 +0200 Subject: [PATCH 057/535] Fix indent --- src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml b/src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml index f3701c706a..602f66ddf4 100644 --- a/src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml +++ b/src/Umbraco.Web.UI/Umbraco/config/lang/nb.xml @@ -192,7 +192,7 @@ You have unsaved changes Are you sure you want to navigate away from this page? - you have unsaved changes - + Done Deleted %0% item From 45ff11b884573c2925cb246c2d4ad37fdd543a2a Mon Sep 17 00:00:00 2001 From: bjarnef Date: Sun, 22 May 2016 14:26:37 +0200 Subject: [PATCH 058/535] Change "siten" to "sitet" --- src/Umbraco.Web.UI/umbraco/config/lang/da.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml index d68e21daf7..4cb2794976 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml @@ -28,7 +28,7 @@ Udgiv Fortryd udgivelse Genindlæs elementer - Genudgiv hele siten + Genudgiv hele sitet Gendan Rettigheder Fortryd ændringer @@ -262,7 +262,7 @@ Fjern makro Obligatorisk Sitet er genindekseret - Siten er nu genudgivet + Sitet er nu genudgivet Websitets cache vil blive genopfrisket. Alt udgivet indhold vil blive opdateret, mens upubliceret indhold vil forblive upubliceret. Antal kolonner Antal rækker From 06077820287171923ed3ab46befa6b66692d44d5 Mon Sep 17 00:00:00 2001 From: bjarnef Date: Sun, 22 May 2016 21:08:21 +0200 Subject: [PATCH 059/535] Added localization for the new password reset stuff. --- src/Umbraco.Web.UI/umbraco/config/lang/da.xml | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml index 4cb2794976..33e9e4a4d2 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml @@ -429,7 +429,7 @@ Layout Henter Låst - Login + Log ind Log af Log ud Makro @@ -606,7 +606,6 @@ Forny for at gemme dine ændringer - Så er det søndag! Smil, det er mandag! Hurra, det er tirsdag! @@ -614,13 +613,21 @@ Glædelig torsdag! Endelig fredag! Glædelig lørdag - - + Log ind nedenfor indtast brugernavn og kodeord Din session er udløbet - - © 2001 - %0%
    umbraco.com

    ]]>
    + Glemt adgangskode? + En e-mail vil blive sendt til den angivne adresse med et link til at nulstille din adgangskode + En e-mail med instruktioner for nulstilling af adgangskoden vil blive sendt til den angivne adresse, hvis det matcher vores optegnelser + Tilbage til login formular + Angiv en ny adgangskode + Din adgangskode er blevet opdateret + Det link, du har klikket på, er ugyldigt eller udløbet + Umbraco: Nulstil adgangskode + + Dit brugernavn til at logge på Umbraco backoffice er: %0%

    Klik her for at nulstille din adgangskode eller kopier/indsæt denne URL i din browser:

    %1%

    ]]> +
    Skrivebord @@ -637,7 +644,7 @@ Intet element valgt, vælg et element i listen ovenfor før der klikkes 'fortsæt' Det nuværende element kan ikke lægges under denne pga. sin type Det nuværende element kan ikke ligge under en af dens undersider - Dette element må ikke findes på rodniveau + Dette element må ikke findes på rodniveau Denne handling er ikke tilladt fordi du ikke har de fornødne rettigheder på et eller flere af under-dokumenterne Relater det kopierede element til originalen From 695c69af7fbbbe49f51611ab90b136cc272567a2 Mon Sep 17 00:00:00 2001 From: bjarnef Date: Sun, 22 May 2016 21:11:51 +0200 Subject: [PATCH 060/535] Updated indent --- src/Umbraco.Web.UI/umbraco/config/lang/da.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml index 33e9e4a4d2..d4b70939ae 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml @@ -644,9 +644,9 @@ Intet element valgt, vælg et element i listen ovenfor før der klikkes 'fortsæt' Det nuværende element kan ikke lægges under denne pga. sin type Det nuværende element kan ikke ligge under en af dens undersider - Dette element må ikke findes på rodniveau + Dette element må ikke findes på rodniveau Denne handling er ikke tilladt fordi du ikke har de fornødne rettigheder på et eller flere af under-dokumenterne - Relater det kopierede element til originalen + Relater det kopierede element til originalen Rediger dine notificeringer for %0% From 43d791f9a5549bf3a8b30800cee515386785d8c0 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 23 May 2016 08:27:30 +0200 Subject: [PATCH 061/535] U4-6504 SmtpClient Not Properly Disposed, Causing Emails to Fail Periodically --- .../umbraco.presentation/library.cs | 38 ++++---- .../businesslogic/translation/Translation.cs | 86 ++++++++++--------- 2 files changed, 61 insertions(+), 63 deletions(-) diff --git a/src/Umbraco.Web/umbraco.presentation/library.cs b/src/Umbraco.Web/umbraco.presentation/library.cs index d9b1d520ed..5047aef271 100644 --- a/src/Umbraco.Web/umbraco.presentation/library.cs +++ b/src/Umbraco.Web/umbraco.presentation/library.cs @@ -1575,30 +1575,26 @@ namespace umbraco /// /// Sends an e-mail using the System.Net.Mail.MailMessage object /// - /// The sender of the e-mail - /// The recipient of the e-mail - /// E-mail subject - /// The complete content of the e-mail - /// Set to true when using Html formatted mails - public static void SendMail(string FromMail, string ToMail, string Subject, string Body, bool IsHtml) + /// The sender of the e-mail + /// The recipient(s) of the e-mail, add multiple email addresses by using a semicolon between them + /// E-mail subject + /// The complete content of the e-mail + /// Set to true when using Html formatted mails + public static void SendMail(string fromMail, string toMail, string subject, string body, bool isHtml) { try { - // create the mail message - MailMessage mail = new MailMessage(FromMail.Trim(), ToMail.Trim()); - - // populate the message - mail.Subject = Subject; - if (IsHtml) - mail.IsBodyHtml = true; - else - mail.IsBodyHtml = false; - - mail.Body = Body; - - // send it - SmtpClient smtpClient = new SmtpClient(); - smtpClient.Send(mail); + using (var mail = new MailMessage()) + { + mail.From = new MailAddress(fromMail.Trim()); + foreach (var mailAddress in toMail.Split(';')) + mail.To.Add(new MailAddress(mailAddress.Trim())); + mail.Subject = subject; + mail.IsBodyHtml = isHtml; + mail.Body = body; + using (var smtpClient = new SmtpClient()) + smtpClient.Send(mail); + } } catch (Exception ee) { diff --git a/src/umbraco.cms/businesslogic/translation/Translation.cs b/src/umbraco.cms/businesslogic/translation/Translation.cs index 7edbfefadd..deb4c32766 100644 --- a/src/umbraco.cms/businesslogic/translation/Translation.cs +++ b/src/umbraco.cms/businesslogic/translation/Translation.cs @@ -16,78 +16,80 @@ namespace umbraco.cms.businesslogic.translation [Obsolete("This will be removed in future versions, the translation utility will not work perfectly in v7.x")] public class Translation { - public static void MakeNew(CMSNode Node, User User, User Translator, Language Language, string Comment, - bool IncludeSubpages, bool SendEmail) + public static void MakeNew(CMSNode node, User user, User translator, Language language, string comment, bool includeSubpages, bool sendEmail) { // Get translation taskType for obsolete task constructor var taskType = ApplicationContext.Current.Services.TaskService.GetTaskTypeByAlias("toTranslate"); // Create pending task - Task t = new Task(new Umbraco.Core.Models.Task(taskType)); - t.Comment = Comment; - t.Node = Node; - t.ParentUser = User; - t.User = Translator; - t.Save(); + var task = new Task(new Umbraco.Core.Models.Task(taskType)) + { + Comment = comment, + Node = node, + ParentUser = user, + User = translator + }; + task.Save(); // Add log entry - Log.Add(LogTypes.SendToTranslate, User, Node.Id, - "Translator: " + Translator.Name + ", Language: " + Language.FriendlyName); + // Note: not updated to LogHelper as LogTypes.SendToTranslate might be something special, not sure + Log.Add(LogTypes.SendToTranslate, user, node.Id, "Translator: " + translator.Name + ", Language: " + language.FriendlyName); // send it - if (SendEmail) + if (sendEmail) { - string serverName = HttpContext.Current.Request.ServerVariables["SERVER_NAME"]; - int port = HttpContext.Current.Request.Url.Port; + var serverName = HttpContext.Current.Request.ServerVariables["SERVER_NAME"]; + var port = HttpContext.Current.Request.Url.Port; - if(port != 80) - serverName += ":" + port.ToString(); + if (port != 80) + serverName += ":" + port; serverName += IOHelper.ResolveUrl(SystemDirectories.Umbraco); // Send mail - string[] subjectVars = {serverName, Node.Text}; - string[] bodyVars = { - Translator.Name, Node.Text, User.Name, - serverName, t.Id.ToString(), - Language.FriendlyName + var subjectVars = new[] { serverName, node.Text }; + var bodyVars = new[] { + translator.Name, node.Text, user.Name, + serverName, task.Id.ToString(), + language.FriendlyName }; - if (User.Email != "" && User.Email.Contains("@") && Translator.Email != "" && - Translator.Email.Contains("@")) + if (string.IsNullOrWhiteSpace(user.Email) == false && user.Email.Contains("@") + && string.IsNullOrWhiteSpace(translator.Email) == false && translator.Email.Contains("@")) { - // create the mail message - MailMessage mail = new MailMessage(User.Email, Translator.Email); - - // populate the message - mail.Subject = ui.Text("translation", "mailSubject", subjectVars, Translator); - mail.IsBodyHtml = false; - mail.Body = ui.Text("translation", "mailBody", bodyVars, Translator); try { - SmtpClient sender = new SmtpClient(); - sender.Send(mail); + using (var mail = new MailMessage()) + { + mail.From = new MailAddress(user.Email.Trim()); + mail.To.Add(new MailAddress(translator.Email.Trim()); + mail.Subject = ui.Text("translation", "mailSubject", subjectVars, translator); ; + mail.IsBodyHtml = false; + mail.Body = ui.Text("translation", "mailBody", bodyVars, translator); ; + using (var smtpClient = new SmtpClient()) + smtpClient.Send(mail); + } } catch (Exception ex) { - LogHelper.Error("Error sending translation e-mail", ex); + LogHelper.Error("Error sending translation e-mail", ex); } } else { - LogHelper.Warn("Could not send translation e-mail because either user or translator lacks e-mail in settings"); + LogHelper.Warn("Could not send translation e-mail because either user or translator lacks e-mail in settings"); } - } - if (IncludeSubpages) + if (includeSubpages == false) + return; + + //store children array here because iterating over an Array property object is very inneficient. + var children = node.Children; + foreach (var child in children) { - //store children array here because iterating over an Array property object is very inneficient. - var c = Node.Children; - foreach (CMSNode n in c) - { - MakeNew(n, User, Translator, Language, Comment, true, false); - } + var cmsNode = (CMSNode) child; + MakeNew(cmsNode, user, translator, language, comment, true, false); } } @@ -123,7 +125,7 @@ namespace umbraco.cms.businesslogic.translation tmpStr = tmpStr.Replace("\r", " "); MatchCollection collection = Regex.Matches(tmpStr, @"[\S]+"); - return collection.Count; + return collection.Count; } } } \ No newline at end of file From 57b19e70173fd04716c8f562cb7205144f5e2ba6 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 23 May 2016 08:47:36 +0200 Subject: [PATCH 062/535] Forgot semicolon, whoops! --- src/umbraco.cms/businesslogic/translation/Translation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/umbraco.cms/businesslogic/translation/Translation.cs b/src/umbraco.cms/businesslogic/translation/Translation.cs index deb4c32766..1cddf4e8e9 100644 --- a/src/umbraco.cms/businesslogic/translation/Translation.cs +++ b/src/umbraco.cms/businesslogic/translation/Translation.cs @@ -62,7 +62,7 @@ namespace umbraco.cms.businesslogic.translation using (var mail = new MailMessage()) { mail.From = new MailAddress(user.Email.Trim()); - mail.To.Add(new MailAddress(translator.Email.Trim()); + mail.To.Add(new MailAddress(translator.Email.Trim())); mail.Subject = ui.Text("translation", "mailSubject", subjectVars, translator); ; mail.IsBodyHtml = false; mail.Body = ui.Text("translation", "mailBody", bodyVars, translator); ; From bbe37ea6b9e6b17272eacf9900d14873d781e691 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 23 May 2016 08:55:51 +0200 Subject: [PATCH 063/535] U4-8349 Cannot create Scripting Files in Umbraco 7.4.0 --- .../umbraco/developer/Python/editPython.aspx.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Python/editPython.aspx.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Python/editPython.aspx.cs index e6090fe676..563fb02055 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Python/editPython.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/developer/Python/editPython.aspx.cs @@ -46,7 +46,7 @@ namespace umbraco.cms.presentation.developer string file = Request.QueryString["file"]; string path = DeepLink.GetTreePathFromFilePath(file); ClientTools - .SetActiveTreeType(TreeDefinitionCollection.Instance.FindTree().Tree.Alias) + .SetActiveTreeType(TreeDefinitionCollection.Instance.FindTree().Tree.Alias) .SyncTree(path, false); } } From c902649768c9f3f19f87751dd1fcc85bccc6eeca Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 23 May 2016 10:47:54 +0200 Subject: [PATCH 064/535] U4-8438 Umbraco 7.4.3 NuGet package missing file --- build/NuSpecs/tools/install.ps1 | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/build/NuSpecs/tools/install.ps1 b/build/NuSpecs/tools/install.ps1 index de7a6cc16e..5ebaa6d02a 100644 --- a/build/NuSpecs/tools/install.ps1 +++ b/build/NuSpecs/tools/install.ps1 @@ -77,8 +77,28 @@ if ($project) { { $packageWebConfigSource = Join-Path $installPath "UmbracoFiles\Web.config" Copy-Item $packageWebConfigSource $destinationWebConfig -Force - } + # Copy files that don't get automatically copied for Website projects + # We do this here, when copyWebconfig is true because we only want to do it for new installs + # If this is an upgrade then the files should already be there + $splashesSource = Join-Path $installPath "UmbracoFiles\Config\splashes\*.*" + $splashesDestination = Join-Path $projectPath "Config\splashes\" + New-Item $splashesDestination -Type directory + Copy-Item $splashesSource $splashesDestination -Force + + $sqlCe64Source = Join-Path $installPath "UmbracoFiles\bin\amd64\*" + $sqlCe64Destination = Join-Path $projectPath "bin\amd64\" + Copy-Item $sqlCe64Source $sqlCe64Destination -Force + + $sqlCex86Source = Join-Path $installPath "UmbracoFiles\bin\x86\*" + $sqlCex86Destination = Join-Path $projectPath "bin\x86\" + Copy-Item $sqlCex86source $sqlCex86Destination -Force + + $umbracoUIXMLSource = Join-Path $installPath "UmbracoFiles\Umbraco\Config\Create\UI.xml" + $umbracoUIXMLDestination = Join-Path $projectPath "Umbraco\Config\Create\UI.xml" + Copy-Item $umbracoUIXMLSource $umbracoUIXMLDestination -Force + } + $installFolder = Join-Path $projectPath "Install" if(Test-Path $installFolder) { Remove-Item $installFolder -Force -Recurse -Confirm:$false From 9cf5ac2f95771eab8b5b261d4895577c311ef733 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 23 May 2016 17:44:45 +0200 Subject: [PATCH 065/535] U4-8491 Moving/Deleting Media does not sync/refresh the tree --- .../listview/listview.controller.js | 38 ++++++++++++++++--- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js index 518c27d110..3911ef7338 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js @@ -1,4 +1,4 @@ -function listViewController($rootScope, $scope, $routeParams, $injector, $cookieStore, notificationsService, iconHelper, dialogService, editorState, localizationService, $location, appState, $timeout, $q, mediaResource, listViewHelper, userService) { +function listViewController($rootScope, $scope, $routeParams, $injector, $cookieStore, notificationsService, iconHelper, dialogService, editorState, localizationService, $location, appState, $timeout, $q, mediaResource, listViewHelper, userService, navigationService, treeService) { //this is a quick check to see if we're in create mode, if so just exit - we cannot show children for content // that isn't created yet, if we continue this will use the parent id in the route params which isn't what @@ -357,7 +357,7 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie $scope.actionInProgress = true; $scope.bulkStatus = getStatusMsg(0, selected.length); - serial(selected, fn, getStatusMsg, 0).then(function (result) { + return serial(selected, fn, getStatusMsg, 0).then(function (result) { // executes once the whole selection has been processed // in case of an error (caught by serial), result will be the error if (!(result.data && angular.isArray(result.data.notifications))) @@ -414,10 +414,36 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie function performMove(target) { - applySelected( - function (selected, index) { return contentResource.move({ parentId: target.id, id: getIdCallback(selected[index]) }); }, - function (count, total) { return "Moved " + count + " out of " + total + " item" + (total > 1 ? "s" : ""); }, - function (total) { return "Moved " + total + " item" + (total > 1 ? "s" : ""); }); + //NOTE: With the way this applySelected/serial works, I'm not sure there's a better way currently to return + // a specific value from one of the methods, so we'll have to try this way. Even though the first method + // will fire once per every node moved, the destination path will be the same and we need to use that to sync. + var newPath = null; + applySelected( + function(selected, index) { + return contentResource.move({ parentId: target.id, id: getIdCallback(selected[index]) }).then(function(path) { + newPath = path; + return path; + }); + }, + function(count, total) { + return "Moved " + count + " out of " + total + " item" + (total > 1 ? "s" : ""); + }, + function(total) { return "Moved " + total + " item" + (total > 1 ? "s" : ""); }) + .then(function() { + //executes if all is successful, let's sync the tree + if (newPath) { + + //we need to do a double sync here: first refresh the node where the content was moved, + // then refresh the node where the content was moved from + navigationService.syncTree({ tree: target.nodeType, path: newPath, forceReload: true, activate: false }).then(function (args) { + //get the currently edited node (if any) + var activeNode = appState.getTreeState("selectedNode"); + if (activeNode) { + navigationService.reloadNode(activeNode); + } + }); + } + }); } $scope.copy = function () { From 877b7d4af7147b0aef4a81eac7b602bf93b3d246 Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 23 May 2016 19:23:59 +0200 Subject: [PATCH 066/535] U4-8358 Writers can't schedule publish/unpublish times --- src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs index ede1dfc78d..efc9b7ced6 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs @@ -179,7 +179,7 @@ namespace Umbraco.Web.Models.Mapping Label = localizedText.Localize("content/releaseDate"), Value = display.ReleaseDate.HasValue ? display.ReleaseDate.Value.ToIsoString() : null, //Not editible for people without publish permission (U4-287) - View = display.AllowedActions.Contains('P') ? "datepicker" : PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View + View = display.AllowedActions.Contains(ActionPublish.Instance.Letter) ? "datepicker" : PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View //TODO: Fix up hard coded datepicker } , new ContentPropertyDisplay @@ -188,7 +188,7 @@ namespace Umbraco.Web.Models.Mapping Label = localizedText.Localize("content/unpublishDate"), Value = display.ExpireDate.HasValue ? display.ExpireDate.Value.ToIsoString() : null, //Not editible for people without publish permission (U4-287) - View = display.AllowedActions.Contains('P') ? "datepicker" : PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View + View = display.AllowedActions.Contains(ActionPublish.Instance.Letter) ? "datepicker" : PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View //TODO: Fix up hard coded datepicker }, new ContentPropertyDisplay From 3ea01b7dabbd6c51d8a7320313c674eb4f2befa9 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 24 May 2016 15:04:46 +0200 Subject: [PATCH 067/535] U4-8445 Validation on the Email field for Members will not allow the entry of root domains greater than four characters. --- .../validation/nodirtycheck.directive.js | 0 .../umbsetdirtyonchange.directive.js | 0 .../validation/valCustom.directive.js | 0 .../validation/valHighlight.directive.js | 56 +-- .../validation/valcompare.directive.js | 46 +-- .../validation/valemail.directive.js | 9 +- .../validation/valformmanager.directive.js | 264 ++++++------ .../validation/valpropertymsg.directive.js | 390 +++++++++--------- .../valpropertyvalidator.directive.js | 0 .../validation/valregex.directive.js | 156 +++---- .../validation/valserver.directive.js | 186 ++++----- .../validation/valserverfield.directive.js | 130 +++--- .../validation/valtab.directive.js | 74 ++-- .../validation/valtogglemsg.directive.js | 178 ++++---- .../validation/valtriggerchange.directive.js | 0 15 files changed, 748 insertions(+), 741 deletions(-) rename src/Umbraco.Web.UI.Client/src/common/directives/{components => }/validation/nodirtycheck.directive.js (100%) rename src/Umbraco.Web.UI.Client/src/common/directives/{components => }/validation/umbsetdirtyonchange.directive.js (100%) rename src/Umbraco.Web.UI.Client/src/common/directives/{components => }/validation/valCustom.directive.js (100%) rename src/Umbraco.Web.UI.Client/src/common/directives/{components => }/validation/valHighlight.directive.js (97%) rename src/Umbraco.Web.UI.Client/src/common/directives/{components => }/validation/valcompare.directive.js (97%) rename src/Umbraco.Web.UI.Client/src/common/directives/{components => }/validation/valemail.directive.js (72%) rename src/Umbraco.Web.UI.Client/src/common/directives/{components => }/validation/valformmanager.directive.js (97%) rename src/Umbraco.Web.UI.Client/src/common/directives/{components => }/validation/valpropertymsg.directive.js (97%) rename src/Umbraco.Web.UI.Client/src/common/directives/{components => }/validation/valpropertyvalidator.directive.js (100%) rename src/Umbraco.Web.UI.Client/src/common/directives/{components => }/validation/valregex.directive.js (97%) rename src/Umbraco.Web.UI.Client/src/common/directives/{components => }/validation/valserver.directive.js (97%) rename src/Umbraco.Web.UI.Client/src/common/directives/{components => }/validation/valserverfield.directive.js (97%) rename src/Umbraco.Web.UI.Client/src/common/directives/{components => }/validation/valtab.directive.js (97%) rename src/Umbraco.Web.UI.Client/src/common/directives/{components => }/validation/valtogglemsg.directive.js (97%) rename src/Umbraco.Web.UI.Client/src/common/directives/{components => }/validation/valtriggerchange.directive.js (100%) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/validation/nodirtycheck.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/nodirtycheck.directive.js similarity index 100% rename from src/Umbraco.Web.UI.Client/src/common/directives/components/validation/nodirtycheck.directive.js rename to src/Umbraco.Web.UI.Client/src/common/directives/validation/nodirtycheck.directive.js diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/validation/umbsetdirtyonchange.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/umbsetdirtyonchange.directive.js similarity index 100% rename from src/Umbraco.Web.UI.Client/src/common/directives/components/validation/umbsetdirtyonchange.directive.js rename to src/Umbraco.Web.UI.Client/src/common/directives/validation/umbsetdirtyonchange.directive.js diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valCustom.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valCustom.directive.js similarity index 100% rename from src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valCustom.directive.js rename to src/Umbraco.Web.UI.Client/src/common/directives/validation/valCustom.directive.js diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valHighlight.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valHighlight.directive.js similarity index 97% rename from src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valHighlight.directive.js rename to src/Umbraco.Web.UI.Client/src/common/directives/validation/valHighlight.directive.js index 2afd75eb29..9182441f8b 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valHighlight.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valHighlight.directive.js @@ -1,28 +1,28 @@ -/** -* @ngdoc directive -* @name umbraco.directives.directive:valHighlight -* @restrict A -* @description Used on input fields when you want to signal that they are in error, this will highlight the item for 1 second -**/ -function valHighlight($timeout) { - return { - restrict: "A", - link: function (scope, element, attrs, ctrl) { - - attrs.$observe("valHighlight", function (newVal) { - if (newVal === "true") { - element.addClass("highlight-error"); - $timeout(function () { - //set the bound scope property to false - scope[attrs.valHighlight] = false; - }, 1000); - } - else { - element.removeClass("highlight-error"); - } - }); - - } - }; -} -angular.module('umbraco.directives.validation').directive("valHighlight", valHighlight); +/** +* @ngdoc directive +* @name umbraco.directives.directive:valHighlight +* @restrict A +* @description Used on input fields when you want to signal that they are in error, this will highlight the item for 1 second +**/ +function valHighlight($timeout) { + return { + restrict: "A", + link: function (scope, element, attrs, ctrl) { + + attrs.$observe("valHighlight", function (newVal) { + if (newVal === "true") { + element.addClass("highlight-error"); + $timeout(function () { + //set the bound scope property to false + scope[attrs.valHighlight] = false; + }, 1000); + } + else { + element.removeClass("highlight-error"); + } + }); + + } + }; +} +angular.module('umbraco.directives.validation').directive("valHighlight", valHighlight); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valcompare.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valcompare.directive.js similarity index 97% rename from src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valcompare.directive.js rename to src/Umbraco.Web.UI.Client/src/common/directives/validation/valcompare.directive.js index 31595273de..1a36dcc24f 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valcompare.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valcompare.directive.js @@ -1,24 +1,24 @@ -angular.module('umbraco.directives.validation') - .directive('valCompare',function () { - return { - require: "ngModel", - link: function (scope, elem, attrs, ctrl) { - - //TODO: Pretty sure this should be done using a requires ^form in the directive declaration - var otherInput = elem.inheritedData("$formController")[attrs.valCompare]; - - ctrl.$parsers.push(function(value) { - if(value === otherInput.$viewValue) { - ctrl.$setValidity("valCompare", true); - return value; - } - ctrl.$setValidity("valCompare", false); - }); - - otherInput.$parsers.push(function(value) { - ctrl.$setValidity("valCompare", value === ctrl.$viewValue); - return value; - }); - } - }; +angular.module('umbraco.directives.validation') + .directive('valCompare',function () { + return { + require: "ngModel", + link: function (scope, elem, attrs, ctrl) { + + //TODO: Pretty sure this should be done using a requires ^form in the directive declaration + var otherInput = elem.inheritedData("$formController")[attrs.valCompare]; + + ctrl.$parsers.push(function(value) { + if(value === otherInput.$viewValue) { + ctrl.$setValidity("valCompare", true); + return value; + } + ctrl.$setValidity("valCompare", false); + }); + + otherInput.$parsers.push(function(value) { + ctrl.$setValidity("valCompare", value === ctrl.$viewValue); + return value; + }); + } + }; }); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valemail.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valemail.directive.js similarity index 72% rename from src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valemail.directive.js rename to src/Umbraco.Web.UI.Client/src/common/directives/validation/valemail.directive.js index 1e81d8edec..ade3403ad7 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valemail.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valemail.directive.js @@ -29,6 +29,12 @@ function valEmail(valEmailExpression) { } }; + //we need to remove the existing parsers = the default angular one which is created by + // type="email", but this has a regex issue, so we'll remove that and add our custom one + ctrl.$parsers.pop(); + //we also need to remove the existing formatter - the default angular one will not render + // what it thinks is an invalid email address, so it will just be blank + ctrl.$formatters.pop(); ctrl.$parsers.push(patternValidator); } }; @@ -36,7 +42,8 @@ function valEmail(valEmailExpression) { angular.module('umbraco.directives.validation') .directive("valEmail", valEmail) - .factory('valEmailExpression', function() { + .factory('valEmailExpression', function () { + //NOTE: This is the fixed regex which is part of the newer angular return { EMAIL_REGEXP: /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i }; diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valformmanager.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valformmanager.directive.js similarity index 97% rename from src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valformmanager.directive.js rename to src/Umbraco.Web.UI.Client/src/common/directives/validation/valformmanager.directive.js index 37c0313c45..9a00d5718c 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valformmanager.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valformmanager.directive.js @@ -1,133 +1,133 @@ -/** -* @ngdoc directive -* @name umbraco.directives.directive:valFormManager -* @restrict A -* @require formController -* @description Used to broadcast an event to all elements inside this one to notify that form validation has -* changed. If we don't use this that means you have to put a watch for each directive on a form's validation -* changing which would result in much higher processing. We need to actually watch the whole $error collection of a form -* because just watching $valid or $invalid doesn't acurrately trigger form validation changing. -* This also sets the show-validation (or a custom) css class on the element when the form is invalid - this lets -* us css target elements to be displayed when the form is submitting/submitted. -* Another thing this directive does is to ensure that any .control-group that contains form elements that are invalid will -* be marked with the 'error' css class. This ensures that labels included in that control group are styled correctly. -**/ -function valFormManager(serverValidationManager, $rootScope, $log, $timeout, notificationsService, eventsService, $routeParams) { - return { - require: "form", - restrict: "A", - controller: function($scope) { - //This exposes an API for direct use with this directive - - var unsubscribe = []; - var self = this; - - //This is basically the same as a directive subscribing to an event but maybe a little - // nicer since the other directive can use this directive's API instead of a magical event - this.onValidationStatusChanged = function (cb) { - unsubscribe.push($scope.$on("valStatusChanged", function(evt, args) { - cb.apply(self, [evt, args]); - })); - }; - - //Ensure to remove the event handlers when this instance is destroyted - $scope.$on('$destroy', function () { - for (var u in unsubscribe) { - unsubscribe[u](); - } - }); - }, - link: function (scope, element, attr, formCtrl) { - - scope.$watch(function () { - return formCtrl.$error; - }, function (e) { - scope.$broadcast("valStatusChanged", { form: formCtrl }); - - //find all invalid elements' .control-group's and apply the error class - var inError = element.find(".control-group .ng-invalid").closest(".control-group"); - inError.addClass("error"); - - //find all control group's that have no error and ensure the class is removed - var noInError = element.find(".control-group .ng-valid").closest(".control-group").not(inError); - noInError.removeClass("error"); - - }, true); - - var className = attr.valShowValidation ? attr.valShowValidation : "show-validation"; - var savingEventName = attr.savingEvent ? attr.savingEvent : "formSubmitting"; - var savedEvent = attr.savedEvent ? attr.savingEvent : "formSubmitted"; - - //This tracks if the user is currently saving a new item, we use this to determine - // if we should display the warning dialog that they are leaving the page - if a new item - // is being saved we never want to display that dialog, this will also cause problems when there - // are server side validation issues. - var isSavingNewItem = false; - - //we should show validation if there are any msgs in the server validation collection - if (serverValidationManager.items.length > 0) { - element.addClass(className); - } - - var unsubscribe = []; - - //listen for the forms saving event - unsubscribe.push(scope.$on(savingEventName, function(ev, args) { - element.addClass(className); - - //set the flag so we can check to see if we should display the error. - isSavingNewItem = $routeParams.create; - })); - - //listen for the forms saved event - unsubscribe.push(scope.$on(savedEvent, function(ev, args) { - //remove validation class - element.removeClass(className); - - //clear form state as at this point we retrieve new data from the server - //and all validation will have cleared at this point - formCtrl.$setPristine(); - })); - - //This handles the 'unsaved changes' dialog which is triggered when a route is attempting to be changed but - // the form has pending changes - var locationEvent = $rootScope.$on('$locationChangeStart', function(event, nextLocation, currentLocation) { - if (!formCtrl.$dirty || isSavingNewItem) { - return; - } - - var path = nextLocation.split("#")[1]; - if (path) { - if (path.indexOf("%253") || path.indexOf("%252")) { - path = decodeURIComponent(path); - } - - if (!notificationsService.hasView()) { - var msg = { view: "confirmroutechange", args: { path: path, listener: locationEvent } }; - notificationsService.add(msg); - } - - //prevent the route! - event.preventDefault(); - - //raise an event - eventsService.emit("valFormManager.pendingChanges", true); - } - - }); - unsubscribe.push(locationEvent); - - //Ensure to remove the event handler when this instance is destroyted - scope.$on('$destroy', function() { - for (var u in unsubscribe) { - unsubscribe[u](); - } - }); - - $timeout(function(){ - formCtrl.$setPristine(); - }, 1000); - } - }; -} +/** +* @ngdoc directive +* @name umbraco.directives.directive:valFormManager +* @restrict A +* @require formController +* @description Used to broadcast an event to all elements inside this one to notify that form validation has +* changed. If we don't use this that means you have to put a watch for each directive on a form's validation +* changing which would result in much higher processing. We need to actually watch the whole $error collection of a form +* because just watching $valid or $invalid doesn't acurrately trigger form validation changing. +* This also sets the show-validation (or a custom) css class on the element when the form is invalid - this lets +* us css target elements to be displayed when the form is submitting/submitted. +* Another thing this directive does is to ensure that any .control-group that contains form elements that are invalid will +* be marked with the 'error' css class. This ensures that labels included in that control group are styled correctly. +**/ +function valFormManager(serverValidationManager, $rootScope, $log, $timeout, notificationsService, eventsService, $routeParams) { + return { + require: "form", + restrict: "A", + controller: function($scope) { + //This exposes an API for direct use with this directive + + var unsubscribe = []; + var self = this; + + //This is basically the same as a directive subscribing to an event but maybe a little + // nicer since the other directive can use this directive's API instead of a magical event + this.onValidationStatusChanged = function (cb) { + unsubscribe.push($scope.$on("valStatusChanged", function(evt, args) { + cb.apply(self, [evt, args]); + })); + }; + + //Ensure to remove the event handlers when this instance is destroyted + $scope.$on('$destroy', function () { + for (var u in unsubscribe) { + unsubscribe[u](); + } + }); + }, + link: function (scope, element, attr, formCtrl) { + + scope.$watch(function () { + return formCtrl.$error; + }, function (e) { + scope.$broadcast("valStatusChanged", { form: formCtrl }); + + //find all invalid elements' .control-group's and apply the error class + var inError = element.find(".control-group .ng-invalid").closest(".control-group"); + inError.addClass("error"); + + //find all control group's that have no error and ensure the class is removed + var noInError = element.find(".control-group .ng-valid").closest(".control-group").not(inError); + noInError.removeClass("error"); + + }, true); + + var className = attr.valShowValidation ? attr.valShowValidation : "show-validation"; + var savingEventName = attr.savingEvent ? attr.savingEvent : "formSubmitting"; + var savedEvent = attr.savedEvent ? attr.savingEvent : "formSubmitted"; + + //This tracks if the user is currently saving a new item, we use this to determine + // if we should display the warning dialog that they are leaving the page - if a new item + // is being saved we never want to display that dialog, this will also cause problems when there + // are server side validation issues. + var isSavingNewItem = false; + + //we should show validation if there are any msgs in the server validation collection + if (serverValidationManager.items.length > 0) { + element.addClass(className); + } + + var unsubscribe = []; + + //listen for the forms saving event + unsubscribe.push(scope.$on(savingEventName, function(ev, args) { + element.addClass(className); + + //set the flag so we can check to see if we should display the error. + isSavingNewItem = $routeParams.create; + })); + + //listen for the forms saved event + unsubscribe.push(scope.$on(savedEvent, function(ev, args) { + //remove validation class + element.removeClass(className); + + //clear form state as at this point we retrieve new data from the server + //and all validation will have cleared at this point + formCtrl.$setPristine(); + })); + + //This handles the 'unsaved changes' dialog which is triggered when a route is attempting to be changed but + // the form has pending changes + var locationEvent = $rootScope.$on('$locationChangeStart', function(event, nextLocation, currentLocation) { + if (!formCtrl.$dirty || isSavingNewItem) { + return; + } + + var path = nextLocation.split("#")[1]; + if (path) { + if (path.indexOf("%253") || path.indexOf("%252")) { + path = decodeURIComponent(path); + } + + if (!notificationsService.hasView()) { + var msg = { view: "confirmroutechange", args: { path: path, listener: locationEvent } }; + notificationsService.add(msg); + } + + //prevent the route! + event.preventDefault(); + + //raise an event + eventsService.emit("valFormManager.pendingChanges", true); + } + + }); + unsubscribe.push(locationEvent); + + //Ensure to remove the event handler when this instance is destroyted + scope.$on('$destroy', function() { + for (var u in unsubscribe) { + unsubscribe[u](); + } + }); + + $timeout(function(){ + formCtrl.$setPristine(); + }, 1000); + } + }; +} angular.module('umbraco.directives.validation').directive("valFormManager", valFormManager); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valpropertymsg.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valpropertymsg.directive.js similarity index 97% rename from src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valpropertymsg.directive.js rename to src/Umbraco.Web.UI.Client/src/common/directives/validation/valpropertymsg.directive.js index eba308d830..be5da51702 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valpropertymsg.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valpropertymsg.directive.js @@ -1,196 +1,196 @@ -/** -* @ngdoc directive -* @name umbraco.directives.directive:valPropertyMsg -* @restrict A -* @element textarea -* @requires formController -* @description This directive is used to control the display of the property level validation message. -* We will listen for server side validation changes -* and when an error is detected for this property we'll show the error message. -* In order for this directive to work, the valStatusChanged directive must be placed on the containing form. -**/ -function valPropertyMsg(serverValidationManager) { - - return { - scope: { - property: "=" - }, - require: "^form", //require that this directive is contained within an ngForm - replace: true, //replace the element with the template - restrict: "E", //restrict to element - template: "
    {{errorMsg}}
    ", - - /** - Our directive requries a reference to a form controller - which gets passed in to this parameter - */ - link: function (scope, element, attrs, formCtrl) { - - var watcher = null; - - // Gets the error message to display - function getErrorMsg() { - //this can be null if no property was assigned - if (scope.property) { - //first try to get the error msg from the server collection - var err = serverValidationManager.getPropertyError(scope.property.alias, ""); - //if there's an error message use it - if (err && err.errorMsg) { - return err.errorMsg; - } - else { - return scope.property.propertyErrorMessage ? scope.property.propertyErrorMessage : "Property has errors"; - } - - } - return "Property has errors"; - } - - // We need to subscribe to any changes to our model (based on user input) - // This is required because when we have a server error we actually invalidate - // the form which means it cannot be resubmitted. - // So once a field is changed that has a server error assigned to it - // we need to re-validate it for the server side validator so the user can resubmit - // the form. Of course normal client-side validators will continue to execute. - function startWatch() { - //if there's not already a watch - if (!watcher) { - watcher = scope.$watch("property.value", function (newValue, oldValue) { - - if (!newValue || angular.equals(newValue, oldValue)) { - return; - } - - var errCount = 0; - for (var e in formCtrl.$error) { - if (angular.isArray(formCtrl.$error[e])) { - errCount++; - } - } - - //we are explicitly checking for valServer errors here, since we shouldn't auto clear - // based on other errors. We'll also check if there's no other validation errors apart from valPropertyMsg, if valPropertyMsg - // is the only one, then we'll clear. - - if ((errCount === 1 && angular.isArray(formCtrl.$error.valPropertyMsg)) || (formCtrl.$invalid && angular.isArray(formCtrl.$error.valServer))) { - scope.errorMsg = ""; - formCtrl.$setValidity('valPropertyMsg', true); - stopWatch(); - } - }, true); - } - } - - //clear the watch when the property validator is valid again - function stopWatch() { - if (watcher) { - watcher(); - watcher = null; - } - } - - //if there's any remaining errors in the server validation service then we should show them. - var showValidation = serverValidationManager.items.length > 0; - var hasError = false; - - //create properties on our custom scope so we can use it in our template - scope.errorMsg = ""; - - var unsubscribe = []; - - //listen for form error changes - unsubscribe.push(scope.$on("valStatusChanged", function(evt, args) { - if (args.form.$invalid) { - - //first we need to check if the valPropertyMsg validity is invalid - if (formCtrl.$error.valPropertyMsg && formCtrl.$error.valPropertyMsg.length > 0) { - //since we already have an error we'll just return since this means we've already set the - // hasError and errorMsg properties which occurs below in the serverValidationManager.subscribe - return; - } - else if (element.closest(".umb-control-group").find(".ng-invalid").length > 0) { - //check if it's one of the properties that is invalid in the current content property - hasError = true; - //update the validation message if we don't already have one assigned. - if (showValidation && scope.errorMsg === "") { - scope.errorMsg = getErrorMsg(); - } - } - else { - hasError = false; - scope.errorMsg = ""; - } - } - else { - hasError = false; - scope.errorMsg = ""; - } - }, true)); - - //listen for the forms saving event - unsubscribe.push(scope.$on("formSubmitting", function(ev, args) { - showValidation = true; - if (hasError && scope.errorMsg === "") { - scope.errorMsg = getErrorMsg(); - } - else if (!hasError) { - scope.errorMsg = ""; - stopWatch(); - } - })); - - //listen for the forms saved event - unsubscribe.push(scope.$on("formSubmitted", function(ev, args) { - showValidation = false; - scope.errorMsg = ""; - formCtrl.$setValidity('valPropertyMsg', true); - stopWatch(); - })); - - //listen for server validation changes - // NOTE: we pass in "" in order to listen for all validation changes to the content property, not for - // validation changes to fields in the property this is because some server side validators may not - // return the field name for which the error belongs too, just the property for which it belongs. - // It's important to note that we need to subscribe to server validation changes here because we always must - // indicate that a content property is invalid at the property level since developers may not actually implement - // the correct field validation in their property editors. - - if (scope.property) { //this can be null if no property was assigned - serverValidationManager.subscribe(scope.property.alias, "", function (isValid, propertyErrors, allErrors) { - hasError = !isValid; - if (hasError) { - //set the error message to the server message - scope.errorMsg = propertyErrors[0].errorMsg; - //flag that the current validator is invalid - formCtrl.$setValidity('valPropertyMsg', false); - startWatch(); - } - else { - scope.errorMsg = ""; - //flag that the current validator is valid - formCtrl.$setValidity('valPropertyMsg', true); - stopWatch(); - } - }); - - //when the element is disposed we need to unsubscribe! - // NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain - // but they are a different callback instance than the above. - element.bind('$destroy', function () { - stopWatch(); - serverValidationManager.unsubscribe(scope.property.alias, ""); - }); - } - - //when the scope is disposed we need to unsubscribe - scope.$on('$destroy', function () { - for (var u in unsubscribe) { - unsubscribe[u](); - } - }); - } - - - }; -} +/** +* @ngdoc directive +* @name umbraco.directives.directive:valPropertyMsg +* @restrict A +* @element textarea +* @requires formController +* @description This directive is used to control the display of the property level validation message. +* We will listen for server side validation changes +* and when an error is detected for this property we'll show the error message. +* In order for this directive to work, the valStatusChanged directive must be placed on the containing form. +**/ +function valPropertyMsg(serverValidationManager) { + + return { + scope: { + property: "=" + }, + require: "^form", //require that this directive is contained within an ngForm + replace: true, //replace the element with the template + restrict: "E", //restrict to element + template: "
    {{errorMsg}}
    ", + + /** + Our directive requries a reference to a form controller + which gets passed in to this parameter + */ + link: function (scope, element, attrs, formCtrl) { + + var watcher = null; + + // Gets the error message to display + function getErrorMsg() { + //this can be null if no property was assigned + if (scope.property) { + //first try to get the error msg from the server collection + var err = serverValidationManager.getPropertyError(scope.property.alias, ""); + //if there's an error message use it + if (err && err.errorMsg) { + return err.errorMsg; + } + else { + return scope.property.propertyErrorMessage ? scope.property.propertyErrorMessage : "Property has errors"; + } + + } + return "Property has errors"; + } + + // We need to subscribe to any changes to our model (based on user input) + // This is required because when we have a server error we actually invalidate + // the form which means it cannot be resubmitted. + // So once a field is changed that has a server error assigned to it + // we need to re-validate it for the server side validator so the user can resubmit + // the form. Of course normal client-side validators will continue to execute. + function startWatch() { + //if there's not already a watch + if (!watcher) { + watcher = scope.$watch("property.value", function (newValue, oldValue) { + + if (!newValue || angular.equals(newValue, oldValue)) { + return; + } + + var errCount = 0; + for (var e in formCtrl.$error) { + if (angular.isArray(formCtrl.$error[e])) { + errCount++; + } + } + + //we are explicitly checking for valServer errors here, since we shouldn't auto clear + // based on other errors. We'll also check if there's no other validation errors apart from valPropertyMsg, if valPropertyMsg + // is the only one, then we'll clear. + + if ((errCount === 1 && angular.isArray(formCtrl.$error.valPropertyMsg)) || (formCtrl.$invalid && angular.isArray(formCtrl.$error.valServer))) { + scope.errorMsg = ""; + formCtrl.$setValidity('valPropertyMsg', true); + stopWatch(); + } + }, true); + } + } + + //clear the watch when the property validator is valid again + function stopWatch() { + if (watcher) { + watcher(); + watcher = null; + } + } + + //if there's any remaining errors in the server validation service then we should show them. + var showValidation = serverValidationManager.items.length > 0; + var hasError = false; + + //create properties on our custom scope so we can use it in our template + scope.errorMsg = ""; + + var unsubscribe = []; + + //listen for form error changes + unsubscribe.push(scope.$on("valStatusChanged", function(evt, args) { + if (args.form.$invalid) { + + //first we need to check if the valPropertyMsg validity is invalid + if (formCtrl.$error.valPropertyMsg && formCtrl.$error.valPropertyMsg.length > 0) { + //since we already have an error we'll just return since this means we've already set the + // hasError and errorMsg properties which occurs below in the serverValidationManager.subscribe + return; + } + else if (element.closest(".umb-control-group").find(".ng-invalid").length > 0) { + //check if it's one of the properties that is invalid in the current content property + hasError = true; + //update the validation message if we don't already have one assigned. + if (showValidation && scope.errorMsg === "") { + scope.errorMsg = getErrorMsg(); + } + } + else { + hasError = false; + scope.errorMsg = ""; + } + } + else { + hasError = false; + scope.errorMsg = ""; + } + }, true)); + + //listen for the forms saving event + unsubscribe.push(scope.$on("formSubmitting", function(ev, args) { + showValidation = true; + if (hasError && scope.errorMsg === "") { + scope.errorMsg = getErrorMsg(); + } + else if (!hasError) { + scope.errorMsg = ""; + stopWatch(); + } + })); + + //listen for the forms saved event + unsubscribe.push(scope.$on("formSubmitted", function(ev, args) { + showValidation = false; + scope.errorMsg = ""; + formCtrl.$setValidity('valPropertyMsg', true); + stopWatch(); + })); + + //listen for server validation changes + // NOTE: we pass in "" in order to listen for all validation changes to the content property, not for + // validation changes to fields in the property this is because some server side validators may not + // return the field name for which the error belongs too, just the property for which it belongs. + // It's important to note that we need to subscribe to server validation changes here because we always must + // indicate that a content property is invalid at the property level since developers may not actually implement + // the correct field validation in their property editors. + + if (scope.property) { //this can be null if no property was assigned + serverValidationManager.subscribe(scope.property.alias, "", function (isValid, propertyErrors, allErrors) { + hasError = !isValid; + if (hasError) { + //set the error message to the server message + scope.errorMsg = propertyErrors[0].errorMsg; + //flag that the current validator is invalid + formCtrl.$setValidity('valPropertyMsg', false); + startWatch(); + } + else { + scope.errorMsg = ""; + //flag that the current validator is valid + formCtrl.$setValidity('valPropertyMsg', true); + stopWatch(); + } + }); + + //when the element is disposed we need to unsubscribe! + // NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain + // but they are a different callback instance than the above. + element.bind('$destroy', function () { + stopWatch(); + serverValidationManager.unsubscribe(scope.property.alias, ""); + }); + } + + //when the scope is disposed we need to unsubscribe + scope.$on('$destroy', function () { + for (var u in unsubscribe) { + unsubscribe[u](); + } + }); + } + + + }; +} angular.module('umbraco.directives.validation').directive("valPropertyMsg", valPropertyMsg); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valpropertyvalidator.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valpropertyvalidator.directive.js similarity index 100% rename from src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valpropertyvalidator.directive.js rename to src/Umbraco.Web.UI.Client/src/common/directives/validation/valpropertyvalidator.directive.js diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valregex.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valregex.directive.js similarity index 97% rename from src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valregex.directive.js rename to src/Umbraco.Web.UI.Client/src/common/directives/validation/valregex.directive.js index 7bc3c6b877..6406583e77 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valregex.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valregex.directive.js @@ -1,78 +1,78 @@ -/** - * @ngdoc directive - * @name umbraco.directives.directive:valRegex - * @restrict A - * @description A custom directive to allow for matching a value against a regex string. - * NOTE: there's already an ng-pattern but this requires that a regex expression is set, not a regex string - **/ -function valRegex() { - - return { - require: 'ngModel', - restrict: "A", - link: function (scope, elm, attrs, ctrl) { - - var flags = ""; - var regex; - var eventBindings = []; - - attrs.$observe("valRegexFlags", function (newVal) { - if (newVal) { - flags = newVal; - } - }); - - attrs.$observe("valRegex", function (newVal) { - if (newVal) { - try { - var resolved = newVal; - if (resolved) { - regex = new RegExp(resolved, flags); - } - else { - regex = new RegExp(attrs.valRegex, flags); - } - } - catch (e) { - regex = new RegExp(attrs.valRegex, flags); - } - } - }); - - eventBindings.push(scope.$watch('ngModel', function(newValue, oldValue){ - if(newValue && newValue !== oldValue) { - patternValidator(newValue); - } - })); - - var patternValidator = function (viewValue) { - if (regex) { - //NOTE: we don't validate on empty values, use required validator for that - if (!viewValue || regex.test(viewValue.toString())) { - // it is valid - ctrl.$setValidity('valRegex', true); - //assign a message to the validator - ctrl.errorMsg = ""; - return viewValue; - } - else { - // it is invalid, return undefined (no model update) - ctrl.$setValidity('valRegex', false); - //assign a message to the validator - ctrl.errorMsg = "Value is invalid, it does not match the correct pattern"; - return undefined; - } - } - }; - - scope.$on('$destroy', function(){ - // unbind watchers - for(var e in eventBindings) { - eventBindings[e](); - } - }); - - } - }; -} -angular.module('umbraco.directives.validation').directive("valRegex", valRegex); +/** + * @ngdoc directive + * @name umbraco.directives.directive:valRegex + * @restrict A + * @description A custom directive to allow for matching a value against a regex string. + * NOTE: there's already an ng-pattern but this requires that a regex expression is set, not a regex string + **/ +function valRegex() { + + return { + require: 'ngModel', + restrict: "A", + link: function (scope, elm, attrs, ctrl) { + + var flags = ""; + var regex; + var eventBindings = []; + + attrs.$observe("valRegexFlags", function (newVal) { + if (newVal) { + flags = newVal; + } + }); + + attrs.$observe("valRegex", function (newVal) { + if (newVal) { + try { + var resolved = newVal; + if (resolved) { + regex = new RegExp(resolved, flags); + } + else { + regex = new RegExp(attrs.valRegex, flags); + } + } + catch (e) { + regex = new RegExp(attrs.valRegex, flags); + } + } + }); + + eventBindings.push(scope.$watch('ngModel', function(newValue, oldValue){ + if(newValue && newValue !== oldValue) { + patternValidator(newValue); + } + })); + + var patternValidator = function (viewValue) { + if (regex) { + //NOTE: we don't validate on empty values, use required validator for that + if (!viewValue || regex.test(viewValue.toString())) { + // it is valid + ctrl.$setValidity('valRegex', true); + //assign a message to the validator + ctrl.errorMsg = ""; + return viewValue; + } + else { + // it is invalid, return undefined (no model update) + ctrl.$setValidity('valRegex', false); + //assign a message to the validator + ctrl.errorMsg = "Value is invalid, it does not match the correct pattern"; + return undefined; + } + } + }; + + scope.$on('$destroy', function(){ + // unbind watchers + for(var e in eventBindings) { + eventBindings[e](); + } + }); + + } + }; +} +angular.module('umbraco.directives.validation').directive("valRegex", valRegex); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valserver.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valserver.directive.js similarity index 97% rename from src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valserver.directive.js rename to src/Umbraco.Web.UI.Client/src/common/directives/validation/valserver.directive.js index 6225485073..1432a713c0 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valserver.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valserver.directive.js @@ -1,94 +1,94 @@ -/** - * @ngdoc directive - * @name umbraco.directives.directive:valServer - * @restrict A - * @description This directive is used to associate a content property with a server-side validation response - * so that the validators in angular are updated based on server-side feedback. - **/ -function valServer(serverValidationManager) { - return { - require: ['ngModel', '?^umbProperty'], - restrict: "A", - link: function (scope, element, attr, ctrls) { - - var modelCtrl = ctrls[0]; - var umbPropCtrl = ctrls.length > 1 ? ctrls[1] : null; - if (!umbPropCtrl) { - //we cannot proceed, this validator will be disabled - return; - } - - var watcher = null; - - //Need to watch the value model for it to change, previously we had subscribed to - //modelCtrl.$viewChangeListeners but this is not good enough if you have an editor that - // doesn't specifically have a 2 way ng binding. This is required because when we - // have a server error we actually invalidate the form which means it cannot be - // resubmitted. So once a field is changed that has a server error assigned to it - // we need to re-validate it for the server side validator so the user can resubmit - // the form. Of course normal client-side validators will continue to execute. - function startWatch() { - //if there's not already a watch - if (!watcher) { - watcher = scope.$watch(function () { - return modelCtrl.$modelValue; - }, function (newValue, oldValue) { - - if (!newValue || angular.equals(newValue, oldValue)) { - return; - } - - if (modelCtrl.$invalid) { - modelCtrl.$setValidity('valServer', true); - stopWatch(); - } - }, true); - } - } - - function stopWatch() { - if (watcher) { - watcher(); - watcher = null; - } - } - - var currentProperty = umbPropCtrl.property; - - //default to 'value' if nothing is set - var fieldName = "value"; - if (attr.valServer) { - fieldName = scope.$eval(attr.valServer); - if (!fieldName) { - //eval returned nothing so just use the string - fieldName = attr.valServer; - } - } - - //subscribe to the server validation changes - serverValidationManager.subscribe(currentProperty.alias, fieldName, function (isValid, propertyErrors, allErrors) { - if (!isValid) { - modelCtrl.$setValidity('valServer', false); - //assign an error msg property to the current validator - modelCtrl.errorMsg = propertyErrors[0].errorMsg; - startWatch(); - } - else { - modelCtrl.$setValidity('valServer', true); - //reset the error message - modelCtrl.errorMsg = ""; - stopWatch(); - } - }); - - //when the element is disposed we need to unsubscribe! - // NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain - // but they are a different callback instance than the above. - element.bind('$destroy', function () { - stopWatch(); - serverValidationManager.unsubscribe(currentProperty.alias, fieldName); - }); - } - }; -} +/** + * @ngdoc directive + * @name umbraco.directives.directive:valServer + * @restrict A + * @description This directive is used to associate a content property with a server-side validation response + * so that the validators in angular are updated based on server-side feedback. + **/ +function valServer(serverValidationManager) { + return { + require: ['ngModel', '?^umbProperty'], + restrict: "A", + link: function (scope, element, attr, ctrls) { + + var modelCtrl = ctrls[0]; + var umbPropCtrl = ctrls.length > 1 ? ctrls[1] : null; + if (!umbPropCtrl) { + //we cannot proceed, this validator will be disabled + return; + } + + var watcher = null; + + //Need to watch the value model for it to change, previously we had subscribed to + //modelCtrl.$viewChangeListeners but this is not good enough if you have an editor that + // doesn't specifically have a 2 way ng binding. This is required because when we + // have a server error we actually invalidate the form which means it cannot be + // resubmitted. So once a field is changed that has a server error assigned to it + // we need to re-validate it for the server side validator so the user can resubmit + // the form. Of course normal client-side validators will continue to execute. + function startWatch() { + //if there's not already a watch + if (!watcher) { + watcher = scope.$watch(function () { + return modelCtrl.$modelValue; + }, function (newValue, oldValue) { + + if (!newValue || angular.equals(newValue, oldValue)) { + return; + } + + if (modelCtrl.$invalid) { + modelCtrl.$setValidity('valServer', true); + stopWatch(); + } + }, true); + } + } + + function stopWatch() { + if (watcher) { + watcher(); + watcher = null; + } + } + + var currentProperty = umbPropCtrl.property; + + //default to 'value' if nothing is set + var fieldName = "value"; + if (attr.valServer) { + fieldName = scope.$eval(attr.valServer); + if (!fieldName) { + //eval returned nothing so just use the string + fieldName = attr.valServer; + } + } + + //subscribe to the server validation changes + serverValidationManager.subscribe(currentProperty.alias, fieldName, function (isValid, propertyErrors, allErrors) { + if (!isValid) { + modelCtrl.$setValidity('valServer', false); + //assign an error msg property to the current validator + modelCtrl.errorMsg = propertyErrors[0].errorMsg; + startWatch(); + } + else { + modelCtrl.$setValidity('valServer', true); + //reset the error message + modelCtrl.errorMsg = ""; + stopWatch(); + } + }); + + //when the element is disposed we need to unsubscribe! + // NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain + // but they are a different callback instance than the above. + element.bind('$destroy', function () { + stopWatch(); + serverValidationManager.unsubscribe(currentProperty.alias, fieldName); + }); + } + }; +} angular.module('umbraco.directives.validation').directive("valServer", valServer); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valserverfield.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valserverfield.directive.js similarity index 97% rename from src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valserverfield.directive.js rename to src/Umbraco.Web.UI.Client/src/common/directives/validation/valserverfield.directive.js index 46fbaf93dd..1e0d2d8ba5 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valserverfield.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valserverfield.directive.js @@ -1,65 +1,65 @@ -/** - * @ngdoc directive - * @name umbraco.directives.directive:valServerField - * @restrict A - * @description This directive is used to associate a content field (not user defined) with a server-side validation response - * so that the validators in angular are updated based on server-side feedback. - **/ -function valServerField(serverValidationManager) { - return { - require: 'ngModel', - restrict: "A", - link: function (scope, element, attr, ctrl) { - - var fieldName = null; - var eventBindings = []; - - attr.$observe("valServerField", function (newVal) { - if (newVal && fieldName === null) { - fieldName = newVal; - - //subscribe to the changed event of the view model. This is required because when we - // have a server error we actually invalidate the form which means it cannot be - // resubmitted. So once a field is changed that has a server error assigned to it - // we need to re-validate it for the server side validator so the user can resubmit - // the form. Of course normal client-side validators will continue to execute. - eventBindings.push(scope.$watch('ngModel', function(newValue){ - if (ctrl.$invalid) { - ctrl.$setValidity('valServerField', true); - } - })); - - //subscribe to the server validation changes - serverValidationManager.subscribe(null, fieldName, function (isValid, fieldErrors, allErrors) { - if (!isValid) { - ctrl.$setValidity('valServerField', false); - //assign an error msg property to the current validator - ctrl.errorMsg = fieldErrors[0].errorMsg; - } - else { - ctrl.$setValidity('valServerField', true); - //reset the error message - ctrl.errorMsg = ""; - } - }); - - //when the element is disposed we need to unsubscribe! - // NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain - // but they are a different callback instance than the above. - element.bind('$destroy', function () { - serverValidationManager.unsubscribe(null, fieldName); - }); - } - }); - - scope.$on('$destroy', function(){ - // unbind watchers - for(var e in eventBindings) { - eventBindings[e](); - } - }); - - } - }; -} -angular.module('umbraco.directives.validation').directive("valServerField", valServerField); +/** + * @ngdoc directive + * @name umbraco.directives.directive:valServerField + * @restrict A + * @description This directive is used to associate a content field (not user defined) with a server-side validation response + * so that the validators in angular are updated based on server-side feedback. + **/ +function valServerField(serverValidationManager) { + return { + require: 'ngModel', + restrict: "A", + link: function (scope, element, attr, ctrl) { + + var fieldName = null; + var eventBindings = []; + + attr.$observe("valServerField", function (newVal) { + if (newVal && fieldName === null) { + fieldName = newVal; + + //subscribe to the changed event of the view model. This is required because when we + // have a server error we actually invalidate the form which means it cannot be + // resubmitted. So once a field is changed that has a server error assigned to it + // we need to re-validate it for the server side validator so the user can resubmit + // the form. Of course normal client-side validators will continue to execute. + eventBindings.push(scope.$watch('ngModel', function(newValue){ + if (ctrl.$invalid) { + ctrl.$setValidity('valServerField', true); + } + })); + + //subscribe to the server validation changes + serverValidationManager.subscribe(null, fieldName, function (isValid, fieldErrors, allErrors) { + if (!isValid) { + ctrl.$setValidity('valServerField', false); + //assign an error msg property to the current validator + ctrl.errorMsg = fieldErrors[0].errorMsg; + } + else { + ctrl.$setValidity('valServerField', true); + //reset the error message + ctrl.errorMsg = ""; + } + }); + + //when the element is disposed we need to unsubscribe! + // NOTE: this is very important otherwise when this controller re-binds the previous subscriptsion will remain + // but they are a different callback instance than the above. + element.bind('$destroy', function () { + serverValidationManager.unsubscribe(null, fieldName); + }); + } + }); + + scope.$on('$destroy', function(){ + // unbind watchers + for(var e in eventBindings) { + eventBindings[e](); + } + }); + + } + }; +} +angular.module('umbraco.directives.validation').directive("valServerField", valServerField); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valtab.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valtab.directive.js similarity index 97% rename from src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valtab.directive.js rename to src/Umbraco.Web.UI.Client/src/common/directives/validation/valtab.directive.js index fbca0cd233..8d1fc60083 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valtab.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valtab.directive.js @@ -1,38 +1,38 @@ - -/** -* @ngdoc directive -* @name umbraco.directives.directive:valTab -* @restrict A -* @description Used to show validation warnings for a tab to indicate that the tab content has validations errors in its data. -* In order for this directive to work, the valFormManager directive must be placed on the containing form. -**/ -function valTab() { - return { - require: ['^form', '^valFormManager'], - restrict: "A", - link: function (scope, element, attr, ctrs) { - - var valFormManager = ctrs[1]; - var tabId = "tab" + scope.tab.id; - scope.tabHasError = false; - - //listen for form validation changes - valFormManager.onValidationStatusChanged(function (evt, args) { - if (!args.form.$valid) { - var tabContent = element.closest(".umb-panel").find("#" + tabId); - //check if the validation messages are contained inside of this tabs - if (tabContent.find(".ng-invalid").length > 0) { - scope.tabHasError = true; - } else { - scope.tabHasError = false; - } - } - else { - scope.tabHasError = false; - } - }); - - } - }; -} + +/** +* @ngdoc directive +* @name umbraco.directives.directive:valTab +* @restrict A +* @description Used to show validation warnings for a tab to indicate that the tab content has validations errors in its data. +* In order for this directive to work, the valFormManager directive must be placed on the containing form. +**/ +function valTab() { + return { + require: ['^form', '^valFormManager'], + restrict: "A", + link: function (scope, element, attr, ctrs) { + + var valFormManager = ctrs[1]; + var tabId = "tab" + scope.tab.id; + scope.tabHasError = false; + + //listen for form validation changes + valFormManager.onValidationStatusChanged(function (evt, args) { + if (!args.form.$valid) { + var tabContent = element.closest(".umb-panel").find("#" + tabId); + //check if the validation messages are contained inside of this tabs + if (tabContent.find(".ng-invalid").length > 0) { + scope.tabHasError = true; + } else { + scope.tabHasError = false; + } + } + else { + scope.tabHasError = false; + } + }); + + } + }; +} angular.module('umbraco.directives.validation').directive("valTab", valTab); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valtogglemsg.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valtogglemsg.directive.js similarity index 97% rename from src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valtogglemsg.directive.js rename to src/Umbraco.Web.UI.Client/src/common/directives/validation/valtogglemsg.directive.js index 43792a708a..304f151274 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valtogglemsg.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valtogglemsg.directive.js @@ -1,90 +1,90 @@ -function valToggleMsg(serverValidationManager) { - return { - require: "^form", - restrict: "A", - - /** - Our directive requries a reference to a form controller which gets passed in to this parameter - */ - link: function (scope, element, attr, formCtrl) { - - if (!attr.valToggleMsg){ - throw "valToggleMsg requires that a reference to a validator is specified"; - } - if (!attr.valMsgFor){ - throw "valToggleMsg requires that the attribute valMsgFor exists on the element"; - } - if (!formCtrl[attr.valMsgFor]) { - throw "valToggleMsg cannot find field " + attr.valMsgFor + " on form " + formCtrl.$name; - } - - //if there's any remaining errors in the server validation service then we should show them. - var showValidation = serverValidationManager.items.length > 0; - var hasCustomMsg = element.contents().length > 0; - - //add a watch to the validator for the value (i.e. myForm.value.$error.required ) - scope.$watch(function () { - //sometimes if a dialog closes in the middle of digest we can get null references here - - return (formCtrl && formCtrl[attr.valMsgFor]) ? formCtrl[attr.valMsgFor].$error[attr.valToggleMsg] : null; - }, function () { - //sometimes if a dialog closes in the middle of digest we can get null references here - if ((formCtrl && formCtrl[attr.valMsgFor])) { - if (formCtrl[attr.valMsgFor].$error[attr.valToggleMsg] && showValidation) { - element.show(); - //display the error message if this element has no contents - if (!hasCustomMsg) { - element.html(formCtrl[attr.valMsgFor].errorMsg); - } - } - else { - element.hide(); - } - } - }); - - var unsubscribe = []; - - //listen for the saving event (the result is a callback method which is called to unsubscribe) - unsubscribe.push(scope.$on("formSubmitting", function(ev, args) { - showValidation = true; - if (formCtrl[attr.valMsgFor].$error[attr.valToggleMsg]) { - element.show(); - //display the error message if this element has no contents - if (!hasCustomMsg) { - element.html(formCtrl[attr.valMsgFor].errorMsg); - } - } - else { - element.hide(); - } - })); - - //listen for the saved event (the result is a callback method which is called to unsubscribe) - unsubscribe.push(scope.$on("formSubmitted", function(ev, args) { - showValidation = false; - element.hide(); - })); - - //when the element is disposed we need to unsubscribe! - // NOTE: this is very important otherwise if this directive is part of a modal, the listener still exists because the dom - // element might still be there even after the modal has been hidden. - element.bind('$destroy', function () { - for (var u in unsubscribe) { - unsubscribe[u](); - } - }); - - } - }; -} - -/** -* @ngdoc directive -* @name umbraco.directives.directive:valToggleMsg -* @restrict A -* @element input -* @requires formController -* @description This directive will show/hide an error based on: is the value + the given validator invalid? AND, has the form been submitted ? -**/ +function valToggleMsg(serverValidationManager) { + return { + require: "^form", + restrict: "A", + + /** + Our directive requries a reference to a form controller which gets passed in to this parameter + */ + link: function (scope, element, attr, formCtrl) { + + if (!attr.valToggleMsg){ + throw "valToggleMsg requires that a reference to a validator is specified"; + } + if (!attr.valMsgFor){ + throw "valToggleMsg requires that the attribute valMsgFor exists on the element"; + } + if (!formCtrl[attr.valMsgFor]) { + throw "valToggleMsg cannot find field " + attr.valMsgFor + " on form " + formCtrl.$name; + } + + //if there's any remaining errors in the server validation service then we should show them. + var showValidation = serverValidationManager.items.length > 0; + var hasCustomMsg = element.contents().length > 0; + + //add a watch to the validator for the value (i.e. myForm.value.$error.required ) + scope.$watch(function () { + //sometimes if a dialog closes in the middle of digest we can get null references here + + return (formCtrl && formCtrl[attr.valMsgFor]) ? formCtrl[attr.valMsgFor].$error[attr.valToggleMsg] : null; + }, function () { + //sometimes if a dialog closes in the middle of digest we can get null references here + if ((formCtrl && formCtrl[attr.valMsgFor])) { + if (formCtrl[attr.valMsgFor].$error[attr.valToggleMsg] && showValidation) { + element.show(); + //display the error message if this element has no contents + if (!hasCustomMsg) { + element.html(formCtrl[attr.valMsgFor].errorMsg); + } + } + else { + element.hide(); + } + } + }); + + var unsubscribe = []; + + //listen for the saving event (the result is a callback method which is called to unsubscribe) + unsubscribe.push(scope.$on("formSubmitting", function(ev, args) { + showValidation = true; + if (formCtrl[attr.valMsgFor].$error[attr.valToggleMsg]) { + element.show(); + //display the error message if this element has no contents + if (!hasCustomMsg) { + element.html(formCtrl[attr.valMsgFor].errorMsg); + } + } + else { + element.hide(); + } + })); + + //listen for the saved event (the result is a callback method which is called to unsubscribe) + unsubscribe.push(scope.$on("formSubmitted", function(ev, args) { + showValidation = false; + element.hide(); + })); + + //when the element is disposed we need to unsubscribe! + // NOTE: this is very important otherwise if this directive is part of a modal, the listener still exists because the dom + // element might still be there even after the modal has been hidden. + element.bind('$destroy', function () { + for (var u in unsubscribe) { + unsubscribe[u](); + } + }); + + } + }; +} + +/** +* @ngdoc directive +* @name umbraco.directives.directive:valToggleMsg +* @restrict A +* @element input +* @requires formController +* @description This directive will show/hide an error based on: is the value + the given validator invalid? AND, has the form been submitted ? +**/ angular.module('umbraco.directives.validation').directive("valToggleMsg", valToggleMsg); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valtriggerchange.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valtriggerchange.directive.js similarity index 100% rename from src/Umbraco.Web.UI.Client/src/common/directives/components/validation/valtriggerchange.directive.js rename to src/Umbraco.Web.UI.Client/src/common/directives/validation/valtriggerchange.directive.js From f29b5aade7b14fec2c028abb44a30c29a35bd2b7 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 24 May 2016 15:07:35 +0200 Subject: [PATCH 068/535] only removes the buggy formatters/parsers if the attribute is type="email" --- .../directives/validation/valemail.directive.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valemail.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valemail.directive.js index ade3403ad7..8574d01f5a 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/validation/valemail.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/validation/valemail.directive.js @@ -29,12 +29,16 @@ function valEmail(valEmailExpression) { } }; - //we need to remove the existing parsers = the default angular one which is created by - // type="email", but this has a regex issue, so we'll remove that and add our custom one - ctrl.$parsers.pop(); - //we also need to remove the existing formatter - the default angular one will not render - // what it thinks is an invalid email address, so it will just be blank - ctrl.$formatters.pop(); + //if there is an attribute: type="email" then we need to remove those formatters and parsers + if (attrs.type === "email") { + //we need to remove the existing parsers = the default angular one which is created by + // type="email", but this has a regex issue, so we'll remove that and add our custom one + ctrl.$parsers.pop(); + //we also need to remove the existing formatter - the default angular one will not render + // what it thinks is an invalid email address, so it will just be blank + ctrl.$formatters.pop(); + } + ctrl.$parsers.push(patternValidator); } }; From 42021a56b21338a61b7ed6f7a726b63689419ce8 Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 24 May 2016 09:47:24 +0200 Subject: [PATCH 069/535] U4-8290 - minor cleanup & refactoring --- src/Umbraco.Core/Constants-PropertyEditors.cs | 21 ++++++----- src/Umbraco.Core/Models/PropertyType.cs | 2 +- .../PropertyEditorAttribute.cs | 4 +-- .../PropertyEditorValueTypes.cs | 31 ++++++++++------ .../PropertyEditors/PropertyValueEditor.cs | 35 ++++++++++-------- .../RequiredManifestValueValidator.cs | 2 +- .../ValueConverters/JsonValueConverter.cs | 2 +- src/Umbraco.Core/Services/DataTypeService.cs | 35 ++---------------- .../PropertyEditorValueEditorTests.cs | 28 +++++++-------- .../ContentPickerPropertyEditor.cs | 2 +- .../PropertyEditors/DatePropertyEditor.cs | 2 +- .../PropertyEditors/DateTimePropertyEditor.cs | 2 +- .../PropertyEditors/DecimalPropertyEditor.cs | 2 +- .../PropertyEditors/DropDownPropertyEditor.cs | 2 +- .../DropDownWithKeysPropertyEditor.cs | 2 +- .../PropertyEditors/GridPropertyEditor.cs | 2 +- .../ImageCropperPropertyEditor.cs | 2 +- .../PropertyEditors/IntegerPropertyEditor.cs | 2 +- .../PropertyEditors/LabelPropertyEditor.cs | 36 +++++++++++++------ .../MacroContainerPropertyEditor.cs | 2 +- .../PropertyEditors/MarkdownPropertyEditor.cs | 2 +- .../MediaPickerPropertyEditor.cs | 2 +- .../MemberPickerPropertyEditor.cs | 2 +- .../MultipleTextStringPropertyEditor.cs | 2 +- .../RadioButtonsPropertyEditor.cs | 2 +- .../RelatedLinksPropertyEditor.cs | 2 +- .../PropertyEditors/RichTextPropertyEditor.cs | 2 +- .../PropertyEditors/TextAreaPropertyEditor.cs | 2 +- .../TrueFalsePropertyEditor.cs | 2 +- .../UserPickerPropertyEditor.cs | 2 +- 30 files changed, 119 insertions(+), 117 deletions(-) diff --git a/src/Umbraco.Core/Constants-PropertyEditors.cs b/src/Umbraco.Core/Constants-PropertyEditors.cs index 358ca0e5d7..80f118b58e 100644 --- a/src/Umbraco.Core/Constants-PropertyEditors.cs +++ b/src/Umbraco.Core/Constants-PropertyEditors.cs @@ -11,7 +11,7 @@ namespace Umbraco.Core { /// /// Used to prefix generic properties that are internal content properties - /// + ///
    public const string InternalGenericPropertiesPrefix = "_umb_"; /// @@ -74,7 +74,7 @@ namespace Umbraco.Core /// [Obsolete("GUIDs are no longer used to reference Property Editors, use the Alias constant instead. This will be removed in future versions")] public const string DictionaryPicker = "17B70066-F764-407D-AB05-3717F1E1C513"; - + /// /// Guid for the Dropdown list datatype. /// @@ -352,7 +352,7 @@ namespace Umbraco.Core ///
    [Obsolete("GUIDs are no longer used to reference Property Editors, use the Alias constant instead. This will be removed in future versions")] public const string UltimatePicker = "CDBF0B5D-5CB2-445F-BC12-FCAAEC07CF2C"; - + /// /// Guid for the UltraSimpleEditor datatype. /// @@ -369,7 +369,7 @@ namespace Umbraco.Core ///
    [Obsolete("GUIDs are no longer used to reference Property Editors, use the Alias constant instead. This will be removed in future versions")] public const string UmbracoUserControlWrapper = "D15E1281-E456-4B24-AA86-1DDA3E4299D5"; - + /// /// Guid for the Upload field datatype. /// @@ -420,11 +420,14 @@ namespace Umbraco.Core ///
    public const string EmailAddressAlias = "Umbraco.EmailAddress"; - /// - /// Pre-value name used to indicate a field that can be used to override the database field to which data for the associated - /// property is saved - /// - public const string DataValueTypePreValueKey = "umbracoDataValueType"; + public static class PreValueKeys + { + /// + /// Pre-value name used to indicate a field that can be used to override the database field to which data for the associated + /// property is saved + /// + public const string DataValueType = "umbracoDataValueType"; + } } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Models/PropertyType.cs b/src/Umbraco.Core/Models/PropertyType.cs index 00e7fc8d13..846b907197 100644 --- a/src/Umbraco.Core/Models/PropertyType.cs +++ b/src/Umbraco.Core/Models/PropertyType.cs @@ -436,7 +436,7 @@ namespace Umbraco.Core.Models { var propertyEditor = PropertyEditorResolver.Current.GetByAlias(_propertyEditorAlias); return propertyEditor.PreValueEditor.Fields - .SingleOrDefault(x => x.Key == Constants.PropertyEditors.DataValueTypePreValueKey) != null; + .SingleOrDefault(x => x.Key == Constants.PropertyEditors.PreValueKeys.DataValueType) != null; } /// diff --git a/src/Umbraco.Core/PropertyEditors/PropertyEditorAttribute.cs b/src/Umbraco.Core/PropertyEditors/PropertyEditorAttribute.cs index dadbe5173f..d120753185 100644 --- a/src/Umbraco.Core/PropertyEditors/PropertyEditorAttribute.cs +++ b/src/Umbraco.Core/PropertyEditors/PropertyEditorAttribute.cs @@ -19,7 +19,7 @@ namespace Umbraco.Core.PropertyEditors EditorView = editorView; //defaults - ValueType = PropertyEditorValueTypes.StringType; + ValueType = PropertyEditorValueTypes.String; Icon = Constants.Icons.PropertyEditor; Group = "common"; } @@ -33,7 +33,7 @@ namespace Umbraco.Core.PropertyEditors Name = name; //defaults - ValueType = PropertyEditorValueTypes.StringType; + ValueType = PropertyEditorValueTypes.String; Icon = Constants.Icons.PropertyEditor; Group = "common"; } diff --git a/src/Umbraco.Core/PropertyEditors/PropertyEditorValueTypes.cs b/src/Umbraco.Core/PropertyEditors/PropertyEditorValueTypes.cs index 073e4388ca..0ece42d82b 100644 --- a/src/Umbraco.Core/PropertyEditors/PropertyEditorValueTypes.cs +++ b/src/Umbraco.Core/PropertyEditors/PropertyEditorValueTypes.cs @@ -1,25 +1,34 @@ -namespace Umbraco.Core.PropertyEditors +using System; + +namespace Umbraco.Core.PropertyEditors { public static class PropertyEditorValueTypes { - public const string DateType = "DATE"; + // mapped to DataTypeDatabaseType in DataTypeService.OverrideDatabaseTypeIfProvidedInPreValues + // BUT what about those that are not mapped? + // + // also mapped to DataTypeDatabaseType in PropertyValueEditor + // and this time the "+" are mapped - public const string DateTimeType = "DATETIME"; + public const string Date = "DATE"; // +Date - public const string DecimalType = "DECIMAL"; + public const string DateTime = "DATETIME"; // Date - public const string IntegerType = "INT"; + public const string Decimal = "DECIMAL"; // Decimal - public const string IntegerTypeAlternative = "INTEGER"; + public const string Integer = "INT"; // Integer - public const string JsonType = "JSON"; + [Obsolete("Use Integer.", false)] + public const string IntegerAlternative = "INTEGER"; // +Integer - public const string TextType = "TEXT"; + public const string Json = "JSON"; // +NText - public const string TimeType = "TIME"; + public const string Text = "TEXT"; // NText - public const string StringType = "STRING"; + public const string Time = "TIME"; // +Date - public const string XmlType = "XML"; + public const string String = "STRING"; // NVarchar + + public const string Xml = "XML"; // +NText } } diff --git a/src/Umbraco.Core/PropertyEditors/PropertyValueEditor.cs b/src/Umbraco.Core/PropertyEditors/PropertyValueEditor.cs index a7154d7d67..0b083025f7 100644 --- a/src/Umbraco.Core/PropertyEditors/PropertyValueEditor.cs +++ b/src/Umbraco.Core/PropertyEditors/PropertyValueEditor.cs @@ -25,7 +25,7 @@ namespace Umbraco.Core.PropertyEditors /// public PropertyValueEditor() { - ValueType = PropertyEditorValueTypes.StringType; + ValueType = PropertyEditorValueTypes.String; //set a default for validators Validators = new List(); } @@ -123,30 +123,35 @@ namespace Umbraco.Core.PropertyEditors } /// - /// Returns the true DataTypeDatabaseType from the string representation ValueType + /// Returns the true DataTypeDatabaseType from the string representation ValueType. /// /// public DataTypeDatabaseType GetDatabaseType() { - switch (ValueType.ToUpper(CultureInfo.InvariantCulture)) + return GetDatabaseType(ValueType); + } + + public static DataTypeDatabaseType GetDatabaseType(string valueType) + { + switch (valueType.ToUpperInvariant()) { - case PropertyEditorValueTypes.IntegerType: - case PropertyEditorValueTypes.IntegerTypeAlternative: + case PropertyEditorValueTypes.Integer: + case PropertyEditorValueTypes.IntegerAlternative: return DataTypeDatabaseType.Integer; - case PropertyEditorValueTypes.DecimalType: + case PropertyEditorValueTypes.Decimal: return DataTypeDatabaseType.Decimal; - case PropertyEditorValueTypes.StringType: + case PropertyEditorValueTypes.String: return DataTypeDatabaseType.Nvarchar; - case PropertyEditorValueTypes.TextType: - case PropertyEditorValueTypes.JsonType: - case PropertyEditorValueTypes.XmlType: + case PropertyEditorValueTypes.Text: + case PropertyEditorValueTypes.Json: + case PropertyEditorValueTypes.Xml: return DataTypeDatabaseType.Ntext; - case PropertyEditorValueTypes.DateTimeType: - case PropertyEditorValueTypes.DateType: - case PropertyEditorValueTypes.TimeType: + case PropertyEditorValueTypes.DateTime: + case PropertyEditorValueTypes.Date: + case PropertyEditorValueTypes.Time: return DataTypeDatabaseType.Date; default: - throw new FormatException("The ValueType does not match a known value type"); + throw new ArgumentException("Not a valid value type.", "valueType"); } } @@ -238,7 +243,7 @@ namespace Umbraco.Core.PropertyEditors public virtual object ConvertEditorToDb(ContentPropertyData editorValue, object currentValue) { //if it's json but it's empty json, then return null - if (ValueType.InvariantEquals(PropertyEditorValueTypes.JsonType) && editorValue.Value != null && editorValue.Value.ToString().DetectIsEmptyJson()) + if (ValueType.InvariantEquals(PropertyEditorValueTypes.Json) && editorValue.Value != null && editorValue.Value.ToString().DetectIsEmptyJson()) { return null; } diff --git a/src/Umbraco.Core/PropertyEditors/RequiredManifestValueValidator.cs b/src/Umbraco.Core/PropertyEditors/RequiredManifestValueValidator.cs index 842184d9ae..b3e8ff1f6f 100644 --- a/src/Umbraco.Core/PropertyEditors/RequiredManifestValueValidator.cs +++ b/src/Umbraco.Core/PropertyEditors/RequiredManifestValueValidator.cs @@ -22,7 +22,7 @@ namespace Umbraco.Core.PropertyEditors { var asString = value.ToString(); - if (editor.ValueEditor.ValueType.InvariantEquals(PropertyEditorValueTypes.JsonType)) + if (editor.ValueEditor.ValueType.InvariantEquals(PropertyEditorValueTypes.Json)) { if (asString.DetectIsEmptyJson()) { diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/JsonValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/JsonValueConverter.cs index 60c2d7f667..c5f0236a1a 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/JsonValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/JsonValueConverter.cs @@ -26,7 +26,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters { var propertyEditor = PropertyEditorResolver.Current.GetByAlias(propertyType.PropertyEditorAlias); if (propertyEditor == null) return false; - return propertyEditor.ValueEditor.ValueType.InvariantEquals(PropertyEditorValueTypes.JsonType); + return propertyEditor.ValueEditor.ValueType.InvariantEquals(PropertyEditorValueTypes.Json); } public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview) diff --git a/src/Umbraco.Core/Services/DataTypeService.cs b/src/Umbraco.Core/Services/DataTypeService.cs index 75234fa3ab..2cdcfc76d5 100644 --- a/src/Umbraco.Core/Services/DataTypeService.cs +++ b/src/Umbraco.Core/Services/DataTypeService.cs @@ -504,7 +504,9 @@ namespace Umbraco.Core.Services if (Saving.IsRaisedEventCancelled(new SaveEventArgs(dataTypeDefinition), this)) return; - OverrideDatabaseTypeIfProvidedInPreValues(dataTypeDefinition, values); + // if preValues contain the data type, override the data type definition accordingly + if (values != null && values.ContainsKey(Constants.PropertyEditors.PreValueKeys.DataValueType)) + dataTypeDefinition.DatabaseType = PropertyValueEditor.GetDatabaseType(values[Constants.PropertyEditors.PreValueKeys.DataValueType].Value); var uow = UowProvider.GetUnitOfWork(); using (var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow)) @@ -525,37 +527,6 @@ namespace Umbraco.Core.Services Audit(AuditType.Save, string.Format("Save DataTypeDefinition performed by user"), userId, dataTypeDefinition.Id); } - /// - /// If the database data field is provided in the pre-values update the data type definition to that instead of the - /// default for the property editor - /// - /// - /// - private static void OverrideDatabaseTypeIfProvidedInPreValues(IDataTypeDefinition dataTypeDefinition, IDictionary values) - { - if (values != null && values.ContainsKey(Constants.PropertyEditors.DataValueTypePreValueKey)) - { - switch (values[Constants.PropertyEditors.DataValueTypePreValueKey].Value) - { - case PropertyEditorValueTypes.StringType: - dataTypeDefinition.DatabaseType = DataTypeDatabaseType.Nvarchar; - break; - case PropertyEditorValueTypes.IntegerType: - dataTypeDefinition.DatabaseType = DataTypeDatabaseType.Integer; - break; - case PropertyEditorValueTypes.DecimalType: - dataTypeDefinition.DatabaseType = DataTypeDatabaseType.Decimal; - break; - case PropertyEditorValueTypes.DateTimeType: - dataTypeDefinition.DatabaseType = DataTypeDatabaseType.Date; - break; - case PropertyEditorValueTypes.TextType: - dataTypeDefinition.DatabaseType = DataTypeDatabaseType.Ntext; - break; - } - } - } - /// /// Deletes an /// diff --git a/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs b/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs index eaa37b1f60..8fa332b108 100644 --- a/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs +++ b/src/Umbraco.Tests/PropertyEditors/PropertyEditorValueEditorTests.cs @@ -41,7 +41,7 @@ namespace Umbraco.Tests.PropertyEditors var valueEditor = new PropertyValueEditor { - ValueType = PropertyEditorValueTypes.StringType + ValueType = PropertyEditorValueTypes.String }; var result = valueEditor.ConvertDbToEditor(prop, prop.PropertyType, new Mock().Object); @@ -73,7 +73,7 @@ namespace Umbraco.Tests.PropertyEditors { var valueEditor = new PropertyValueEditor { - ValueType = PropertyEditorValueTypes.DecimalType + ValueType = PropertyEditorValueTypes.Decimal }; var result = valueEditor.TryConvertValueToCrlType("12.34"); @@ -86,7 +86,7 @@ namespace Umbraco.Tests.PropertyEditors { var valueEditor = new PropertyValueEditor { - ValueType = PropertyEditorValueTypes.DecimalType + ValueType = PropertyEditorValueTypes.Decimal }; var result = valueEditor.TryConvertValueToCrlType("12,34"); @@ -99,7 +99,7 @@ namespace Umbraco.Tests.PropertyEditors { var valueEditor = new PropertyValueEditor { - ValueType = PropertyEditorValueTypes.DecimalType + ValueType = PropertyEditorValueTypes.Decimal }; var result = valueEditor.TryConvertValueToCrlType(string.Empty); @@ -112,7 +112,7 @@ namespace Umbraco.Tests.PropertyEditors { var valueEditor = new PropertyValueEditor { - ValueType = PropertyEditorValueTypes.DateType + ValueType = PropertyEditorValueTypes.Date }; var result = valueEditor.TryConvertValueToCrlType("2010-02-05"); @@ -120,12 +120,12 @@ namespace Umbraco.Tests.PropertyEditors Assert.AreEqual(new DateTime(2010, 2, 5), result.Result); } - [TestCase(PropertyEditorValueTypes.StringType, "hello", "hello")] - [TestCase(PropertyEditorValueTypes.TextType, "hello", "hello")] - [TestCase(PropertyEditorValueTypes.IntegerType, 123, "123")] - [TestCase(PropertyEditorValueTypes.IntegerTypeAlternative, 123, "123")] - [TestCase(PropertyEditorValueTypes.IntegerType, "", "")] //test empty string for int - [TestCase(PropertyEditorValueTypes.DateTimeType, "", "")] //test empty string for date + [TestCase(PropertyEditorValueTypes.String, "hello", "hello")] + [TestCase(PropertyEditorValueTypes.Text, "hello", "hello")] + [TestCase(PropertyEditorValueTypes.Integer, 123, "123")] + [TestCase(PropertyEditorValueTypes.IntegerAlternative, 123, "123")] + [TestCase(PropertyEditorValueTypes.Integer, "", "")] //test empty string for int + [TestCase(PropertyEditorValueTypes.DateTime, "", "")] //test empty string for date public void Value_Editor_Can_Serialize_Value(string valueType, object val, string expected) { var prop = new Property(1, Guid.NewGuid(), new PropertyType("test", DataTypeDatabaseType.Nvarchar), val); @@ -145,7 +145,7 @@ namespace Umbraco.Tests.PropertyEditors var value = 12.34M; var valueEditor = new PropertyValueEditor { - ValueType = PropertyEditorValueTypes.DecimalType + ValueType = PropertyEditorValueTypes.Decimal }; var prop = new Property(1, Guid.NewGuid(), new PropertyType("test", DataTypeDatabaseType.Decimal), value); @@ -159,7 +159,7 @@ namespace Umbraco.Tests.PropertyEditors { var valueEditor = new PropertyValueEditor { - ValueType = PropertyEditorValueTypes.DecimalType + ValueType = PropertyEditorValueTypes.Decimal }; var prop = new Property(1, Guid.NewGuid(), new PropertyType("test", DataTypeDatabaseType.Decimal), string.Empty); @@ -174,7 +174,7 @@ namespace Umbraco.Tests.PropertyEditors var now = DateTime.Now; var valueEditor = new PropertyValueEditor { - ValueType = PropertyEditorValueTypes.DateType + ValueType = PropertyEditorValueTypes.Date }; var prop = new Property(1, Guid.NewGuid(), new PropertyType("test", DataTypeDatabaseType.Date), now); diff --git a/src/Umbraco.Web/PropertyEditors/ContentPickerPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/ContentPickerPropertyEditor.cs index 22c35e9b8c..4d58060164 100644 --- a/src/Umbraco.Web/PropertyEditors/ContentPickerPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/ContentPickerPropertyEditor.cs @@ -4,7 +4,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.ContentPickerAlias, "Content Picker", PropertyEditorValueTypes.IntegerType, "contentpicker", IsParameterEditor = true, Group = "Pickers")] + [PropertyEditor(Constants.PropertyEditors.ContentPickerAlias, "Content Picker", PropertyEditorValueTypes.Integer, "contentpicker", IsParameterEditor = true, Group = "Pickers")] public class ContentPickerPropertyEditor : PropertyEditor { diff --git a/src/Umbraco.Web/PropertyEditors/DatePropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/DatePropertyEditor.cs index 9cb8d5fec8..a98c96e759 100644 --- a/src/Umbraco.Web/PropertyEditors/DatePropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/DatePropertyEditor.cs @@ -9,7 +9,7 @@ using Umbraco.Core.Services; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.DateAlias, "Date", PropertyEditorValueTypes.DateType, "datepicker", Icon="icon-calendar")] + [PropertyEditor(Constants.PropertyEditors.DateAlias, "Date", PropertyEditorValueTypes.Date, "datepicker", Icon="icon-calendar")] public class DatePropertyEditor : PropertyEditor { public DatePropertyEditor() diff --git a/src/Umbraco.Web/PropertyEditors/DateTimePropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/DateTimePropertyEditor.cs index 1c6d7ce9d4..6291afd195 100644 --- a/src/Umbraco.Web/PropertyEditors/DateTimePropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/DateTimePropertyEditor.cs @@ -5,7 +5,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.DateTimeAlias, "Date/Time", "datepicker", ValueType = PropertyEditorValueTypes.DateTimeType, Icon="icon-time")] + [PropertyEditor(Constants.PropertyEditors.DateTimeAlias, "Date/Time", "datepicker", ValueType = PropertyEditorValueTypes.DateTime, Icon="icon-time")] public class DateTimePropertyEditor : PropertyEditor { public DateTimePropertyEditor() diff --git a/src/Umbraco.Web/PropertyEditors/DecimalPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/DecimalPropertyEditor.cs index 6a1a7d73a8..63c1964668 100644 --- a/src/Umbraco.Web/PropertyEditors/DecimalPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/DecimalPropertyEditor.cs @@ -3,7 +3,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.DecimalAlias, "Decimal", PropertyEditorValueTypes.DecimalType, "decimal", IsParameterEditor = true)] + [PropertyEditor(Constants.PropertyEditors.DecimalAlias, "Decimal", PropertyEditorValueTypes.Decimal, "decimal", IsParameterEditor = true)] public class DecimalPropertyEditor : PropertyEditor { /// diff --git a/src/Umbraco.Web/PropertyEditors/DropDownPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/DropDownPropertyEditor.cs index 4a6f5321b8..115b99dea4 100644 --- a/src/Umbraco.Web/PropertyEditors/DropDownPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/DropDownPropertyEditor.cs @@ -16,7 +16,7 @@ namespace Umbraco.Web.PropertyEditors /// as INT and we have logic in here to ensure it is formatted correctly including ensuring that the string value is published /// in cache and not the int ID. /// - [PropertyEditor(Constants.PropertyEditors.DropDownListAlias, "Dropdown list", "dropdown", ValueType = PropertyEditorValueTypes.StringType, Group = "lists", Icon = "icon-indent")] + [PropertyEditor(Constants.PropertyEditors.DropDownListAlias, "Dropdown list", "dropdown", ValueType = PropertyEditorValueTypes.String, Group = "lists", Icon = "icon-indent")] public class DropDownPropertyEditor : DropDownWithKeysPropertyEditor { /// diff --git a/src/Umbraco.Web/PropertyEditors/DropDownWithKeysPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/DropDownWithKeysPropertyEditor.cs index 6c947f4bad..a33115003c 100644 --- a/src/Umbraco.Web/PropertyEditors/DropDownWithKeysPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/DropDownWithKeysPropertyEditor.cs @@ -11,7 +11,7 @@ namespace Umbraco.Web.PropertyEditors /// as INT and we have logic in here to ensure it is formatted correctly including ensuring that the INT ID value is published /// in cache and not the string value. /// - [PropertyEditor(Constants.PropertyEditors.DropdownlistPublishingKeysAlias, "Dropdown list, publishing keys", "dropdown", ValueType = PropertyEditorValueTypes.IntegerType, Group = "lists", Icon = "icon-indent")] + [PropertyEditor(Constants.PropertyEditors.DropdownlistPublishingKeysAlias, "Dropdown list, publishing keys", "dropdown", ValueType = PropertyEditorValueTypes.Integer, Group = "lists", Icon = "icon-indent")] public class DropDownWithKeysPropertyEditor : PropertyEditor { diff --git a/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs index 96ae6a1247..6178a4f9a4 100644 --- a/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs @@ -16,7 +16,7 @@ using UmbracoExamine; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Core.Constants.PropertyEditors.GridAlias, "Grid layout", "grid", HideLabel = true, IsParameterEditor = false, ValueType = PropertyEditorValueTypes.JsonType, Group="rich content", Icon="icon-layout")] + [PropertyEditor(Core.Constants.PropertyEditors.GridAlias, "Grid layout", "grid", HideLabel = true, IsParameterEditor = false, ValueType = PropertyEditorValueTypes.Json, Group="rich content", Icon="icon-layout")] public class GridPropertyEditor : PropertyEditor { /// diff --git a/src/Umbraco.Web/PropertyEditors/ImageCropperPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/ImageCropperPropertyEditor.cs index b4fa34a670..1072448628 100644 --- a/src/Umbraco.Web/PropertyEditors/ImageCropperPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/ImageCropperPropertyEditor.cs @@ -15,7 +15,7 @@ using Umbraco.Core.Services; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.ImageCropperAlias, "Image Cropper", "imagecropper", ValueType = PropertyEditorValueTypes.JsonType, HideLabel = false, Group="media", Icon="icon-crop")] + [PropertyEditor(Constants.PropertyEditors.ImageCropperAlias, "Image Cropper", "imagecropper", ValueType = PropertyEditorValueTypes.Json, HideLabel = false, Group="media", Icon="icon-crop")] public class ImageCropperPropertyEditor : PropertyEditor { diff --git a/src/Umbraco.Web/PropertyEditors/IntegerPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/IntegerPropertyEditor.cs index f569905810..026aaf115f 100644 --- a/src/Umbraco.Web/PropertyEditors/IntegerPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/IntegerPropertyEditor.cs @@ -3,7 +3,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.IntegerAlias, "Numeric", "integer", IsParameterEditor = true, ValueType = PropertyEditorValueTypes.IntegerTypeAlternative)] + [PropertyEditor(Constants.PropertyEditors.IntegerAlias, "Numeric", "integer", IsParameterEditor = true, ValueType = PropertyEditorValueTypes.IntegerAlternative)] public class IntegerPropertyEditor : PropertyEditor { /// diff --git a/src/Umbraco.Web/PropertyEditors/LabelPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/LabelPropertyEditor.cs index fab9d0bba3..c5482695a3 100644 --- a/src/Umbraco.Web/PropertyEditors/LabelPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/LabelPropertyEditor.cs @@ -19,7 +19,7 @@ namespace Umbraco.Web.PropertyEditors { return new LabelPreValueEditor(); } - + /// /// Custom value editor to mark it as readonly /// @@ -52,10 +52,10 @@ namespace Umbraco.Web.PropertyEditors Key = LegacyPropertyEditorValuesKey }); - ValueType = PropertyEditorValueTypes.StringType; + ValueType = PropertyEditorValueTypes.String; } - [PreValueField(Constants.PropertyEditors.DataValueTypePreValueKey, "Value type", "valuetype")] + [PreValueField(Constants.PropertyEditors.PreValueKeys.DataValueType, "Value type", "valuetype")] public string ValueType { get; set; } /// @@ -70,23 +70,23 @@ namespace Umbraco.Web.PropertyEditors var existing = base.ConvertDbToEditor(defaultPreVals, persistedPreVals); // Check for a saved value type. If not found set to default string type. - var valueType = PropertyEditorValueTypes.StringType; - if (existing.ContainsKey(Constants.PropertyEditors.DataValueTypePreValueKey)) + var valueType = PropertyEditorValueTypes.String; + if (existing.ContainsKey(Constants.PropertyEditors.PreValueKeys.DataValueType)) { - valueType = (string)existing[Constants.PropertyEditors.DataValueTypePreValueKey]; + valueType = (string)existing[Constants.PropertyEditors.PreValueKeys.DataValueType]; } // Convert any other values from a legacy property editor to a list, easier to enumerate on the editor. // Make sure to exclude values defined on the label property editor itself. var asList = existing .Select(e => new KeyValuePair(e.Key, e.Value)) - .Where(e => e.Key != Constants.PropertyEditors.DataValueTypePreValueKey) + .Where(e => e.Key != Constants.PropertyEditors.PreValueKeys.DataValueType) .ToList(); - var result = new Dictionary { { Constants.PropertyEditors.DataValueTypePreValueKey, valueType } }; + var result = new Dictionary { { Constants.PropertyEditors.PreValueKeys.DataValueType, valueType } }; if (asList.Any()) { - result.Add("values", asList); + result.Add(LegacyPropertyEditorValuesKey, asList); } return result; @@ -100,6 +100,20 @@ namespace Umbraco.Web.PropertyEditors /// public override IDictionary ConvertEditorToDb(IDictionary editorValue, PreValueCollection currentValue) { + // notes (from the PR): + // + // "All stemmed from the fact that even though the label property editor could have pre-values (from a legacy type), + // they couldn't up to now be edited and saved through the UI. Now that a "true" pre-value has been added, it can, + // which led to some odd behaviour. + // + // Firstly there would be a pre-value record saved for legacy values even if there aren't any (the key would exist + // but with no value). In that case I remove that pre-value so it's not saved(likely does no harm, but it's not + // necessary - we only need this legacy values pre-value record if there are any). + // + // Secondly if there are legacy values, I found on each save the JSON structure containing them would get repeatedly + // nested (an outer JSON wrapper would be added each time). So what I'm doing is if there are legacy pre-values, + // I'm converting what comes in "wrapped" like (below) into the legacy property editor values." + if (editorValue.ContainsKey(LegacyPropertyEditorValuesKey)) { // If provided value contains an empty legacy property editor values, don't save it @@ -110,8 +124,8 @@ namespace Umbraco.Web.PropertyEditors else { // If provided value contains legacy property editor values, unwrap the value to save so it doesn't get repeatedly nested on saves. - // This is a bit funky - but basically needing to parse out the original value from a JSON structure that is passed in - // looking like: + // This is a bit funky - but basically needing to parse out the original value from a JSON structure that is passed in + // looking like: // Value = {[ // { // "Key": "values", diff --git a/src/Umbraco.Web/PropertyEditors/MacroContainerPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/MacroContainerPropertyEditor.cs index ffe42b8603..3ac5788dd2 100644 --- a/src/Umbraco.Web/PropertyEditors/MacroContainerPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/MacroContainerPropertyEditor.cs @@ -9,7 +9,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.MacroContainerAlias, "Macro container", "macrocontainer", ValueType = PropertyEditorValueTypes.TextType, Group="rich content", Icon="icon-settings-alt")] + [PropertyEditor(Constants.PropertyEditors.MacroContainerAlias, "Macro container", "macrocontainer", ValueType = PropertyEditorValueTypes.Text, Group="rich content", Icon="icon-settings-alt")] public class MacroContainerPropertyEditor : PropertyEditor { /// diff --git a/src/Umbraco.Web/PropertyEditors/MarkdownPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/MarkdownPropertyEditor.cs index 1da9ac57c6..9fa8f2d588 100644 --- a/src/Umbraco.Web/PropertyEditors/MarkdownPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/MarkdownPropertyEditor.cs @@ -3,7 +3,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.MarkdownEditorAlias, "Markdown editor", "markdowneditor", ValueType = PropertyEditorValueTypes.TextType, Icon="icon-code", Group="rich content")] + [PropertyEditor(Constants.PropertyEditors.MarkdownEditorAlias, "Markdown editor", "markdowneditor", ValueType = PropertyEditorValueTypes.Text, Icon="icon-code", Group="rich content")] public class MarkdownPropertyEditor : PropertyEditor { protected override PreValueEditor CreatePreValueEditor() diff --git a/src/Umbraco.Web/PropertyEditors/MediaPickerPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/MediaPickerPropertyEditor.cs index d9a86da778..7e966d31ad 100644 --- a/src/Umbraco.Web/PropertyEditors/MediaPickerPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/MediaPickerPropertyEditor.cs @@ -9,7 +9,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.MediaPickerAlias, "Legacy Media Picker", PropertyEditorValueTypes.IntegerType, "mediapicker", Group="media", Icon="icon-picture")] + [PropertyEditor(Constants.PropertyEditors.MediaPickerAlias, "Legacy Media Picker", PropertyEditorValueTypes.Integer, "mediapicker", Group="media", Icon="icon-picture")] public class MediaPickerPropertyEditor : PropertyEditor { public MediaPickerPropertyEditor() diff --git a/src/Umbraco.Web/PropertyEditors/MemberPickerPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/MemberPickerPropertyEditor.cs index b35e4f7675..7dadbfe24c 100644 --- a/src/Umbraco.Web/PropertyEditors/MemberPickerPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/MemberPickerPropertyEditor.cs @@ -8,7 +8,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.MemberPickerAlias, "Member Picker", PropertyEditorValueTypes.IntegerType, "memberpicker", Group = "People", Icon = "icon-user")] + [PropertyEditor(Constants.PropertyEditors.MemberPickerAlias, "Member Picker", PropertyEditorValueTypes.Integer, "memberpicker", Group = "People", Icon = "icon-user")] public class MemberPickerPropertyEditor : PropertyEditor { } diff --git a/src/Umbraco.Web/PropertyEditors/MultipleTextStringPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/MultipleTextStringPropertyEditor.cs index 81885c8c55..96288c9857 100644 --- a/src/Umbraco.Web/PropertyEditors/MultipleTextStringPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/MultipleTextStringPropertyEditor.cs @@ -14,7 +14,7 @@ using Umbraco.Core.Services; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.MultipleTextstringAlias, "Repeatable textstrings", "multipletextbox", ValueType = PropertyEditorValueTypes.TextType, Icon="icon-ordered-list", Group="lists")] + [PropertyEditor(Constants.PropertyEditors.MultipleTextstringAlias, "Repeatable textstrings", "multipletextbox", ValueType = PropertyEditorValueTypes.Text, Icon="icon-ordered-list", Group="lists")] public class MultipleTextStringPropertyEditor : PropertyEditor { protected override PropertyValueEditor CreateValueEditor() diff --git a/src/Umbraco.Web/PropertyEditors/RadioButtonsPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/RadioButtonsPropertyEditor.cs index 7704a4c178..2bcd8fcbd8 100644 --- a/src/Umbraco.Web/PropertyEditors/RadioButtonsPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/RadioButtonsPropertyEditor.cs @@ -11,7 +11,7 @@ namespace Umbraco.Web.PropertyEditors /// as INT and we have logic in here to ensure it is formatted correctly including ensuring that the INT ID value is published /// in cache and not the string value. /// - [PropertyEditor(Constants.PropertyEditors.RadioButtonListAlias, "Radio button list", "radiobuttons", ValueType = PropertyEditorValueTypes.IntegerType, Group="lists", Icon="icon-target")] + [PropertyEditor(Constants.PropertyEditors.RadioButtonListAlias, "Radio button list", "radiobuttons", ValueType = PropertyEditorValueTypes.Integer, Group="lists", Icon="icon-target")] public class RadioButtonsPropertyEditor : DropDownWithKeysPropertyEditor { diff --git a/src/Umbraco.Web/PropertyEditors/RelatedLinksPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/RelatedLinksPropertyEditor.cs index 61faa6827f..cf9d4100a4 100644 --- a/src/Umbraco.Web/PropertyEditors/RelatedLinksPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/RelatedLinksPropertyEditor.cs @@ -8,7 +8,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.RelatedLinksAlias, "Related links", "relatedlinks", ValueType = PropertyEditorValueTypes.JsonType, Icon="icon-thumbnail-list", Group="pickers")] + [PropertyEditor(Constants.PropertyEditors.RelatedLinksAlias, "Related links", "relatedlinks", ValueType = PropertyEditorValueTypes.Json, Icon="icon-thumbnail-list", Group="pickers")] public class RelatedLinksPropertyEditor : PropertyEditor { protected override PreValueEditor CreatePreValueEditor() diff --git a/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs index e069d09783..de65a326f7 100644 --- a/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/RichTextPropertyEditor.cs @@ -7,7 +7,7 @@ using Umbraco.Core.Services; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.TinyMCEAlias, "Rich Text Editor", "rte", ValueType = PropertyEditorValueTypes.TextType, HideLabel = false, Group="Rich Content", Icon="icon-browser-window")] + [PropertyEditor(Constants.PropertyEditors.TinyMCEAlias, "Rich Text Editor", "rte", ValueType = PropertyEditorValueTypes.Text, HideLabel = false, Group="Rich Content", Icon="icon-browser-window")] public class RichTextPropertyEditor : PropertyEditor { /// diff --git a/src/Umbraco.Web/PropertyEditors/TextAreaPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/TextAreaPropertyEditor.cs index 3f7c6559b8..3bec23f004 100644 --- a/src/Umbraco.Web/PropertyEditors/TextAreaPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/TextAreaPropertyEditor.cs @@ -3,7 +3,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.TextboxMultipleAlias, "Textarea", "textarea", IsParameterEditor = true, ValueType = PropertyEditorValueTypes.TextType, Icon="icon-application-window-alt")] + [PropertyEditor(Constants.PropertyEditors.TextboxMultipleAlias, "Textarea", "textarea", IsParameterEditor = true, ValueType = PropertyEditorValueTypes.Text, Icon="icon-application-window-alt")] public class TextAreaPropertyEditor : PropertyEditor { } diff --git a/src/Umbraco.Web/PropertyEditors/TrueFalsePropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/TrueFalsePropertyEditor.cs index 012167a99c..0dc181cbc3 100644 --- a/src/Umbraco.Web/PropertyEditors/TrueFalsePropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/TrueFalsePropertyEditor.cs @@ -3,7 +3,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.TrueFalseAlias, "True/False", PropertyEditorValueTypes.IntegerType, "boolean", IsParameterEditor = true, Group = "Common", Icon="icon-checkbox")] + [PropertyEditor(Constants.PropertyEditors.TrueFalseAlias, "True/False", PropertyEditorValueTypes.Integer, "boolean", IsParameterEditor = true, Group = "Common", Icon="icon-checkbox")] public class TrueFalsePropertyEditor : PropertyEditor { protected override PreValueEditor CreatePreValueEditor() diff --git a/src/Umbraco.Web/PropertyEditors/UserPickerPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/UserPickerPropertyEditor.cs index 4c08b26770..e4a070cb29 100644 --- a/src/Umbraco.Web/PropertyEditors/UserPickerPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/UserPickerPropertyEditor.cs @@ -6,7 +6,7 @@ using Umbraco.Core.PropertyEditors; namespace Umbraco.Web.PropertyEditors { - [PropertyEditor(Constants.PropertyEditors.UserPickerAlias, "User picker", PropertyEditorValueTypes.IntegerType, "entitypicker", Group="People", Icon="icon-user")] + [PropertyEditor(Constants.PropertyEditors.UserPickerAlias, "User picker", PropertyEditorValueTypes.Integer, "entitypicker", Group="People", Icon="icon-user")] public class UserPickerPropertyEditor : PropertyEditor { private IDictionary _defaultPreValues; From b69580967e8b247893782541107305e28d071c63 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 24 May 2016 16:12:54 +0200 Subject: [PATCH 070/535] Updates interceptor files with correct module usage - creates new request interceptor to append a custom Time-Offset header --- .../src/common/security/_module.js | 8 +- .../src/common/security/requestinterceptor.js | 26 +++ .../src/common/security/retryqueue.js | 1 + ...{interceptor.js => securityinterceptor.js} | 188 +++++++++--------- 4 files changed, 125 insertions(+), 98 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/common/security/requestinterceptor.js rename src/Umbraco.Web.UI.Client/src/common/security/{interceptor.js => securityinterceptor.js} (96%) diff --git a/src/Umbraco.Web.UI.Client/src/common/security/_module.js b/src/Umbraco.Web.UI.Client/src/common/security/_module.js index 15a7663d9b..c8289c754e 100644 --- a/src/Umbraco.Web.UI.Client/src/common/security/_module.js +++ b/src/Umbraco.Web.UI.Client/src/common/security/_module.js @@ -1,4 +1,4 @@ -// Based loosely around work by Witold Szczerba - https://github.com/witoldsz/angular-http-auth -angular.module('umbraco.security', [ - 'umbraco.security.retryQueue', - 'umbraco.security.interceptor']); \ No newline at end of file +//TODO: This is silly and unecessary to have a separate module for this +angular.module('umbraco.security.retryQueue', []); +angular.module('umbraco.security.interceptor', ['umbraco.security.retryQueue']); +angular.module('umbraco.security', ['umbraco.security.retryQueue', 'umbraco.security.interceptor']); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/security/requestinterceptor.js b/src/Umbraco.Web.UI.Client/src/common/security/requestinterceptor.js new file mode 100644 index 0000000000..8557ce1435 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/security/requestinterceptor.js @@ -0,0 +1,26 @@ +angular.module('umbraco.security.interceptor').factory("requestInterceptor", + ['$q', 'requestInterceptorFilter', function ($q, requestInterceptorFilter) { + var requestInterceptor = { + request: function (config) { + + var filtered = _.find(requestInterceptorFilter(), function (val) { + return config.url.indexOf(val) > 0; + }); + if (filtered) { + return config; + } + + config.headers["Time-Offset"] = (new Date().getTimezoneOffset()); + return config; + } + }; + + return requestInterceptor; + } + ]) + // We have to add the interceptor to the queue as a string because the interceptor depends upon service instances that are not available in the config block. + .config([ + '$httpProvider', function($httpProvider) { + $httpProvider.interceptors.push('requestInterceptor'); + } + ]); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/security/retryqueue.js b/src/Umbraco.Web.UI.Client/src/common/security/retryqueue.js index e971719398..28d91dd610 100644 --- a/src/Umbraco.Web.UI.Client/src/common/security/retryqueue.js +++ b/src/Umbraco.Web.UI.Client/src/common/security/retryqueue.js @@ -1,3 +1,4 @@ +//TODO: This is silly and unecessary to have a separate module for this angular.module('umbraco.security.retryQueue', []) // This is a generic retry queue for security failures. Each item is expected to expose two functions: retry and cancel. diff --git a/src/Umbraco.Web.UI.Client/src/common/security/interceptor.js b/src/Umbraco.Web.UI.Client/src/common/security/securityinterceptor.js similarity index 96% rename from src/Umbraco.Web.UI.Client/src/common/security/interceptor.js rename to src/Umbraco.Web.UI.Client/src/common/security/securityinterceptor.js index 2b757707ba..b80754ef67 100644 --- a/src/Umbraco.Web.UI.Client/src/common/security/interceptor.js +++ b/src/Umbraco.Web.UI.Client/src/common/security/securityinterceptor.js @@ -1,95 +1,95 @@ -angular.module('umbraco.security.interceptor', ['umbraco.security.retryQueue']) - // This http interceptor listens for authentication successes and failures - .factory('securityInterceptor', ['$injector', 'securityRetryQueue', 'notificationsService', 'requestInterceptorFilter', function ($injector, queue, notifications, requestInterceptorFilter) { - return function(promise) { - - return promise.then( - function(originalResponse) { - // Intercept successful requests - - //Here we'll check if our custom header is in the response which indicates how many seconds the user's session has before it - //expires. Then we'll update the user in the user service accordingly. - var headers = originalResponse.headers(); - if (headers["x-umb-user-seconds"]) { - // We must use $injector to get the $http service to prevent circular dependency - var userService = $injector.get('userService'); - userService.setUserTimeout(headers["x-umb-user-seconds"]); - } - - return promise; - }, function(originalResponse) { - // Intercept failed requests - - //Here we'll check if we should ignore the error, this will be based on an original header set - var headers = originalResponse.config ? originalResponse.config.headers : {}; - if (headers["x-umb-ignore-error"] === "ignore") { - //exit/ignore - return promise; - } - var filtered = _.find(requestInterceptorFilter(), function(val) { - return originalResponse.config.url.indexOf(val) > 0; - }); - if (filtered) { - return promise; - } - - //A 401 means that the user is not logged in - if (originalResponse.status === 401) { - - // The request bounced because it was not authorized - add a new request to the retry queue - promise = queue.pushRetryFn('unauthorized-server', function retryRequest() { - // We must use $injector to get the $http service to prevent circular dependency - return $injector.get('$http')(originalResponse.config); - }); - } - else if (originalResponse.status === 404) { - - //a 404 indicates that the request was not found - this could be due to a non existing url, or it could - //be due to accessing a url with a parameter that doesn't exist, either way we should notifiy the user about it - - var errMsg = "The URL returned a 404 (not found):
    " + originalResponse.config.url.split('?')[0] + ""; - if (originalResponse.data && originalResponse.data.ExceptionMessage) { - errMsg += "
    with error:
    " + originalResponse.data.ExceptionMessage + ""; - } - if (originalResponse.config.data) { - errMsg += "
    with data:
    " + angular.toJson(originalResponse.config.data) + "
    Contact your administrator for information."; - } - - notifications.error( - "Request error", - errMsg); - - } - else if (originalResponse.status === 403) { - //if the status was a 403 it means the user didn't have permission to do what the request was trying to do. - //How do we deal with this now, need to tell the user somehow that they don't have permission to do the thing that was - //requested. We can either deal with this globally here, or we can deal with it globally for individual requests on the umbRequestHelper, - // or completely custom for services calling resources. - - //http://issues.umbraco.org/issue/U4-2749 - - //It was decided to just put these messages into the normal status messages. - - var msg = "Unauthorized access to URL:
    " + originalResponse.config.url.split('?')[0] + ""; - if (originalResponse.config.data) { - msg += "
    with data:
    " + angular.toJson(originalResponse.config.data) + "
    Contact your administrator for information."; - } - - notifications.error( - "Authorization error", - msg); - } - - return promise; - }); - }; - }]) - - .value('requestInterceptorFilter', function() { - return ["www.gravatar.com"]; - }) - - // We have to add the interceptor to the queue as a string because the interceptor depends upon service instances that are not available in the config block. - .config(['$httpProvider', function ($httpProvider) { - $httpProvider.responseInterceptors.push('securityInterceptor'); +angular.module('umbraco.security.interceptor') + // This http interceptor listens for authentication successes and failures + .factory('securityInterceptor', ['$injector', 'securityRetryQueue', 'notificationsService', 'requestInterceptorFilter', function ($injector, queue, notifications, requestInterceptorFilter) { + return function(promise) { + + return promise.then( + function(originalResponse) { + // Intercept successful requests + + //Here we'll check if our custom header is in the response which indicates how many seconds the user's session has before it + //expires. Then we'll update the user in the user service accordingly. + var headers = originalResponse.headers(); + if (headers["x-umb-user-seconds"]) { + // We must use $injector to get the $http service to prevent circular dependency + var userService = $injector.get('userService'); + userService.setUserTimeout(headers["x-umb-user-seconds"]); + } + + return promise; + }, function(originalResponse) { + // Intercept failed requests + + //Here we'll check if we should ignore the error, this will be based on an original header set + var headers = originalResponse.config ? originalResponse.config.headers : {}; + if (headers["x-umb-ignore-error"] === "ignore") { + //exit/ignore + return promise; + } + var filtered = _.find(requestInterceptorFilter(), function(val) { + return originalResponse.config.url.indexOf(val) > 0; + }); + if (filtered) { + return promise; + } + + //A 401 means that the user is not logged in + if (originalResponse.status === 401) { + + // The request bounced because it was not authorized - add a new request to the retry queue + promise = queue.pushRetryFn('unauthorized-server', function retryRequest() { + // We must use $injector to get the $http service to prevent circular dependency + return $injector.get('$http')(originalResponse.config); + }); + } + else if (originalResponse.status === 404) { + + //a 404 indicates that the request was not found - this could be due to a non existing url, or it could + //be due to accessing a url with a parameter that doesn't exist, either way we should notifiy the user about it + + var errMsg = "The URL returned a 404 (not found):
    " + originalResponse.config.url.split('?')[0] + ""; + if (originalResponse.data && originalResponse.data.ExceptionMessage) { + errMsg += "
    with error:
    " + originalResponse.data.ExceptionMessage + ""; + } + if (originalResponse.config.data) { + errMsg += "
    with data:
    " + angular.toJson(originalResponse.config.data) + "
    Contact your administrator for information."; + } + + notifications.error( + "Request error", + errMsg); + + } + else if (originalResponse.status === 403) { + //if the status was a 403 it means the user didn't have permission to do what the request was trying to do. + //How do we deal with this now, need to tell the user somehow that they don't have permission to do the thing that was + //requested. We can either deal with this globally here, or we can deal with it globally for individual requests on the umbRequestHelper, + // or completely custom for services calling resources. + + //http://issues.umbraco.org/issue/U4-2749 + + //It was decided to just put these messages into the normal status messages. + + var msg = "Unauthorized access to URL:
    " + originalResponse.config.url.split('?')[0] + ""; + if (originalResponse.config.data) { + msg += "
    with data:
    " + angular.toJson(originalResponse.config.data) + "
    Contact your administrator for information."; + } + + notifications.error( + "Authorization error", + msg); + } + + return promise; + }); + }; + }]) + + .value('requestInterceptorFilter', function() { + return ["www.gravatar.com"]; + }) + + // We have to add the interceptor to the queue as a string because the interceptor depends upon service instances that are not available in the config block. + .config(['$httpProvider', function ($httpProvider) { + $httpProvider.responseInterceptors.push('securityInterceptor'); }]); \ No newline at end of file From 6cb817fc0147950383782dba34ec365e1d2fa804 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Tue, 24 May 2016 16:20:20 +0200 Subject: [PATCH 071/535] U4-7332 Default gravatar link broken --- .../src/controllers/main.controller.js | 74 ++++++++++--------- .../Editors/BackOfficeController.cs | 4 + src/Umbraco.Web/Editors/GravatarController.cs | 38 ++++++++++ src/Umbraco.Web/Umbraco.Web.csproj | 1 + 4 files changed, 81 insertions(+), 36 deletions(-) create mode 100644 src/Umbraco.Web/Editors/GravatarController.cs diff --git a/src/Umbraco.Web.UI.Client/src/controllers/main.controller.js b/src/Umbraco.Web.UI.Client/src/controllers/main.controller.js index 42d50b1ce7..0d3b56991e 100644 --- a/src/Umbraco.Web.UI.Client/src/controllers/main.controller.js +++ b/src/Umbraco.Web.UI.Client/src/controllers/main.controller.js @@ -19,7 +19,7 @@ function MainController($scope, $rootScope, $location, $routeParams, $timeout, $ { value: "assets/img/application/logo@3x.png" } ]; $scope.touchDevice = appState.getGlobalState("touchDevice"); - + $scope.removeNotification = function (index) { notificationsService.remove(index); @@ -28,12 +28,12 @@ function MainController($scope, $rootScope, $location, $routeParams, $timeout, $ $scope.closeDialogs = function (event) { //only close dialogs if non-link and non-buttons are clicked var el = event.target.nodeName; - var els = ["INPUT","A","BUTTON"]; + var els = ["INPUT", "A", "BUTTON"]; - if(els.indexOf(el) >= 0){return;} + if (els.indexOf(el) >= 0) { return; } var parents = $(event.target).parents("a,button"); - if(parents.length > 0){ + if (parents.length > 0) { return; } @@ -49,31 +49,31 @@ function MainController($scope, $rootScope, $location, $routeParams, $timeout, $ var evts = []; //when a user logs out or timesout - evts.push(eventsService.on("app.notAuthenticated", function() { + evts.push(eventsService.on("app.notAuthenticated", function () { $scope.authenticated = null; $scope.user = null; })); - + //when the app is read/user is logged in, setup the data evts.push(eventsService.on("app.ready", function (evt, data) { - + $scope.authenticated = data.authenticated; $scope.user = data.user; - updateChecker.check().then(function(update){ - if(update && update !== "null"){ - if(update.type !== "None"){ + updateChecker.check().then(function(update) { + if (update && update !== "null") { + if (update.type !== "None") { var notification = { - headline: "Update available", - message: "Click to download", - sticky: true, - type: "info", - url: update.url + headline: "Update available", + message: "Click to download", + sticky: true, + type: "info", + url: update.url }; notificationsService.add(notification); } } - }) + }); //if the user has changed we need to redirect to the root so they don't try to continue editing the //last item in the URL (NOTE: the user id can equal zero, so we cannot just do !data.lastUserId since that will resolve to true) @@ -91,38 +91,40 @@ function MainController($scope, $rootScope, $location, $routeParams, $timeout, $ if ($scope.user.emailHash) { //let's attempt to load the avatar, it might not exist or we might not have - // internet access so we'll detect it first - $http.get("https://www.gravatar.com/avatar/" + $scope.user.emailHash + ".jpg?s=64&d=404") + // internet access, well get an empty string back + $http.get(umbRequestHelper.getApiUrl("gravatarApiBaseUrl", "GetCurrentUserGravatarUrl")) .then( - function successCallback(response) { - $("#avatar-img").fadeTo(1000, 0, function () { - $scope.$apply(function () { - //this can be null if they time out - if ($scope.user && $scope.user.emailHash) { - var avatarBaseUrl = "https://www.gravatar.com/avatar/", - hash = $scope.user.emailHash; + function successCallback(response) { + // if we can't download the gravatar for some reason, an null gets returned, we cannot do anything + if (response.data !== "null") { + $("#avatar-img").fadeTo(1000, 0, function () { + $scope.$apply(function () { + //this can be null if they time out + if ($scope.user && $scope.user.emailHash) { + var avatarBaseUrl = "https://www.gravatar.com/avatar/", + hash = $scope.user.emailHash; - $scope.avatar = [ - { value: avatarBaseUrl + hash + ".jpg?s=30&d=mm" }, - { value: avatarBaseUrl + hash + ".jpg?s=60&d=mm" }, - { value: avatarBaseUrl + hash + ".jpg?s=90&d=mm" } - ]; - } + $scope.avatar = [ + { value: avatarBaseUrl + hash + ".jpg?s=30&d=mm" }, + { value: avatarBaseUrl + hash + ".jpg?s=60&d=mm" }, + { value: avatarBaseUrl + hash + ".jpg?s=90&d=mm" } + ]; + } + }); + $("#avatar-img").fadeTo(1000, 1); }); - $("#avatar-img").fadeTo(1000, 1); - }); + } }, function errorCallback(response) { //cannot load it from the server so we cannot do anything }); } - })); - evts.push(eventsService.on("app.ysod", function(name, error) { + evts.push(eventsService.on("app.ysod", function (name, error) { $scope.ysodOverlay = { view: "ysod", error: error, - show: true + show: true }; })); diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs index b5cea7a945..95e1f7803e 100644 --- a/src/Umbraco.Web/Editors/BackOfficeController.cs +++ b/src/Umbraco.Web/Editors/BackOfficeController.cs @@ -291,6 +291,10 @@ namespace Umbraco.Web.Editors "logApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl( controller => controller.GetEntityLog(0)) }, + { + "gravatarApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl( + controller => controller.GetCurrentUserGravatarUrl()) + }, { "memberApiBaseUrl", Url.GetUmbracoApiServiceBaseUrl( controller => controller.GetByKey(Guid.Empty)) diff --git a/src/Umbraco.Web/Editors/GravatarController.cs b/src/Umbraco.Web/Editors/GravatarController.cs new file mode 100644 index 0000000000..f1e184dce7 --- /dev/null +++ b/src/Umbraco.Web/Editors/GravatarController.cs @@ -0,0 +1,38 @@ +using System; +using System.Net; +using Umbraco.Core; +using Umbraco.Web.Mvc; + +namespace Umbraco.Web.Editors +{ + /// + /// API controller used for getting Gravatar urls + /// + [PluginController("UmbracoApi")] + public class GravatarController : UmbracoAuthorizedJsonController + { + public string GetCurrentUserGravatarUrl() + { + var userService = Services.UserService; + var user = userService.GetUserById(UmbracoContext.Security.CurrentUser.Id); + var gravatarHash = user.Email.ToMd5(); + var gravatarUrl = "https://www.gravatar.com/avatar/" + gravatarHash; + + // Test if we can reach this URL, will fail when there's network or firewall errors + var request = (HttpWebRequest)WebRequest.Create(gravatarUrl); + // Require response within 10 seconds + request.Timeout = 10000; + try + { + using ((HttpWebResponse)request.GetResponse()) { } + } + catch (Exception) + { + // There was an HTTP or other error, return an null instead + return null; + } + + return gravatarUrl; + } + } +} diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 48005b1209..de4b49bc77 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -318,6 +318,7 @@ + From 1fc17e6f46db1c6f4114195e2558ceeb591e8dfa Mon Sep 17 00:00:00 2001 From: Jeroen Breuer Date: Tue, 24 May 2016 17:04:39 +0200 Subject: [PATCH 072/535] Fix for U4-8510 --- .../ValueConverters/MultipleTextStringValueConverter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Core/PropertyEditors/ValueConverters/MultipleTextStringValueConverter.cs b/src/Umbraco.Core/PropertyEditors/ValueConverters/MultipleTextStringValueConverter.cs index 39bcf85b12..a3b12a6688 100644 --- a/src/Umbraco.Core/PropertyEditors/ValueConverters/MultipleTextStringValueConverter.cs +++ b/src/Umbraco.Core/PropertyEditors/ValueConverters/MultipleTextStringValueConverter.cs @@ -28,7 +28,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters // // - var sourceString = source.ToString(); + var sourceString = source != null ? source.ToString() : null; if (string.IsNullOrWhiteSpace(sourceString)) return Enumerable.Empty(); //SD: I have no idea why this logic is here, I'm pretty sure we've never saved the multiple txt string From 2504586c267c114815f478a9fcf287f2eda65047 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 25 May 2016 09:43:31 +0200 Subject: [PATCH 073/535] removes initial idea of performing conversion on the server since this would be a breaking change, instead we can easily do this on the client side - and this works much better. Have added pre-values to the date/time picker to be able to enable offset times. This is enabled for the publish-at pickers since those must be offset. When the datetime is offset, it shows the server time in small text underneath the picker. Have added js unit tests for the date conversions. Have updated the datepicker controller to set the model date in a single place/method so it's consistent. --- .../src/common/security/requestinterceptor.js | 26 ------- .../src/common/services/util.service.js | 38 ++++++++++ .../datepicker/datepicker.controller.js | 76 ++++++++++++------- .../datepicker/datepicker.html | 3 + .../test/config/karma.conf.js | 1 + .../unit/common/services/date-helper.spec.js | 53 +++++++++++++ .../Editors/BackOfficeController.cs | 4 + .../Editors/ContentControllerBase.cs | 5 +- .../Models/Mapping/ContentModelMapper.cs | 12 ++- .../PropertyEditors/DateTimePreValueEditor.cs | 10 +++ .../PropertyEditors/DateTimePropertyEditor.cs | 13 +++- src/Umbraco.Web/Umbraco.Web.csproj | 1 + .../WebApi/Binders/ContentItemBaseBinder.cs | 12 ++- 13 files changed, 190 insertions(+), 64 deletions(-) delete mode 100644 src/Umbraco.Web.UI.Client/src/common/security/requestinterceptor.js create mode 100644 src/Umbraco.Web.UI.Client/test/unit/common/services/date-helper.spec.js create mode 100644 src/Umbraco.Web/PropertyEditors/DateTimePreValueEditor.cs diff --git a/src/Umbraco.Web.UI.Client/src/common/security/requestinterceptor.js b/src/Umbraco.Web.UI.Client/src/common/security/requestinterceptor.js deleted file mode 100644 index 8557ce1435..0000000000 --- a/src/Umbraco.Web.UI.Client/src/common/security/requestinterceptor.js +++ /dev/null @@ -1,26 +0,0 @@ -angular.module('umbraco.security.interceptor').factory("requestInterceptor", - ['$q', 'requestInterceptorFilter', function ($q, requestInterceptorFilter) { - var requestInterceptor = { - request: function (config) { - - var filtered = _.find(requestInterceptorFilter(), function (val) { - return config.url.indexOf(val) > 0; - }); - if (filtered) { - return config; - } - - config.headers["Time-Offset"] = (new Date().getTimezoneOffset()); - return config; - } - }; - - return requestInterceptor; - } - ]) - // We have to add the interceptor to the queue as a string because the interceptor depends upon service instances that are not available in the config block. - .config([ - '$httpProvider', function($httpProvider) { - $httpProvider.interceptors.push('requestInterceptor'); - } - ]); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/services/util.service.js b/src/Umbraco.Web.UI.Client/src/common/services/util.service.js index 9fbf2947af..2f06d4c393 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/util.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/util.service.js @@ -1,5 +1,43 @@ /*Contains multiple services for various helper tasks */ +function dateHelper() { + + return { + + convertToServerStringTime: function(momentLocal, serverOffsetMinutes, format) { + + //get the formatted offset time in HH:mm (server time offset is in minutes) + var formattedOffset = (serverOffsetMinutes > 0 ? "+" : "-") + + moment() + .startOf('day') + .minutes(Math.abs(serverOffsetMinutes)) + .format('HH:mm'); + + var server = moment.utc(momentLocal).zone(formattedOffset); + return server.format(format ? format : "YYYY-MM-DD HH:mm:ss"); + }, + + convertToLocalMomentTime: function (strVal, serverOffsetMinutes) { + + //get the formatted offset time in HH:mm (server time offset is in minutes) + var formattedOffset = (serverOffsetMinutes > 0 ? "+" : "-") + + moment() + .startOf('day') + .minutes(Math.abs(serverOffsetMinutes)) + .format('HH:mm'); + + //convert to the iso string format + var isoFormat = moment(strVal).format("YYYY-MM-DDTHH:mm:ss") + formattedOffset; + + //create a moment with the iso format which will include the offset with the correct time + // then convert it to local time + return moment.parseZone(isoFormat).local(); + } + + }; +} +angular.module('umbraco.services').factory('dateHelper', dateHelper); + function packageHelper(assetsService, treeService, eventsService, $templateCache) { return { diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js index 693bd49ec6..95d0a1bdf6 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js @@ -1,4 +1,4 @@ -function dateTimePickerController($scope, notificationsService, assetsService, angularHelper, userService, $element) { +function dateTimePickerController($scope, notificationsService, assetsService, angularHelper, userService, $element, dateHelper) { //setup the default config var config = { @@ -22,6 +22,8 @@ function dateTimePickerController($scope, notificationsService, assetsService, a $scope.model.config.format = $scope.model.config.pickTime ? "YYYY-MM-DD HH:mm:ss" : "YYYY-MM-DD"; } + + $scope.hasDatetimePickerValue = $scope.model.value ? true : false; $scope.datetimePickerValue = null; @@ -43,20 +45,46 @@ function dateTimePickerController($scope, notificationsService, assetsService, a if (e.date && e.date.isValid()) { $scope.datePickerForm.datepicker.$setValidity("pickerError", true); $scope.hasDatetimePickerValue = true; - $scope.datetimePickerValue = e.date.format($scope.model.config.format); - $scope.model.value = $scope.datetimePickerValue; + $scope.datetimePickerValue = e.date.format($scope.model.config.format); } else { $scope.hasDatetimePickerValue = false; $scope.datetimePickerValue = null; } - + + setModelValue(); + if (!$scope.model.config.pickTime) { $element.find("div:first").datetimepicker("hide", 0); } }); } + //sets the scope model value accordingly - this is the value to be sent up to the server and depends on + // if the picker is configured to offset time. We always format the date/time in a specific format for sending + // to the server, this is different from the format used to display the date/time. + function setModelValue() { + if ($scope.hasDatetimePickerValue) { + var elementData = $element.find("div:first").data().DateTimePicker; + if ($scope.model.config.pickTime) { + //check if we are supposed to offset the time + if ($scope.model.value && $scope.model.config.offsetTime === "1" && Umbraco.Sys.ServerVariables.application.serverTimeOffset) { + $scope.model.value = dateHelper.convertToServerStringTime(elementData.getDate(), Umbraco.Sys.ServerVariables.application.serverTimeOffset); + $scope.serverTime = dateHelper.convertToServerStringTime(elementData.getDate(), Umbraco.Sys.ServerVariables.application.serverTimeOffset, "YYYY-MM-DD HH:mm:ss Z"); + } + else { + $scope.model.value = elementData.getDate().format("YYYY-MM-DD HH:mm:ss"); + } + } + else { + $scope.model.value = elementData.getDate().format("YYYY-MM-DD"); + } + } + else { + $scope.model.value = null; + } + } + var picker = null; $scope.clearDate = function() { @@ -66,6 +94,8 @@ function dateTimePickerController($scope, notificationsService, assetsService, a $scope.datePickerForm.datepicker.$setValidity("pickerError", true); } + $scope.serverTime = null; + //get the current user to see if we can localize this picker userService.getCurrentUser().then(function (user) { @@ -97,8 +127,17 @@ function dateTimePickerController($scope, notificationsService, assetsService, a }); if ($scope.hasDatetimePickerValue) { - //assign value to plugin/picker - var dateVal = $scope.model.value ? moment($scope.model.value, "YYYY-MM-DD HH:mm:ss") : moment(); + var dateVal; + //check if we are supposed to offset the time + if ($scope.model.value && $scope.model.config.offsetTime === "1" && Umbraco.Sys.ServerVariables.application.serverTimeOffset) { + //get the local time offset from the server + dateVal = dateHelper.convertToLocalMomentTime($scope.model.value, Umbraco.Sys.ServerVariables.application.serverTimeOffset); + $scope.serverTime = dateHelper.convertToServerStringTime(dateVal, Umbraco.Sys.ServerVariables.application.serverTimeOffset, "YYYY-MM-DD HH:mm:ss Z"); + } + else { + //create a normal moment , no offset required + var dateVal = $scope.model.value ? moment($scope.model.value, "YYYY-MM-DD HH:mm:ss") : moment(); + } element.datetimepicker("setValue", dateVal); $scope.datetimePickerValue = dateVal.format($scope.model.config.format); @@ -117,18 +156,7 @@ function dateTimePickerController($scope, notificationsService, assetsService, a var unsubscribe = $scope.$on("formSubmitting", function (ev, args) { - if ($scope.hasDatetimePickerValue) { - var elementData = $element.find("div:first").data().DateTimePicker; - if ($scope.model.config.pickTime) { - $scope.model.value = elementData.getDate().format("YYYY-MM-DD HH:mm:ss"); - } - else { - $scope.model.value = elementData.getDate().format("YYYY-MM-DD"); - } - } - else { - $scope.model.value = null; - } + setModelValue(); }); //unbind doc click event! $scope.$on('$destroy', function () { @@ -142,17 +170,7 @@ function dateTimePickerController($scope, notificationsService, assetsService, a }); var unsubscribe = $scope.$on("formSubmitting", function (ev, args) { - if ($scope.hasDatetimePickerValue) { - if ($scope.model.config.pickTime) { - $scope.model.value = $element.find("div:first").data().DateTimePicker.getDate().format("YYYY-MM-DD HH:mm:ss"); - } - else { - $scope.model.value = $element.find("div:first").data().DateTimePicker.getDate().format("YYYY-MM-DD"); - } - } - else { - $scope.model.value = null; - } + setModelValue(); }); //unbind doc click event! diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.html index e6d49e5c6c..c9b83cc8ed 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.html @@ -18,6 +18,9 @@ {{datePickerForm.datepicker.errorMsg}} Invalid date +

    + Server time: {{serverTime}} +

    Clear date

    diff --git a/src/Umbraco.Web.UI.Client/test/config/karma.conf.js b/src/Umbraco.Web.UI.Client/test/config/karma.conf.js index 0f323f03aa..ede7c20538 100644 --- a/src/Umbraco.Web.UI.Client/test/config/karma.conf.js +++ b/src/Umbraco.Web.UI.Client/test/config/karma.conf.js @@ -24,6 +24,7 @@ module.exports = function(karma) { 'lib/../build/belle/lib/underscore/underscore-min.js', + 'lib/../build/belle/lib/moment/moment-with-locales.js', 'lib/umbraco/Extensions.js', 'lib/../build/belle/lib/rgrove-lazyload/lazyload.js', 'lib/../build/belle/lib/angular-local-storage/angular-local-storage.min.js', diff --git a/src/Umbraco.Web.UI.Client/test/unit/common/services/date-helper.spec.js b/src/Umbraco.Web.UI.Client/test/unit/common/services/date-helper.spec.js new file mode 100644 index 0000000000..74d2b38cfa --- /dev/null +++ b/src/Umbraco.Web.UI.Client/test/unit/common/services/date-helper.spec.js @@ -0,0 +1,53 @@ +describe('date helper tests', function () { + var dateHelper; + + beforeEach(module('umbraco.services')); + + beforeEach(inject(function ($injector) { + dateHelper = $injector.get('dateHelper'); + })); + + describe('converting to local moments', function () { + + it('converts from a positive offset', function () { + var offsetMin = 600; //+10 + var strDate = "2016-01-01 10:00:00"; + + var result = dateHelper.convertToLocalMomentTime(strDate, offsetMin); + + expect(result.format("YYYY-MM-DD HH:mm:ss Z")).toBe("2016-01-01 01:00:00 +01:00"); + }); + + it('converts from a negataive offset', function () { + var offsetMin = -420; //-7 + var strDate = "2016-01-01 10:00:00"; + + var result = dateHelper.convertToLocalMomentTime(strDate, offsetMin); + + expect(result.format("YYYY-MM-DD HH:mm:ss Z")).toBe("2016-01-01 18:00:00 +01:00"); + }); + + }); + + describe('converting to server strings', function () { + + it('converts to a positive offset', function () { + var offsetMin = 600; //+10 + var localDate = moment("2016-01-01 10:00:00"); + + var result = dateHelper.convertToServerStringTime(localDate, offsetMin, "YYYY-MM-DD HH:mm:ss Z"); + + expect(result).toBe("2016-01-01 19:00:00 +10:00"); + }); + + it('converts from a negataive offset', function () { + var offsetMin = -420; //-7 + var localDate = moment("2016-01-01 10:00:00"); + + var result = dateHelper.convertToServerStringTime(localDate, offsetMin, "YYYY-MM-DD HH:mm:ss Z"); + + expect(result).toBe("2016-01-01 02:00:00 -07:00"); + }); + + }); +}); \ No newline at end of file diff --git a/src/Umbraco.Web/Editors/BackOfficeController.cs b/src/Umbraco.Web/Editors/BackOfficeController.cs index b5cea7a945..6ee6f260f3 100644 --- a/src/Umbraco.Web/Editors/BackOfficeController.cs +++ b/src/Umbraco.Web/Editors/BackOfficeController.cs @@ -677,6 +677,10 @@ namespace Umbraco.Web.Editors app.Add("cdf", ClientDependencySettings.Instance.Version); //useful for dealing with virtual paths on the client side when hosted in virtual directories especially app.Add("applicationPath", HttpContext.Request.ApplicationPath.EnsureEndsWith('/')); + + //add the server's GMT time offset in minutes + app.Add("serverTimeOffset", Convert.ToInt32(DateTimeOffset.Now.Offset.TotalMinutes)); + return app; } diff --git a/src/Umbraco.Web/Editors/ContentControllerBase.cs b/src/Umbraco.Web/Editors/ContentControllerBase.cs index bf9f2056b3..495217cec2 100644 --- a/src/Umbraco.Web/Editors/ContentControllerBase.cs +++ b/src/Umbraco.Web/Editors/ContentControllerBase.cs @@ -97,10 +97,11 @@ namespace Umbraco.Web.Editors var d = new Dictionary(); //add the files if any var files = contentItem.UploadedFiles.Where(x => x.PropertyAlias == p.Alias).ToArray(); - if (files.Any()) + if (files.Length > 0) { d.Add("files", files); } + var data = new ContentPropertyData(p.Value, p.PreValues, d); //get the deserialized value from the property editor @@ -113,7 +114,7 @@ namespace Umbraco.Web.Editors var valueEditor = p.PropertyEditor.ValueEditor; //don't persist any bound value if the editor is readonly if (valueEditor.IsReadOnly == false) - { + { var propVal = p.PropertyEditor.ValueEditor.ConvertEditorToDb(data, dboProperty.Value); var supportTagsAttribute = TagExtractor.GetAttribute(p.PropertyEditor); if (supportTagsAttribute != null) diff --git a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs index ede1dfc78d..e44fc056da 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs @@ -179,7 +179,11 @@ namespace Umbraco.Web.Models.Mapping Label = localizedText.Localize("content/releaseDate"), Value = display.ReleaseDate.HasValue ? display.ReleaseDate.Value.ToIsoString() : null, //Not editible for people without publish permission (U4-287) - View = display.AllowedActions.Contains('P') ? "datepicker" : PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View + View = display.AllowedActions.Contains('P') ? "datepicker" : PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View, + Config = new Dictionary + { + {"offsetTime", "1"} + } //TODO: Fix up hard coded datepicker } , new ContentPropertyDisplay @@ -188,7 +192,11 @@ namespace Umbraco.Web.Models.Mapping Label = localizedText.Localize("content/unpublishDate"), Value = display.ExpireDate.HasValue ? display.ExpireDate.Value.ToIsoString() : null, //Not editible for people without publish permission (U4-287) - View = display.AllowedActions.Contains('P') ? "datepicker" : PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View + View = display.AllowedActions.Contains('P') ? "datepicker" : PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View, + Config = new Dictionary + { + {"offsetTime", "1"} + } //TODO: Fix up hard coded datepicker }, new ContentPropertyDisplay diff --git a/src/Umbraco.Web/PropertyEditors/DateTimePreValueEditor.cs b/src/Umbraco.Web/PropertyEditors/DateTimePreValueEditor.cs new file mode 100644 index 0000000000..242893cbca --- /dev/null +++ b/src/Umbraco.Web/PropertyEditors/DateTimePreValueEditor.cs @@ -0,0 +1,10 @@ +using Umbraco.Core.PropertyEditors; + +namespace Umbraco.Web.PropertyEditors +{ + internal class DateTimePreValueEditor : DatePreValueEditor + { + [PreValueField("offsetTime", "Offset time", "boolean", Description = "When enabled the time displayed will be offset with the server's timezone, this is useful for scenarios like scheduled publishing when an editor is in a different timezone than the hosted server")] + public bool OffsetTime { get; set; } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/PropertyEditors/DateTimePropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/DateTimePropertyEditor.cs index 38674de14e..2a76c0d50a 100644 --- a/src/Umbraco.Web/PropertyEditors/DateTimePropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/DateTimePropertyEditor.cs @@ -1,7 +1,10 @@ using System; using System.Collections.Generic; using Umbraco.Core; +using Umbraco.Core.Models; +using Umbraco.Core.Models.Editors; using Umbraco.Core.PropertyEditors; +using Umbraco.Core.Services; namespace Umbraco.Web.PropertyEditors { @@ -14,7 +17,11 @@ namespace Umbraco.Web.PropertyEditors { //NOTE: This is very important that we do not use .Net format's there, this format // is the correct format for the JS picker we are using so you cannot capitalize the HH, they need to be 'hh' - {"format", "YYYY-MM-DD HH:mm:ss"} + {"format", "YYYY-MM-DD HH:mm:ss"}, + //a pre-value indicating if the client/server time should be offset, when set to true the date/time seen + // by the client will be offset with the server time. + // For example, this is forced to true for scheduled publishing date/time pickers + {"offsetTime", "0"} }; } @@ -40,7 +47,9 @@ namespace Umbraco.Web.PropertyEditors protected override PreValueEditor CreatePreValueEditor() { - return new DatePreValueEditor(); + return new DateTimePreValueEditor(); } } + + } \ No newline at end of file diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 48005b1209..a1968d5e3f 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -354,6 +354,7 @@ + diff --git a/src/Umbraco.Web/WebApi/Binders/ContentItemBaseBinder.cs b/src/Umbraco.Web/WebApi/Binders/ContentItemBaseBinder.cs index dda19f9ff9..195c488b1e 100644 --- a/src/Umbraco.Web/WebApi/Binders/ContentItemBaseBinder.cs +++ b/src/Umbraco.Web/WebApi/Binders/ContentItemBaseBinder.cs @@ -166,7 +166,7 @@ namespace Umbraco.Web.WebApi.Binders //create the dto from the persisted model if (model.PersistedContent != null) { - model.ContentDto = MapFromPersisted(model); + model.ContentDto = MapFromPersisted(model); } if (model.ContentDto != null) { @@ -186,9 +186,15 @@ namespace Umbraco.Web.WebApi.Binders /// private static void MapPropertyValuesFromSaved(TModelSave saveModel, ContentItemDto dto) { - foreach (var p in saveModel.Properties.Where(p => dto.Properties.Any(x => x.Alias == p.Alias))) + //NOTE: Don't convert this to linq, this is much quicker + foreach (var p in saveModel.Properties) { - dto.Properties.Single(x => x.Alias == p.Alias).Value = p.Value; + foreach (var propertyDto in dto.Properties) + { + if (propertyDto.Alias != p.Alias) continue; + propertyDto.Value = p.Value; + break; + } } } From bab693f2baac2d4898c8fdb1ea555b253d32ba52 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 25 May 2016 10:56:41 +0200 Subject: [PATCH 074/535] fix build --- src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs index 97d81539d2..34cd64c265 100644 --- a/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs +++ b/src/Umbraco.Web/Models/Mapping/ContentModelMapper.cs @@ -179,7 +179,7 @@ namespace Umbraco.Web.Models.Mapping Label = localizedText.Localize("content/releaseDate"), Value = display.ReleaseDate.HasValue ? display.ReleaseDate.Value.ToIsoString() : null, //Not editible for people without publish permission (U4-287) - View = display.AllowedActions.Contains(ActionPublish.Instance.Letter) ? "datepicker" : PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View + View = display.AllowedActions.Contains(ActionPublish.Instance.Letter) ? "datepicker" : PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View, Config = new Dictionary { {"offsetTime", "1"} @@ -192,7 +192,7 @@ namespace Umbraco.Web.Models.Mapping Label = localizedText.Localize("content/unpublishDate"), Value = display.ExpireDate.HasValue ? display.ExpireDate.Value.ToIsoString() : null, //Not editible for people without publish permission (U4-287) - View = display.AllowedActions.Contains(ActionPublish.Instance.Letter) ? "datepicker" : PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View + View = display.AllowedActions.Contains(ActionPublish.Instance.Letter) ? "datepicker" : PropertyEditorResolver.Current.GetByAlias(Constants.PropertyEditors.NoEditAlias).ValueEditor.View, Config = new Dictionary { {"offsetTime", "1"} From 85a54c64920c3335fc5b1382ffae797a4574be5f Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 25 May 2016 11:20:35 +0200 Subject: [PATCH 075/535] fixes the delete part of U4-8491 --- .../listview/listview.controller.js | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js index 3911ef7338..594475a7d2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/listview/listview.controller.js @@ -366,11 +366,24 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie } $scope.delete = function () { - applySelected( - function (selected, index) { return deleteItemCallback(getIdCallback(selected[index])); }, - function (count, total) { return "Deleted " + count + " out of " + total + " item" + (total > 1 ? "s" : ""); }, - function (total) { return "Deleted " + total + " item" + (total > 1 ? "s" : ""); }, - "Sure you want to delete?"); + + var attempt = + applySelected( + function(selected, index) { return deleteItemCallback(getIdCallback(selected[index])); }, + function(count, total) { + return "Deleted " + count + " out of " + total + " item" + (total > 1 ? "s" : ""); + }, + function(total) { return "Deleted " + total + " item" + (total > 1 ? "s" : ""); }, + "Sure you want to delete?"); + if (attempt) { + attempt.then(function () { + //executes if all is successful, let's sync the tree + var activeNode = appState.getTreeState("selectedNode"); + if (activeNode) { + navigationService.reloadNode(activeNode); + } + }); + } }; $scope.publish = function () { @@ -412,6 +425,7 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie }; + function performMove(target) { //NOTE: With the way this applySelected/serial works, I'm not sure there's a better way currently to return @@ -425,9 +439,7 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie return path; }); }, - function(count, total) { - return "Moved " + count + " out of " + total + " item" + (total > 1 ? "s" : ""); - }, + function(count, total) {return "Moved " + count + " out of " + total + " item" + (total > 1 ? "s" : "");}, function(total) { return "Moved " + total + " item" + (total > 1 ? "s" : ""); }) .then(function() { //executes if all is successful, let's sync the tree From 247a5f415df1d216255a241a1d589d967aa90648 Mon Sep 17 00:00:00 2001 From: Claus Date: Wed, 25 May 2016 12:12:52 +0200 Subject: [PATCH 076/535] added a check to create macroScripts folder if it doesn't exist when creating a scripting file. --- .../umbraco/create/DLRScriptingTasks.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Umbraco.Web/umbraco.presentation/umbraco/create/DLRScriptingTasks.cs b/src/Umbraco.Web/umbraco.presentation/umbraco/create/DLRScriptingTasks.cs index 1d9503e661..fd13010167 100644 --- a/src/Umbraco.Web/umbraco.presentation/umbraco/create/DLRScriptingTasks.cs +++ b/src/Umbraco.Web/umbraco.presentation/umbraco/create/DLRScriptingTasks.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using Umbraco.Core.IO; using Umbraco.Core.Logging; using Umbraco.Core; @@ -42,6 +43,11 @@ namespace umbraco } } + var abFileFolder = Path.GetDirectoryName(abFileName); + if (string.IsNullOrWhiteSpace(abFileFolder) == false) + if (Directory.Exists(abFileFolder) == false) + Directory.CreateDirectory(abFileFolder); + var scriptWriter = System.IO.File.CreateText(abFileName); scriptWriter.Write(scriptContent); scriptWriter.Flush(); From 81d1ac74d2c9a271fc369deb1cb0e61038fe11b0 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 25 May 2016 13:56:42 +0200 Subject: [PATCH 077/535] U4-8513 Fix the RestartApplicationPool extension to null out the current identity --- src/Umbraco.Web/ApplicationContextExtensions.cs | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web/ApplicationContextExtensions.cs b/src/Umbraco.Web/ApplicationContextExtensions.cs index 1756da5f3c..b91e73df0d 100644 --- a/src/Umbraco.Web/ApplicationContextExtensions.cs +++ b/src/Umbraco.Web/ApplicationContextExtensions.cs @@ -1,4 +1,5 @@ -using System.Web; +using System.Threading; +using System.Web; using Umbraco.Core; namespace Umbraco.Web @@ -17,8 +18,13 @@ namespace Umbraco.Web // it can check if this flag exists... if it does it means the app pool isn't restarted yet. http.Application.Add("AppPoolRestarting", true); - // unload app domain - HttpRuntime.UnloadAppDomain(); + // unload app domain - we must null out all identities otherwise we get serialization errors + // http://www.zpqrtbnk.net/posts/custom-iidentity-serialization-issue + http.User = null; + if (HttpContext.Current != null) + HttpContext.Current.User = null; + Thread.CurrentPrincipal = null; + HttpRuntime.UnloadAppDomain(); } } } From 1e38089bb4db835caeeba99046afaadd5ce656cc Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 25 May 2016 13:58:56 +0200 Subject: [PATCH 078/535] U4-8514 Fix installation issue when there are stale cookies on localhost --- src/umbraco.cms/businesslogic/Packager/Installer.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/umbraco.cms/businesslogic/Packager/Installer.cs b/src/umbraco.cms/businesslogic/Packager/Installer.cs index 4be82ba7b7..0225dd94a8 100644 --- a/src/umbraco.cms/businesslogic/Packager/Installer.cs +++ b/src/umbraco.cms/businesslogic/Packager/Installer.cs @@ -14,6 +14,7 @@ using umbraco.cms.businesslogic.web; using umbraco.cms.businesslogic.propertytype; using umbraco.BusinessLogic; using System.Diagnostics; +using System.Security; using umbraco.cms.businesslogic.macro; using umbraco.cms.businesslogic.template; using umbraco.interfaces; @@ -304,13 +305,20 @@ namespace umbraco.cms.businesslogic.packager // Get current user, with a fallback var currentUser = new User(0); + + //if there's a context, try to resolve the user - this will return null if there is a context but no + // user found when there are old/invalid cookies lying around most likely during installation. + // in that case we'll keep using the admin user if (string.IsNullOrEmpty(BasePages.UmbracoEnsuredPage.umbracoUserContextID) == false) { if (BasePages.UmbracoEnsuredPage.ValidateUserContextID(BasePages.UmbracoEnsuredPage.umbracoUserContextID)) { - currentUser = User.GetCurrent(); + var userById = User.GetCurrent(); + if (userById != null) + currentUser = userById; } } + //Xml as XElement which is used with the new PackagingService var rootElement = Config.DocumentElement.GetXElement(); From 8cea391a3f00c822f8e2aa4f0223d537d7c7fc42 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 25 May 2016 14:36:00 +0200 Subject: [PATCH 079/535] U4-8514 Fix installation issue when there are stale cookies on localhost --- src/Umbraco.Web/Install/InstallHelper.cs | 2 +- .../Install/InstallSteps/NewInstallStep.cs | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Umbraco.Web/Install/InstallHelper.cs b/src/Umbraco.Web/Install/InstallHelper.cs index 143067f6a1..d39b16f6ac 100644 --- a/src/Umbraco.Web/Install/InstallHelper.cs +++ b/src/Umbraco.Web/Install/InstallHelper.cs @@ -42,7 +42,7 @@ namespace Umbraco.Web.Install { return new List { - new NewInstallStep(_umbContext.Application), + new NewInstallStep(_umbContext.HttpContext, _umbContext.Application), new UpgradeStep(), new FilePermissionsStep(), new MajorVersion7UpgradeReport(_umbContext.Application), diff --git a/src/Umbraco.Web/Install/InstallSteps/NewInstallStep.cs b/src/Umbraco.Web/Install/InstallSteps/NewInstallStep.cs index baa94c304e..4d8e9c5a4b 100644 --- a/src/Umbraco.Web/Install/InstallSteps/NewInstallStep.cs +++ b/src/Umbraco.Web/Install/InstallSteps/NewInstallStep.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Configuration; +using System.Web; using System.Web.Security; using Umbraco.Core; using Umbraco.Core.Configuration; @@ -22,10 +23,12 @@ namespace Umbraco.Web.Install.InstallSteps "User", 20, "")] internal class NewInstallStep : InstallSetupStep { + private readonly HttpContextBase _http; private readonly ApplicationContext _applicationContext; - public NewInstallStep(ApplicationContext applicationContext) + public NewInstallStep(HttpContextBase http, ApplicationContext applicationContext) { + _http = http; _applicationContext = applicationContext; } @@ -111,7 +114,7 @@ namespace Umbraco.Web.Install.InstallSteps //the continue install UI : "continueinstall"; } } - + public override bool RequiresExecution(UserModel model) { //now we have to check if this is really a new install, the db might be configured and might contain data @@ -136,6 +139,10 @@ namespace Umbraco.Web.Install.InstallSteps } else { + // In this one case when it's a brand new install and nothing has been configured, make sure the + // back office cookie is cleared so there's no old cookies lying around causing problems + _http.ExpireCookie(UmbracoConfig.For.UmbracoSettings().Security.AuthCookieName); + return true; } } From def8ee4962bd755bcc51d82780891f8c08b4ed44 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 25 May 2016 14:38:24 +0200 Subject: [PATCH 080/535] fixes ysod when indexing grid content when the value is not a string (sub json value) --- .../PropertyEditors/GridPropertyEditor.cs | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs index 6178a4f9a4..85177540d2 100644 --- a/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs @@ -60,15 +60,21 @@ namespace Umbraco.Web.PropertyEditors foreach (var areaVal in areaVals) { - var str = areaVal.Value(); - str = XmlHelper.CouldItBeXml(str) ? str.StripHtml() : str; - sb.Append(str); - sb.Append(" "); + //TODO: If it's not a string, then it's a json formatted value - + // we cannot really index this in a smart way since it could be 'anything' + if (areaVal.Type == JTokenType.String) + { + var str = areaVal.Value(); + str = XmlHelper.CouldItBeXml(str) ? str.StripHtml() : str; + sb.Append(str); + sb.Append(" "); - //add the row name as an individual field - e.Document.Add( - new Field( - string.Format("{0}.{1}", field.Name, rowName), str, Field.Store.YES, Field.Index.ANALYZED)); + //add the row name as an individual field + e.Document.Add( + new Field( + string.Format("{0}.{1}", field.Name, rowName), str, Field.Store.YES, Field.Index.ANALYZED)); + } + } } From b3b4cd4654434e3a7db164dc8603d729285c7788 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Wed, 25 May 2016 15:30:35 +0200 Subject: [PATCH 081/535] Fixes: U4-8480 Allow deleting empty tab when creating a doctype --- .../src/views/components/umb-groups-builder.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/components/umb-groups-builder.html b/src/Umbraco.Web.UI.Client/src/views/components/umb-groups-builder.html index 567d00c871..3533255288 100644 --- a/src/Umbraco.Web.UI.Client/src/views/components/umb-groups-builder.html +++ b/src/Umbraco.Web.UI.Client/src/views/components/umb-groups-builder.html @@ -49,7 +49,7 @@
    -
    +
    Date: Thu, 26 May 2016 13:12:05 +0200 Subject: [PATCH 082/535] hacked new packages tree --- .../Trees/NewPackagesTreeController.cs | 48 +++++++++++++++++++ src/Umbraco.Web/Umbraco.Web.csproj | 1 + 2 files changed, 49 insertions(+) create mode 100644 src/Umbraco.Web/Trees/NewPackagesTreeController.cs diff --git a/src/Umbraco.Web/Trees/NewPackagesTreeController.cs b/src/Umbraco.Web/Trees/NewPackagesTreeController.cs new file mode 100644 index 0000000000..c6c4e67841 --- /dev/null +++ b/src/Umbraco.Web/Trees/NewPackagesTreeController.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Net; +using System.Net.Http.Formatting; +using System.Web.Http; +using Umbraco.Core; +using Umbraco.Core.Models; +using Umbraco.Web.Models.Trees; +using Umbraco.Web.Mvc; +using Umbraco.Web.WebApi.Filters; +using umbraco; +using umbraco.BusinessLogic.Actions; +using Umbraco.Core.Models.EntityBase; +using Umbraco.Core.Services; +using Constants = Umbraco.Core.Constants; + +namespace Umbraco.Web.Trees +{ + [UmbracoTreeAuthorize(Constants.Trees.DataTypes)] + [Tree(Constants.Applications.Developer, "packagesNew")] + [PluginController("UmbracoTrees")] + [CoreTree] + public class NewPackagesTreeController : TreeController + { + protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings) + { + var nodes = new TreeNodeCollection(); + + var node = CreateTreeNode("1", id, queryStrings, "Name", "icon-folder", false, ""); + node.Path = "path"; + //node.NodeType = "container"; + //TODO: This isn't the best way to ensure a noop process for clicking a node but it works for now. + //node.AdditionalData["jsClickCallback"] = "javascript:void(0);"; + + nodes.Add(node); + + return nodes; + } + + protected override MenuItemCollection GetMenuForNode(string id, FormDataCollection queryStrings) + { + var menu = new MenuItemCollection(); + return menu; + } + } +} \ No newline at end of file diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index de4b49bc77..5102416548 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -376,6 +376,7 @@ + From 05746c7b7c7e4be08b78365e937d9e6e35868f48 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 26 May 2016 13:12:41 +0200 Subject: [PATCH 083/535] added editor scaffold --- .../src/views/packagesNew/edit.controller.js | 16 +++++++++++ .../src/views/packagesNew/edit.html | 27 +++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.controller.js create mode 100644 src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.controller.js new file mode 100644 index 0000000000..345846fdb9 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.controller.js @@ -0,0 +1,16 @@ +(function () { + "use strict"; + + function PackagesEditController($scope) { + + var vm = this; + + vm.page = {}; + vm.page.name = "Packages"; + + + } + + angular.module("umbraco").controller("Umbraco.Editors.Packages.EditController", PackagesEditController); + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html new file mode 100644 index 0000000000..9af94dc739 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html @@ -0,0 +1,27 @@ +
    + + + +
    + + + + + + + + This is my new package repository + + + + +
    + +
    From f876b6b7280cdc41507d54111fac8253264752dd Mon Sep 17 00:00:00 2001 From: Simon Busborg Date: Thu, 26 May 2016 13:39:01 +0200 Subject: [PATCH 084/535] added umb-packages.less, added repeater for packages + minimal styling --- src/Umbraco.Web.UI.Client/src/less/belle.less | 1 + .../src/less/components/umb-packages.less | 42 +++++++++++ .../src/views/packagesNew/edit.controller.js | 33 ++++++++- .../src/views/packagesNew/edit.html | 69 ++++++++++++++----- 4 files changed, 127 insertions(+), 18 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less diff --git a/src/Umbraco.Web.UI.Client/src/less/belle.less b/src/Umbraco.Web.UI.Client/src/less/belle.less index 9d01cae4b9..d00bc6021e 100644 --- a/src/Umbraco.Web.UI.Client/src/less/belle.less +++ b/src/Umbraco.Web.UI.Client/src/less/belle.less @@ -108,6 +108,7 @@ @import "components/umb-empty-state.less"; @import "components/umb-property-editor.less"; @import "components/umb-iconpicker.less"; +@import "components/umb-packages.less"; @import "components/buttons/umb-button.less"; @import "components/buttons/umb-button-group.less"; diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less new file mode 100644 index 0000000000..581b6da16d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less @@ -0,0 +1,42 @@ +.umb-packages { + display: flex; + flex-wrap: wrap; +} + +.umb-package { + flex: 0 0 25%; + + padding-left: 20px; + padding-right: 20px; + + box-sizing: border-box; +} + +.umb-package-link { + display: flex; + flex-wrap: wrap; + flex-direction: column; + + padding: 20px; + + background: whitesmoke; + border: 2px solid #ececec; + border-radius: 3px; + + text-decoration: none !important; +} + + +.umb-package-icon { + padding: 20px; + text-align: center; +} + +.umb-package-name { + font-weight: bold; +} + +.umb-package-numbers { + display: flex; + flex-wrap: wrap; +} diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.controller.js index 345846fdb9..9279d1916e 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.controller.js @@ -7,7 +7,38 @@ vm.page = {}; vm.page.name = "Packages"; - + + vm.packages = [ + { + "name": "Test App", + "description": "lorem flaxis slk asjasd ks", + "karma": "1", + "downloads": "2", + "icon": "flax" + }, + { + "name": "Tessti flaxi", + "description": "loremlaksjd lkajs dasjasd ks", + "karma": "10", + "downloads": "22", + "icon": "flaxo" + }, + { + "name": "Walla", + "description": "lorem flaxis slk asjasd ks", + "karma": "1", + "downloads": "2", + "icon": "flax" + }, + { + "name": "Walla", + "description": "lorem flaxis slk asjasd ks", + "karma": "1", + "downloads": "2", + "icon": "flax" + } + ]; + } diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html index 9af94dc739..f0c54febaa 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html @@ -1,27 +1,62 @@
    - + -
    + - + - - + + - - This is my new package repository - + - + + +
    + +
    + + + + + +
    + +
    From 259ccd653e6444bad5110b5401b8b4c1f5e149bd Mon Sep 17 00:00:00 2001 From: Simon Busborg Date: Thu, 26 May 2016 14:13:55 +0200 Subject: [PATCH 085/535] Added dummy data to packages --- .../src/less/components/umb-packages.less | 121 +++++++++++++++++- .../src/views/packagesNew/edit.controller.js | 28 ++++ .../src/views/packagesNew/edit.html | 20 +-- src/Umbraco.Web.UI/config/trees.config | 1 + 4 files changed, 158 insertions(+), 12 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less index 581b6da16d..fd9880f016 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less @@ -4,12 +4,33 @@ } .umb-package { - flex: 0 0 25%; + flex: 0 0 100%; padding-left: 20px; padding-right: 20px; + padding-bottom: 20px; box-sizing: border-box; + + @media (min-width: 768px) { + flex: 0 0 50%; + } + + @media (min-width: 1024px) { + flex: 0 0 33.33%; + } + + @media (min-width: 1260px) { + flex: 0 0 25%; + } + + @media (min-width: 1600px) { + flex: 0 0 20%; + } + + @media (min-width: 2000px) { + flex: 0 0 16.66%; + } } .umb-package-link { @@ -17,8 +38,6 @@ flex-wrap: wrap; flex-direction: column; - padding: 20px; - background: whitesmoke; border: 2px solid #ececec; border-radius: 3px; @@ -28,15 +47,109 @@ .umb-package-icon { - padding: 20px; + display: flex; + + justify-content: center; + align-items: center; + + padding: 10px; text-align: center; + border-bottom: 2px solid #ececec; + background-color: white; + + min-height: 120px; } +.umb-package-icon img { + opacity: .1; +} + +.umb-package-info { + padding-top: 10px; + padding-right: 20px; + padding-bottom: 20px; + padding-left: 20px; +} + + .umb-package-name { font-weight: bold; + margin-bottom: 10px; } .umb-package-numbers { display: flex; flex-wrap: wrap; + + margin-bottom: 20px; + + opacity: .6; +} + +.umb-package-link:hover .umb-package-numbers { + opacity: 1; +} + +.umb-package-link:hover .umb-era-button { + background: #2e8aea; + color: white; + + &:hover { + background-color: #287dd6; + } +} + +/* umb-buttons-era */ +.umb-era-button { + display: flex; + justify-content: center; + align-items: center; + + font-size: 14px; + font-weight: bold; + text-transform: capitalize; + + height: 38px; + line-height: 38px; + + + max-width: 100%; + padding: 0 18px; + + color: #484848; + background-color: #e0e0e0; + + text-decoration: none !important; + user-select: none; + + white-space: nowrap; + overflow: hidden; + + border-radius: 3px; + border: 0 none; + + transition: background-color 80ms ease, color 80ms ease; +} + + +.umb-era-button:hover, +.umb-era-button:active { + color: #484848; + background-color: #d3d3d3; + outline: none; + text-decoration: none; +} + + +.umb-era-button:focus { + outline: none; +} + +.umb-era-button.-blue { + background: #2e8aea; + color: white; +} + +.umb-era-button.-blue:hover { + background-color: #287dd6; } diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.controller.js index 9279d1916e..9c41d98d3a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.controller.js @@ -9,6 +9,34 @@ vm.page.name = "Packages"; vm.packages = [ + { + "name": "Test App", + "description": "lorem flaxis slk asjasd ks", + "karma": "1", + "downloads": "2", + "icon": "flax" + }, + { + "name": "Tessti flaxi", + "description": "loremlaksjd lkajs dasjasd ks", + "karma": "10", + "downloads": "22", + "icon": "flaxo" + }, + { + "name": "Walla", + "description": "lorem flaxis slk asjasd ks", + "karma": "1", + "downloads": "2", + "icon": "flax" + }, + { + "name": "Walla", + "description": "lorem flaxis slk asjasd ks", + "karma": "1", + "downloads": "2", + "icon": "flax" + }, { "name": "Test App", "description": "lorem flaxis slk asjasd ks", diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html index f0c54febaa..e01fe89161 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html @@ -26,30 +26,34 @@ diff --git a/src/Umbraco.Web.UI/config/trees.config b/src/Umbraco.Web.UI/config/trees.config index 91c216c727..6c9fb153b6 100644 --- a/src/Umbraco.Web.UI/config/trees.config +++ b/src/Umbraco.Web.UI/config/trees.config @@ -42,4 +42,5 @@ + \ No newline at end of file From 7bb8430022b0a539d7315f603809acee622ecc82 Mon Sep 17 00:00:00 2001 From: Simon Busborg Date: Thu, 26 May 2016 14:50:11 +0200 Subject: [PATCH 086/535] =?UTF-8?q?Packages=20=F0=9F=93=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/less/components/umb-packages.less | 14 ++++++++++---- .../src/views/packagesNew/edit.html | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less index fd9880f016..6840376703 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less @@ -43,6 +43,12 @@ border-radius: 3px; text-decoration: none !important; + + transition: border-color 100ms ease; + + &:hover { + border-color: @blue; + } } @@ -91,11 +97,11 @@ } .umb-package-link:hover .umb-era-button { - background: #2e8aea; + background: @blue; color: white; &:hover { - background-color: #287dd6; + background-color: @blueDark; } } @@ -146,10 +152,10 @@ } .umb-era-button.-blue { - background: #2e8aea; + background: @blue; color: white; } .umb-era-button.-blue:hover { - background-color: #287dd6; + background-color: @blueDark; } diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html index e01fe89161..e7e46528a8 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html @@ -31,7 +31,7 @@
    - +
    From 098eb32ef61fbe3ec6994e5dd1243541c6bd38ed Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Thu, 26 May 2016 14:57:38 +0200 Subject: [PATCH 087/535] added categories --- .../src/less/components/umb-packages.less | 39 +++++++++++++++++++ .../src/views/packagesNew/edit.controller.js | 27 +++++++++++++ .../src/views/packagesNew/edit.html | 5 ++- 3 files changed, 70 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less index 6840376703..4d4d443b09 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less @@ -159,3 +159,42 @@ .umb-era-button.-blue:hover { background-color: @blueDark; } + + + +/* CATEGORIES */ + +.umb-packages-categories { + display: flex; + user-select: center; + flex-wrap: wrap; + margin-bottom: 30px; +} + +.umb-packages-category { + display: flex; + align-items: center; + flex: 1 0 auto; + max-width: 25%; + background-color: @blue; + padding: 10px; + font-size: 12px; + border-radius: 3px; + color: @white; + font-weight: bold; + box-sizing: border-box; + flex: 1 0 auto; + margin: 5px; + justify-content: center; +} + +.umb-packages-category:hover, +.umb-packages-category:focus { + text-decoration: none; + color: @white; +} + +.umb-packages-category-icon { + font-size: 20px; + margin-right: 5px; +} diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.controller.js index 9c41d98d3a..4ce5597429 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.controller.js @@ -8,6 +8,33 @@ vm.page = {}; vm.page.name = "Packages"; + vm.categories = [ + { + "icon": "icon-male-and-female", + "name": "Collaboration" + }, + { + "icon": "icon-molecular-network", + "name": "Backoffice extensions" + }, + { + "icon": "icon-brackets", + "name": "Developer tools" + }, + { + "icon": "icon-wand", + "name": "Starter kits" + }, + { + "icon": "icon-medal", + "name": "Umbraco Pro" + }, + { + "icon": "icon-wrench", + "name": "Website utilities" + } + ]; + vm.packages = [ { "name": "Test App", diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html index e7e46528a8..8f98ba8712 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html @@ -21,7 +21,10 @@
    From 8a744b52fe42097d2031cd8dd18f76af0f7f7121 Mon Sep 17 00:00:00 2001 From: Simon Busborg Date: Thu, 26 May 2016 15:21:12 +0200 Subject: [PATCH 088/535] Removed install button, better spacing --- .../src/less/components/umb-packages.less | 25 +++++++++++-------- .../src/views/packagesNew/edit.html | 12 +++------ 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less index 4d4d443b09..bca3d7cbd7 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less @@ -1,13 +1,17 @@ .umb-packages { display: flex; flex-wrap: wrap; + + margin: 0 -5px; } + +// List .umb-package { flex: 0 0 100%; - padding-left: 20px; - padding-right: 20px; + padding-left: 10px; + padding-right: 10px; padding-bottom: 20px; box-sizing: border-box; @@ -33,6 +37,8 @@ } } + +// Link (Wrapper) .umb-package-link { display: flex; flex-wrap: wrap; @@ -52,6 +58,8 @@ } + +// Icon .umb-package-icon { display: flex; @@ -70,6 +78,8 @@ opacity: .1; } + +// Info .umb-package-info { padding-top: 10px; padding-right: 20px; @@ -78,17 +88,17 @@ } +// Name .umb-package-name { font-weight: bold; margin-bottom: 10px; } +// Numbers .umb-package-numbers { display: flex; flex-wrap: wrap; - margin-bottom: 20px; - opacity: .6; } @@ -96,14 +106,7 @@ opacity: 1; } -.umb-package-link:hover .umb-era-button { - background: @blue; - color: white; - &:hover { - background-color: @blueDark; - } -} /* umb-buttons-era */ .umb-era-button { diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html index 8f98ba8712..c34c9487f2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html @@ -43,16 +43,12 @@
    -
    + Downloads {{ package.downloads }} -
    -
    + + Karma {{ package.karma }} -
    -
    - -
    - Install +
    From 628ce5ea1fb9e7405a90ea593983a68951397c3f Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 26 May 2016 15:30:40 +0200 Subject: [PATCH 089/535] Backports some changes from v8 so that we can perform a nice strongly typed query with paging - this is then used for the content indexer to index content via the db for published content instead of the xml cache system. This was already done in v8 but have no backported the logic and fixed up the unit tests. When merging with v8 we will most likely just keep all v8 stuff and discard these changes, but we'll need to compare just in case. All tests pass and re-indexing is working as expected. Also updated the paging count from 1000 to 5000 for reindexing. --- .../Repositories/ContentRepository.cs | 20 +++--- .../Interfaces/IContentRepository.cs | 4 +- .../Repositories/VersionableRepositoryBase.cs | 22 ++++++- src/Umbraco.Core/Services/ContentService.cs | 46 +++++++++++++- src/Umbraco.Core/Services/IContentService.cs | 16 +++++ .../Repositories/ContentRepositoryTest.cs | 8 ++- .../LegacyExamineBackedMediaTests.cs | 20 +++--- .../UmbracoExamine/EventsTest.cs | 28 +++++---- .../UmbracoExamine/ExamineBaseTest.cs | 28 +++++---- .../UmbracoExamine/IndexInitializer.cs | 45 +++++++++++++- src/Umbraco.Tests/UmbracoExamine/IndexTest.cs | 31 +++++----- src/UmbracoExamine/BaseUmbracoIndexer.cs | 30 +++------ src/UmbracoExamine/UmbracoContentIndexer.cs | 62 ++++++++++--------- 13 files changed, 239 insertions(+), 121 deletions(-) diff --git a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs index 5f96cad114..1a1a7b00bf 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs @@ -771,22 +771,22 @@ namespace Umbraco.Core.Persistence.Repositories /// Search text filter /// An Enumerable list of objects public IEnumerable GetPagedResultsByQuery(IQuery query, long pageIndex, int pageSize, out long totalRecords, - string orderBy, Direction orderDirection, bool orderBySystemField, string filter = "") + string orderBy, Direction orderDirection, bool orderBySystemField, IQuery filter = null) { //NOTE: This uses the GetBaseQuery method but that does not take into account the required 'newest' field which is // what we always require for a paged result, so we'll ensure it's included in the filter - - var args = new List(); - var sbWhere = new StringBuilder("AND (cmsDocument.newest = 1)"); - - if (filter.IsNullOrWhiteSpace() == false) + + var filterSql = new Sql().Append("AND (cmsDocument.newest = 1)"); + if (filter != null) { - sbWhere.Append(" AND (cmsDocument." + SqlSyntax.GetQuotedColumnName("text") + " LIKE @" + args.Count + ")"); - args.Add("%" + filter + "%"); + foreach (var filterClaus in filter.GetWhereClauses()) + { + filterSql.Append(string.Format("AND ({0})", filterClaus.Item1), filterClaus.Item2); + } } - - Func> filterCallback = () => new Tuple(sbWhere.ToString(), args.ToArray()); + + Func> filterCallback = () => new Tuple(filterSql.SQL, filterSql.Arguments); return GetPagedResultsByQuery(query, pageIndex, pageSize, out totalRecords, new Tuple("cmsDocument", "nodeId"), diff --git a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs index ab176df6d0..c18765239b 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs @@ -85,9 +85,9 @@ namespace Umbraco.Core.Persistence.Repositories /// Field to order by /// Direction to order by /// Flag to indicate when ordering by system field - /// Search text filter + /// /// An Enumerable list of objects IEnumerable GetPagedResultsByQuery(IQuery query, long pageIndex, int pageSize, out long totalRecords, - string orderBy, Direction orderDirection, bool orderBySystemField, string filter = ""); + string orderBy, Direction orderDirection, bool orderBySystemField, IQuery filter = null); } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs index 4b2befb3e3..e062f49235 100644 --- a/src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs @@ -235,13 +235,29 @@ namespace Umbraco.Core.Persistence.Repositories private Sql GetFilteredSqlForPagedResults(Sql sql, Func> defaultFilter = null) { - //copy to var so that the original isn't changed - var filteredSql = new Sql(sql.SQL, sql.Arguments); + Sql filteredSql; + // Apply filter if (defaultFilter != null) { var filterResult = defaultFilter(); - filteredSql.Append(filterResult.Item1, filterResult.Item2); + + //NOTE: this is certainly strange - NPoco handles this much better but we need to re-create the sql + // instance a couple of times to get the parameter order correct, for some reason the first + // time the arguments don't show up correctly but the SQL argument parameter names are actually updated + // accordingly - so we re-create it again. In v8 we don't need to do this and it's already taken care of. + + filteredSql = new Sql(sql.SQL, sql.Arguments); + var args = filteredSql.Arguments.Concat(filterResult.Item2).ToArray(); + filteredSql = new Sql( + string.Format("{0} {1}", filteredSql.SQL, filterResult.Item1), + args); + filteredSql = new Sql(filteredSql.SQL, args); + } + else + { + //copy to var so that the original isn't changed + filteredSql = new Sql(sql.SQL, sql.Arguments); } return filteredSql; } diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index bbae07eb6a..7fcb915b30 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -536,7 +536,12 @@ namespace Umbraco.Core.Services { query.Where(x => x.ParentId == id); } - var contents = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, orderBySystemField, filter); + IQuery filterQuery = null; + if (filter.IsNullOrWhiteSpace() == false) + { + filterQuery = Query.Builder.Where(x => x.Name.Contains(filter)); + } + var contents = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, orderBySystemField, filterQuery); return contents; } @@ -593,12 +598,49 @@ namespace Umbraco.Core.Services { query.Where(x => x.Path.SqlContains(string.Format(",{0},", id), TextColumnType.NVarchar)); } - var contents = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, orderBySystemField, filter); + IQuery filterQuery = null; + if (filter.IsNullOrWhiteSpace() == false) + { + filterQuery = Query.Builder.Where(x => x.Name.Contains(filter)); + } + var contents = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, orderBySystemField, filterQuery); return contents; } } + /// + /// Gets a collection of objects by Parent Id + /// + /// Id of the Parent to retrieve Descendants from + /// Page number + /// Page size + /// Total records query would return without paging + /// Field to order by + /// Direction to order by + /// Flag to indicate when ordering by system field + /// Search filter + /// An Enumerable list of objects + public IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy, Direction orderDirection, bool orderBySystemField, IQuery filter) + { + Mandate.ParameterCondition(pageIndex >= 0, "pageIndex"); + Mandate.ParameterCondition(pageSize > 0, "pageSize"); + + using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork())) + { + var query = Query.Builder; + + //if the id is System Root, then just get all + if (id != Constants.System.Root) + { + query.Where(x => x.Path.SqlContains(string.Format(",{0},", id), TextColumnType.NVarchar)); + } + var contents = repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, orderBySystemField, filter); + + return contents; + } + } + /// /// Gets a collection of objects by its name or partial name /// diff --git a/src/Umbraco.Core/Services/IContentService.cs b/src/Umbraco.Core/Services/IContentService.cs index df70fa8094..5e90559233 100644 --- a/src/Umbraco.Core/Services/IContentService.cs +++ b/src/Umbraco.Core/Services/IContentService.cs @@ -4,6 +4,7 @@ using System.ComponentModel; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; using Umbraco.Core.Persistence.DatabaseModelDefinitions; +using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Publishing; namespace Umbraco.Core.Services @@ -268,6 +269,21 @@ namespace Umbraco.Core.Services IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalRecords, string orderBy, Direction orderDirection, bool orderBySystemField, string filter); + /// + /// Gets a collection of objects by Parent Id + /// + /// Id of the Parent to retrieve Descendants from + /// Page number + /// Page size + /// Total records query would return without paging + /// Field to order by + /// Direction to order by + /// Flag to indicate when ordering by system field + /// + /// An Enumerable list of objects + IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalRecords, + string orderBy, Direction orderDirection, bool orderBySystemField, IQuery filter); + /// /// Gets a collection of an objects versions by its Id /// diff --git a/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs b/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs index d29b073df7..2d036bb620 100644 --- a/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs +++ b/src/Umbraco.Tests/Persistence/Repositories/ContentRepositoryTest.cs @@ -685,8 +685,10 @@ namespace Umbraco.Tests.Persistence.Repositories { // Act var query = Query.Builder.Where(x => x.Level == 2); + var filterQuery = Query.Builder.Where(x => x.Name.Contains("Page 2")); + long totalRecords; - var result = repository.GetPagedResultsByQuery(query, 0, 1, out totalRecords, "Name", Direction.Ascending, true, "Page 2"); + var result = repository.GetPagedResultsByQuery(query, 0, 1, out totalRecords, "Name", Direction.Ascending, true, filterQuery); // Assert Assert.That(totalRecords, Is.EqualTo(1)); @@ -706,8 +708,10 @@ namespace Umbraco.Tests.Persistence.Repositories { // Act var query = Query.Builder.Where(x => x.Level == 2); + var filterQuery = Query.Builder.Where(x => x.Name.Contains("Page")); + long totalRecords; - var result = repository.GetPagedResultsByQuery(query, 0, 1, out totalRecords, "Name", Direction.Ascending, true, "Page"); + var result = repository.GetPagedResultsByQuery(query, 0, 1, out totalRecords, "Name", Direction.Ascending, true, filterQuery); // Assert Assert.That(totalRecords, Is.EqualTo(2)); diff --git a/src/Umbraco.Tests/PublishedContent/LegacyExamineBackedMediaTests.cs b/src/Umbraco.Tests/PublishedContent/LegacyExamineBackedMediaTests.cs index 7b0ffb41d7..8a83bea75a 100644 --- a/src/Umbraco.Tests/PublishedContent/LegacyExamineBackedMediaTests.cs +++ b/src/Umbraco.Tests/PublishedContent/LegacyExamineBackedMediaTests.cs @@ -7,14 +7,17 @@ using NUnit.Framework; using Umbraco.Tests.TestHelpers; using Umbraco.Tests.UmbracoExamine; using umbraco.MacroEngines; +using Umbraco.Core; +using Umbraco.Core.Logging; +using Umbraco.Core.Persistence.Mappers; namespace Umbraco.Tests.PublishedContent { public class LegacyExamineBackedMediaTests : ExamineBaseTest { - public override void TestSetup() + public override void Initialize() { - base.TestSetup(); + base.Initialize(); var settings = SettingsForTests.GenerateMockSettings(); var contentMock = Mock.Get(settings.Content); @@ -22,13 +25,8 @@ namespace Umbraco.Tests.PublishedContent contentMock.Setup(x => x.UmbracoLibraryCacheDuration).Returns(1800); SettingsForTests.ConfigureSettings(settings); } - - public override void TestTearDown() - { - SettingsForTests.Reset(); - base.TestTearDown(); - } - + + [Test] public void Ensure_Children_Are_Sorted() { @@ -47,7 +45,9 @@ namespace Umbraco.Tests.PublishedContent var children = backedMedia.ChildrenAsList.Value; var currSort = 0; - for (var i = 0; i < children.Count(); i++) + Assert.Greater(children.Count, 0); + + for (var i = 0; i < children.Count; i++) { Assert.GreaterOrEqual(children[i].SortOrder, currSort); currSort = children[i].SortOrder; diff --git a/src/Umbraco.Tests/UmbracoExamine/EventsTest.cs b/src/Umbraco.Tests/UmbracoExamine/EventsTest.cs index d01b298bb4..6bd01c7f1c 100644 --- a/src/Umbraco.Tests/UmbracoExamine/EventsTest.cs +++ b/src/Umbraco.Tests/UmbracoExamine/EventsTest.cs @@ -45,19 +45,21 @@ namespace Umbraco.Tests.UmbracoExamine private static UmbracoContentIndexer _indexer; private Lucene.Net.Store.Directory _luceneDir; - public override void TestSetup() - { - base.TestSetup(); - _luceneDir = new RAMDirectory(); - _indexer = IndexInitializer.GetUmbracoIndexer(_luceneDir); - _indexer.RebuildIndex(); - _searcher = IndexInitializer.GetUmbracoSearcher(_luceneDir); - } + public override void Initialize() + { + base.Initialize(); - public override void TestTearDown() - { - base.TestTearDown(); - _luceneDir.Dispose(); - } + _luceneDir = new RAMDirectory(); + _indexer = IndexInitializer.GetUmbracoIndexer(_luceneDir); + _indexer.RebuildIndex(); + _searcher = IndexInitializer.GetUmbracoSearcher(_luceneDir); + } + + public override void TearDown() + { + base.TearDown(); + _luceneDir.Dispose(); + } + } } \ No newline at end of file diff --git a/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs b/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs index 5fed998194..ec3babc7ab 100644 --- a/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs +++ b/src/Umbraco.Tests/UmbracoExamine/ExamineBaseTest.cs @@ -1,5 +1,9 @@ -using NUnit.Framework; +using Moq; +using NUnit.Framework; +using Umbraco.Core; +using Umbraco.Core.Logging; using Umbraco.Core.ObjectResolution; +using Umbraco.Core.Persistence.Mappers; using Umbraco.Core.Strings; using Umbraco.Tests.TestHelpers; using UmbracoExamine; @@ -7,29 +11,27 @@ using UmbracoExamine; namespace Umbraco.Tests.UmbracoExamine { [TestFixture] - public abstract class ExamineBaseTest : BaseUmbracoConfigurationTest + public abstract class ExamineBaseTest : BaseDatabaseFactoryTest { - - [SetUp] - public virtual void TestSetup() + /// + /// sets up resolvers before resolution is frozen + /// + protected override void FreezeResolution() { UmbracoExamineSearcher.DisableInitializationCheck = true; BaseUmbracoIndexer.DisableInitializationCheck = true; ShortStringHelperResolver.Current = new ShortStringHelperResolver(new DefaultShortStringHelper(SettingsForTests.GetDefault())); - Resolution.Freeze(); + base.FreezeResolution(); } - [TearDown] - public virtual void TestTearDown() + public override void TearDown() { + base.TearDown(); + UmbracoExamineSearcher.DisableInitializationCheck = null; BaseUmbracoIndexer.DisableInitializationCheck = null; - - //reset all resolvers - ResolverCollection.ResetAll(); - //reset resolution itself (though this should be taken care of by resetting any of the resolvers above) - Resolution.Reset(); } + } } \ No newline at end of file diff --git a/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs b/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs index 9990c58a43..b303eed997 100644 --- a/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs +++ b/src/Umbraco.Tests/UmbracoExamine/IndexInitializer.cs @@ -10,6 +10,7 @@ using Moq; using Umbraco.Core.Models; using Umbraco.Core.Models.Membership; using Umbraco.Core.Persistence.DatabaseModelDefinitions; +using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Services; using UmbracoExamine; using UmbracoExamine.Config; @@ -41,7 +42,48 @@ namespace Umbraco.Tests.UmbracoExamine } if (contentService == null) { - contentService = Mock.Of(); + long longTotalRecs; + int intTotalRecs; + + var allRecs = dataService.ContentService.GetLatestContentByXPath("//*[@isDoc]") + .Root + .Elements() + .Select(x => Mock.Of( + m => + m.Id == (int)x.Attribute("id") && + m.ParentId == (int)x.Attribute("parentID") && + m.Level == (int)x.Attribute("level") && + m.CreatorId == 0 && + m.SortOrder == (int)x.Attribute("sortOrder") && + m.CreateDate == (DateTime)x.Attribute("createDate") && + m.UpdateDate == (DateTime)x.Attribute("updateDate") && + m.Name == (string)x.Attribute("nodeName") && + m.Path == (string)x.Attribute("path") && + m.Properties == new PropertyCollection() && + m.ContentType == Mock.Of(mt => + mt.Alias == x.Name.LocalName && + mt.Id == (int)x.Attribute("nodeType") && + mt.Icon == "test"))) + .ToArray(); + + + contentService = Mock.Of( + x => x.GetPagedDescendants( + It.IsAny(), It.IsAny(), It.IsAny(), out longTotalRecs, It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()) + == + allRecs + && x.GetPagedDescendants( + It.IsAny(), It.IsAny(), It.IsAny(), out longTotalRecs, It.IsAny(), It.IsAny(), It.IsAny()) + == + allRecs + && x.GetPagedDescendants( + It.IsAny(), It.IsAny(), It.IsAny(), out intTotalRecs, It.IsAny(), It.IsAny(), It.IsAny()) + == + allRecs + && x.GetPagedDescendants( + It.IsAny(), It.IsAny(), It.IsAny(), out longTotalRecs, It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny>()) + == + allRecs); } if (userService == null) { @@ -86,7 +128,6 @@ namespace Umbraco.Tests.UmbracoExamine It.IsAny(), It.IsAny(), It.IsAny(), out intTotalRecs, It.IsAny(), It.IsAny(), It.IsAny()) == allRecs); - } if (dataTypeService == null) { diff --git a/src/Umbraco.Tests/UmbracoExamine/IndexTest.cs b/src/Umbraco.Tests/UmbracoExamine/IndexTest.cs index a5418649fe..6cef19af9e 100644 --- a/src/Umbraco.Tests/UmbracoExamine/IndexTest.cs +++ b/src/Umbraco.Tests/UmbracoExamine/IndexTest.cs @@ -142,8 +142,6 @@ namespace Umbraco.Tests.UmbracoExamine { var s = (IndexSearcher)_searcher.GetSearcher(); - - //first delete all 'Content' (not media). This is done by directly manipulating the index with the Lucene API, not examine! var contentTerm = new Term(LuceneIndexer.IndexTypeFieldName, IndexTypes.Content); @@ -207,23 +205,24 @@ namespace Umbraco.Tests.UmbracoExamine private Lucene.Net.Store.Directory _luceneDir; - public override void TestTearDown() - { - base.TestTearDown(); - _luceneDir.Dispose(); + public override void TearDown() + { + base.TearDown(); + _luceneDir.Dispose(); UmbracoExamineSearcher.DisableInitializationCheck = null; BaseUmbracoIndexer.DisableInitializationCheck = null; - } - - public override void TestSetup() - { - base.TestSetup(); - _luceneDir = new RAMDirectory(); - _indexer = IndexInitializer.GetUmbracoIndexer(_luceneDir); - _indexer.RebuildIndex(); - _searcher = IndexInitializer.GetUmbracoSearcher(_luceneDir); - } + } + + public override void Initialize() + { + base.Initialize(); + _luceneDir = new RAMDirectory(); + _indexer = IndexInitializer.GetUmbracoIndexer(_luceneDir); + _indexer.RebuildIndex(); + _searcher = IndexInitializer.GetUmbracoSearcher(_luceneDir); + } + #endregion } diff --git a/src/UmbracoExamine/BaseUmbracoIndexer.cs b/src/UmbracoExamine/BaseUmbracoIndexer.cs index ee77f5d05c..26763bd7cd 100644 --- a/src/UmbracoExamine/BaseUmbracoIndexer.cs +++ b/src/UmbracoExamine/BaseUmbracoIndexer.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Net; using System.Security; @@ -361,10 +362,11 @@ namespace UmbracoExamine /// protected override void PerformIndexAll(string type) { - //NOTE: the logic below is ONLY used for published content, for media and members and non-published content, this method is overridden + //NOTE: the logic below is NOT used, this method is overridden // and we query directly against the umbraco service layer. + // This is here for backwards compat only. - if (!SupportedTypes.Contains(type)) + if (SupportedTypes.Contains(type) == false) return; var xPath = "//*[(number(@id) > 0 and (@isDoc or @nodeTypeAlias)){0}]"; //we'll add more filters to this below if needed @@ -417,16 +419,11 @@ namespace UmbracoExamine AddNodesToIndex(xPath, type); } - /// - /// Returns an XDocument for the entire tree stored for the IndexType specified. - /// - /// The xpath to the node. - /// The type of data to request from the data service. - /// Either the Content or Media xml. If the type is not of those specified null is returned + [Obsolete("This method is not be used, it will be removed in future versions")] + [EditorBrowsable(EditorBrowsableState.Never)] protected virtual XDocument GetXDocument(string xPath, string type) { - //TODO: We need to get rid of this! it will now only ever be called for published content - but we're keeping the other - // logic here for backwards compatibility in case inheritors are calling this for some reason. + //TODO: We need to get rid of this! This does not get called by our code if (type == IndexTypes.Content) { @@ -447,12 +444,9 @@ namespace UmbracoExamine } #endregion - #region Private - /// - /// Adds all nodes with the given xPath root. - /// - /// The x path. - /// The type. + + [Obsolete("This method is not be used, it will be removed in future versions")] + [EditorBrowsable(EditorBrowsableState.Never)] private void AddNodesToIndex(string xPath, string type) { // Get all the nodes of nodeTypeAlias == nodeTypeAlias @@ -476,9 +470,5 @@ namespace UmbracoExamine } } - - - - #endregion } } diff --git a/src/UmbracoExamine/UmbracoContentIndexer.cs b/src/UmbracoExamine/UmbracoContentIndexer.cs index 613304c4ff..92a1fb776e 100644 --- a/src/UmbracoExamine/UmbracoContentIndexer.cs +++ b/src/UmbracoExamine/UmbracoContentIndexer.cs @@ -25,6 +25,7 @@ using UmbracoExamine.Config; using Examine.LuceneEngine.Providers; using Lucene.Net.Analysis; using umbraco.BasePages; +using Umbraco.Core.Persistence.Querying; using IContentService = Umbraco.Core.Services.IContentService; using UmbracoExamine.LocalStorage; using IMediaService = Umbraco.Core.Services.IMediaService; @@ -348,50 +349,55 @@ namespace UmbracoExamine protected override void PerformIndexAll(string type) { - - const int pageSize = 1000; + const int pageSize = 5000; var pageIndex = 0; switch (type) { case IndexTypes.Content: - if (this.SupportUnpublishedContent == false) + + + var contentParentId = -1; + if (IndexerData.ParentNodeId.HasValue && IndexerData.ParentNodeId.Value > 0) { - //use the base implementation which will use the published XML cache to perform the lookups - base.PerformIndexAll(type); + contentParentId = IndexerData.ParentNodeId.Value; } - else + IContent[] content; + + do { - var contentParentId = -1; - if (IndexerData.ParentNodeId.HasValue && IndexerData.ParentNodeId.Value > 0) + long total; + + IEnumerable descendants; + if (SupportUnpublishedContent) { - contentParentId = IndexerData.ParentNodeId.Value; + descendants = _contentService.GetPagedDescendants(contentParentId, pageIndex, pageSize, out total); } - IContent[] content; - - do + else { - long total; - var descendants = _contentService.GetPagedDescendants(contentParentId, pageIndex, pageSize, out total); + //add the published filter + var qry = Query.Builder.Where(x => x.Published == true); - //if specific types are declared we need to post filter them - //TODO: Update the service layer to join the cmsContentType table so we can query by content type too - if (IndexerData.IncludeNodeTypes.Any()) - { - content = descendants.Where(x => IndexerData.IncludeNodeTypes.Contains(x.ContentType.Alias)).ToArray(); - } - else - { - content = descendants.ToArray(); - } + descendants = _contentService.GetPagedDescendants(contentParentId, pageIndex, pageSize, out total, "Path", Direction.Ascending, true, qry); + } - AddNodesToIndex(GetSerializedContent(content), type); - pageIndex++; + //if specific types are declared we need to post filter them + //TODO: Update the service layer to join the cmsContentType table so we can query by content type too + if (IndexerData.IncludeNodeTypes.Any()) + { + content = descendants.Where(x => IndexerData.IncludeNodeTypes.Contains(x.ContentType.Alias)).ToArray(); + } + else + { + content = descendants.ToArray(); + } + + AddNodesToIndex(GetSerializedContent(content), type); + pageIndex++; - } while (content.Length == pageSize); + } while (content.Length == pageSize); - } break; case IndexTypes.Media: From 3cc8a71a60fa12158ffb28c70e7ea0ed5fdac306 Mon Sep 17 00:00:00 2001 From: Simon Busborg Date: Thu, 26 May 2016 16:31:56 +0200 Subject: [PATCH 090/535] added button back --- .../src/less/components/umb-packages.less | 103 ++++++++++++------ .../src/views/packagesNew/edit.controller.js | 82 ++++++-------- .../src/views/packagesNew/edit.html | 45 +++++++- 3 files changed, 143 insertions(+), 87 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less index bca3d7cbd7..b226517bbf 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less @@ -1,3 +1,25 @@ +.umb-packages-search { + width: 100%; + + margin-top: 40px; + margin-bottom: 30px; +} + +.umb-packages-search input { + border-width: 2px; + border-radius: 3px; + min-height: 44px; + + padding: 4px 10px; + font-size: 16px; + border-color: #ececec; + + &:hover, &:focus { + border-color: @grayLight; + } +} + + .umb-packages { display: flex; flex-wrap: wrap; @@ -8,33 +30,10 @@ // List .umb-package { - flex: 0 0 100%; + height: 260px; + width: 200px; - padding-left: 10px; - padding-right: 10px; - padding-bottom: 20px; - - box-sizing: border-box; - - @media (min-width: 768px) { - flex: 0 0 50%; - } - - @media (min-width: 1024px) { - flex: 0 0 33.33%; - } - - @media (min-width: 1260px) { - flex: 0 0 25%; - } - - @media (min-width: 1600px) { - flex: 0 0 20%; - } - - @media (min-width: 2000px) { - flex: 0 0 16.66%; - } + padding: 20px; } @@ -43,8 +42,11 @@ display: flex; flex-wrap: wrap; flex-direction: column; + justify-content: center; + + height: 100%; + width: 100%; - background: whitesmoke; border: 2px solid #ececec; border-radius: 3px; @@ -66,40 +68,62 @@ justify-content: center; align-items: center; - padding: 10px; + padding-top: 10px; + padding-right: 10px; + padding-left: 10px; + text-align: center; - border-bottom: 2px solid #ececec; background-color: white; - min-height: 120px; + min-height: 80px; } .umb-package-icon img { - opacity: .1; + max-width: 70px; + height: auto; } // Info .umb-package-info { - padding-top: 10px; padding-right: 20px; padding-bottom: 20px; padding-left: 20px; + + text-align: center; } // Name .umb-package-name { + max-width: 250px; + font-weight: bold; + margin-bottom: 10px; + + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + + line-height: normal; } // Numbers .umb-package-numbers { display: flex; flex-wrap: wrap; + flex-direction: column; + justify-content: center; opacity: .6; + + margin-bottom: 20px; +} + +.umb-package-numbers small { + padding: 0 5px; + display: block; } .umb-package-link:hover .umb-package-numbers { @@ -180,15 +204,22 @@ flex: 1 0 auto; max-width: 25%; background-color: @blue; - padding: 10px; - font-size: 12px; + padding: 40px 10px; + font-size: 13px; border-radius: 3px; color: @white; - font-weight: bold; box-sizing: border-box; flex: 1 0 auto; margin: 5px; justify-content: center; + + text-transform: uppercase; + letter-spacing: 1.3px; + + &:hover { + background-color: @blueDark; + box-shadow: 0 3px 8px rgba(0,0,0,0.2); + } } .umb-packages-category:hover, @@ -200,4 +231,6 @@ .umb-packages-category-icon { font-size: 20px; margin-right: 5px; + + display: none; } diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.controller.js index 4ce5597429..e082448933 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.controller.js @@ -37,60 +37,46 @@ vm.packages = [ { - "name": "Test App", - "description": "lorem flaxis slk asjasd ks", + "name": "uSightly", + "description": "An HTML5 audio player based on jPlayer", "karma": "1", - "downloads": "2", - "icon": "flax" + "downloads": "1672", + "icon":"https://our.umbraco.org/media/wiki/150283/635768313097111400_usightlylogopng.png?bgcolor=fff&height=154&width=281&format=png" }, { - "name": "Tessti flaxi", - "description": "loremlaksjd lkajs dasjasd ks", - "karma": "10", - "downloads": "22", - "icon": "flaxo" + "name": "Kill IE6", + "description": "A simple port of the IE6 warning script (http://code.google.com/p/ie6-upgrade-warning/) to use in your Umbraco websites.", + "karma": "11", + "downloads": "688", + "icon":"https://our.umbraco.org/media/wiki/9138/634697622367666000_offroadcode-100x100.png?bgcolor=fff&height=154&width=281&format=png" }, { - "name": "Walla", - "description": "lorem flaxis slk asjasd ks", + "name": "Examine Media Indexer", + "description": "CogUmbracoExamineMediaIndexer", + "karma": "3", + "downloads": "1329", + "icon":"https://our.umbraco.org/media/wiki/50703/634782902373558000_cogworks.jpg?bgcolor=fff&height=154&width=281&format=png" + }, + { + "name": "SVG Icon Picker", + "description": "A picker, for picking icons from an SVG spritesheet.", + "karma": "5", + "downloads": "8", + "icon":"https://our.umbraco.org/media/wiki/154472/635997115126742822_logopng.png?bgcolor=fff&height=154&width=281&format=png" + }, + { + "name": "Pipeline CRM", + "description": "Pipeline is a social CRM that lives in Umbraco back-office. It tracks opportunities and helps teams collaborate with timelines and tasks. It stores information about your customers and your interactions with them. It integrates with your website, capturing opportunities from forms and powering personal portals.", + "karma": "3", + "downloads": "105", + "icon":"https://our.umbraco.org/media/wiki/152476/635917291068518788_pipeline-crm-logopng.png?bgcolor=fff&height=154&width=281&format=png" + }, + { + "name": "CodeMirror", + "description": "CodeMirror Editor for Umbraco", "karma": "1", - "downloads": "2", - "icon": "flax" - }, - { - "name": "Walla", - "description": "lorem flaxis slk asjasd ks", - "karma": "1", - "downloads": "2", - "icon": "flax" - }, - { - "name": "Test App", - "description": "lorem flaxis slk asjasd ks", - "karma": "1", - "downloads": "2", - "icon": "flax" - }, - { - "name": "Tessti flaxi", - "description": "loremlaksjd lkajs dasjasd ks", - "karma": "10", - "downloads": "22", - "icon": "flaxo" - }, - { - "name": "Walla", - "description": "lorem flaxis slk asjasd ks", - "karma": "1", - "downloads": "2", - "icon": "flax" - }, - { - "name": "Walla", - "description": "lorem flaxis slk asjasd ks", - "karma": "1", - "downloads": "2", - "icon": "flax" + "downloads": "70", + "icon":"https://our.umbraco.org/media/wiki/151028/635810233171153461_logopng.png?bgcolor=fff&height=154&width=281&format=png" } ]; diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html index c34c9487f2..cf9c68e7d9 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html @@ -17,7 +17,7 @@
    @@ -27,14 +27,15 @@
    + +
    Popular
    - + + + +
    Latest
    +
    From 41b68333d27157b996c5f48687ccd7ab6474208f Mon Sep 17 00:00:00 2001 From: Shannon Date: Thu, 26 May 2016 16:36:53 +0200 Subject: [PATCH 091/535] publicizes EnableChangeTracking and DisableChangeTracking methods for entities, ensures that change tracking is disabled whenever building an entity for a repository as this is totally unnecessary and probably large memory overhead. Updates examine content indexer to page by 10000 rows --- .../EntityBase/TracksChangesEntityBase.cs | 6 +- .../Persistence/Factories/ContentFactory.cs | 51 ++++++----- .../Factories/ContentTypeFactory.cs | 36 ++++++-- .../Factories/DataTypeDefinitionFactory.cs | 48 ++++++---- .../Factories/DictionaryItemFactory.cs | 26 ++++-- .../Factories/DictionaryTranslationFactory.cs | 22 +++-- .../Persistence/Factories/MacroFactory.cs | 25 ++++-- .../Persistence/Factories/MediaFactory.cs | 44 ++++++---- .../Persistence/Factories/MemberFactory.cs | 47 ++++++---- .../Factories/MemberGroupFactory.cs | 28 +++--- .../Factories/MemberTypeReadOnlyFactory.cs | 82 +++++++++-------- .../Persistence/Factories/PropertyFactory.cs | 22 +++-- .../Factories/PropertyGroupFactory.cs | 88 +++++++++++-------- .../Persistence/Factories/RelationFactory.cs | 29 +++--- .../Factories/RelationTypeFactory.cs | 27 ++++-- .../Persistence/Factories/TaskFactory.cs | 34 ++++--- .../Persistence/Factories/TemplateFactory.cs | 36 +++++--- .../Factories/UmbracoEntityFactory.cs | 78 ++++++++-------- .../Persistence/Factories/UserFactory.cs | 62 +++++++------ .../Persistence/Factories/UserTypeFactory.cs | 34 ++++--- src/UmbracoExamine/UmbracoContentIndexer.cs | 2 +- 21 files changed, 506 insertions(+), 321 deletions(-) diff --git a/src/Umbraco.Core/Models/EntityBase/TracksChangesEntityBase.cs b/src/Umbraco.Core/Models/EntityBase/TracksChangesEntityBase.cs index 0d5378d253..8e4fbc13f5 100644 --- a/src/Umbraco.Core/Models/EntityBase/TracksChangesEntityBase.cs +++ b/src/Umbraco.Core/Models/EntityBase/TracksChangesEntityBase.cs @@ -138,18 +138,18 @@ namespace Umbraco.Core.Models.EntityBase _propertyChangedInfo = new Dictionary(); } - protected void ResetChangeTrackingCollections() + public void ResetChangeTrackingCollections() { _propertyChangedInfo = new Dictionary(); _lastPropertyChangedInfo = new Dictionary(); } - protected void DisableChangeTracking() + public void DisableChangeTracking() { _changeTrackingEnabled = false; } - protected void EnableChangeTracking() + public void EnableChangeTracking() { _changeTrackingEnabled = true; } diff --git a/src/Umbraco.Core/Persistence/Factories/ContentFactory.cs b/src/Umbraco.Core/Persistence/Factories/ContentFactory.cs index d21aea33e6..3cc5608620 100644 --- a/src/Umbraco.Core/Persistence/Factories/ContentFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/ContentFactory.cs @@ -29,28 +29,37 @@ namespace Umbraco.Core.Persistence.Factories public IContent BuildEntity(DocumentDto dto) { - var content = new Content(dto.Text, dto.ContentVersionDto.ContentDto.NodeDto.ParentId, _contentType) + var content = new Content(dto.Text, dto.ContentVersionDto.ContentDto.NodeDto.ParentId, _contentType); + + try { - Id = _id, - Key = dto.ContentVersionDto.ContentDto.NodeDto.UniqueId, - Name = dto.Text, - NodeName = dto.ContentVersionDto.ContentDto.NodeDto.Text, - Path = dto.ContentVersionDto.ContentDto.NodeDto.Path, - CreatorId = dto.ContentVersionDto.ContentDto.NodeDto.UserId.Value, - WriterId = dto.WriterUserId, - Level = dto.ContentVersionDto.ContentDto.NodeDto.Level, - ParentId = dto.ContentVersionDto.ContentDto.NodeDto.ParentId, - SortOrder = dto.ContentVersionDto.ContentDto.NodeDto.SortOrder, - Trashed = dto.ContentVersionDto.ContentDto.NodeDto.Trashed, - Published = dto.Published, - CreateDate = dto.ContentVersionDto.ContentDto.NodeDto.CreateDate, - UpdateDate = dto.ContentVersionDto.VersionDate, - ExpireDate = dto.ExpiresDate.HasValue ? dto.ExpiresDate.Value : (DateTime?)null, - ReleaseDate = dto.ReleaseDate.HasValue ? dto.ReleaseDate.Value : (DateTime?)null, - Version = dto.ContentVersionDto.VersionId, - PublishedState = dto.Published ? PublishedState.Published : PublishedState.Unpublished, - PublishedVersionGuid = dto.DocumentPublishedReadOnlyDto == null ? default(Guid) : dto.DocumentPublishedReadOnlyDto.VersionId - }; + content.DisableChangeTracking(); + + content.Id = _id; + content.Key = dto.ContentVersionDto.ContentDto.NodeDto.UniqueId; + content.Name = dto.Text; + content.NodeName = dto.ContentVersionDto.ContentDto.NodeDto.Text; + content.Path = dto.ContentVersionDto.ContentDto.NodeDto.Path; + content.CreatorId = dto.ContentVersionDto.ContentDto.NodeDto.UserId.Value; + content.WriterId = dto.WriterUserId; + content.Level = dto.ContentVersionDto.ContentDto.NodeDto.Level; + content.ParentId = dto.ContentVersionDto.ContentDto.NodeDto.ParentId; + content.SortOrder = dto.ContentVersionDto.ContentDto.NodeDto.SortOrder; + content.Trashed = dto.ContentVersionDto.ContentDto.NodeDto.Trashed; + content.Published = dto.Published; + content.CreateDate = dto.ContentVersionDto.ContentDto.NodeDto.CreateDate; + content.UpdateDate = dto.ContentVersionDto.VersionDate; + content.ExpireDate = dto.ExpiresDate.HasValue ? dto.ExpiresDate.Value : (DateTime?) null; + content.ReleaseDate = dto.ReleaseDate.HasValue ? dto.ReleaseDate.Value : (DateTime?) null; + content.Version = dto.ContentVersionDto.VersionId; + content.PublishedState = dto.Published ? PublishedState.Published : PublishedState.Unpublished; + content.PublishedVersionGuid = dto.DocumentPublishedReadOnlyDto == null ? default(Guid) : dto.DocumentPublishedReadOnlyDto.VersionId; + } + finally + { + content.EnableChangeTracking(); + } + //on initial construction we don't want to have dirty properties tracked // http://issues.umbraco.org/issue/U4-1946 content.ResetDirtyProperties(false); diff --git a/src/Umbraco.Core/Persistence/Factories/ContentTypeFactory.cs b/src/Umbraco.Core/Persistence/Factories/ContentTypeFactory.cs index 54c7d8d2c9..6fa13654ad 100644 --- a/src/Umbraco.Core/Persistence/Factories/ContentTypeFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/ContentTypeFactory.cs @@ -21,13 +21,22 @@ namespace Umbraco.Core.Persistence.Factories public IContentType BuildContentTypeEntity(ContentTypeDto dto) { var contentType = new ContentType(dto.NodeDto.ParentId); - BuildCommonEntity(contentType, dto); - //on initial construction we don't want to have dirty properties tracked - // http://issues.umbraco.org/issue/U4-1946 - contentType.ResetDirtyProperties(false); + try + { + contentType.DisableChangeTracking(); - return contentType; + BuildCommonEntity(contentType, dto); + + //on initial construction we don't want to have dirty properties tracked + // http://issues.umbraco.org/issue/U4-1946 + contentType.ResetDirtyProperties(false); + return contentType; + } + finally + { + contentType.EnableChangeTracking(); + } } #endregion @@ -37,11 +46,20 @@ namespace Umbraco.Core.Persistence.Factories public IMediaType BuildMediaTypeEntity(ContentTypeDto dto) { var contentType = new MediaType(dto.NodeDto.ParentId); - BuildCommonEntity(contentType, dto); + try + { + contentType.DisableChangeTracking(); - //on initial construction we don't want to have dirty properties tracked - // http://issues.umbraco.org/issue/U4-1946 - contentType.ResetDirtyProperties(false); + BuildCommonEntity(contentType, dto); + + //on initial construction we don't want to have dirty properties tracked + // http://issues.umbraco.org/issue/U4-1946 + contentType.ResetDirtyProperties(false); + } + finally + { + contentType.EnableChangeTracking(); + } return contentType; } diff --git a/src/Umbraco.Core/Persistence/Factories/DataTypeDefinitionFactory.cs b/src/Umbraco.Core/Persistence/Factories/DataTypeDefinitionFactory.cs index 377d70e3cb..cf487fa1a2 100644 --- a/src/Umbraco.Core/Persistence/Factories/DataTypeDefinitionFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/DataTypeDefinitionFactory.cs @@ -19,25 +19,35 @@ namespace Umbraco.Core.Persistence.Factories public IDataTypeDefinition BuildEntity(DataTypeDto dto) { - var dataTypeDefinition = new DataTypeDefinition(dto.PropertyEditorAlias) - { - CreateDate = dto.NodeDto.CreateDate, - DatabaseType = dto.DbType.EnumParse(true), - Id = dto.DataTypeId, - Key = dto.NodeDto.UniqueId, - Level = dto.NodeDto.Level, - UpdateDate = dto.NodeDto.CreateDate, - Name = dto.NodeDto.Text, - ParentId = dto.NodeDto.ParentId, - Path = dto.NodeDto.Path, - SortOrder = dto.NodeDto.SortOrder, - Trashed = dto.NodeDto.Trashed, - CreatorId = dto.NodeDto.UserId.Value - }; - //on initial construction we don't want to have dirty properties tracked - // http://issues.umbraco.org/issue/U4-1946 - dataTypeDefinition.ResetDirtyProperties(false); - return dataTypeDefinition; + var dataTypeDefinition = new DataTypeDefinition(dto.PropertyEditorAlias); + + + try + { + dataTypeDefinition.DisableChangeTracking(); + + dataTypeDefinition.CreateDate = dto.NodeDto.CreateDate; + dataTypeDefinition.DatabaseType = dto.DbType.EnumParse(true); + dataTypeDefinition.Id = dto.DataTypeId; + dataTypeDefinition.Key = dto.NodeDto.UniqueId; + dataTypeDefinition.Level = dto.NodeDto.Level; + dataTypeDefinition.UpdateDate = dto.NodeDto.CreateDate; + dataTypeDefinition.Name = dto.NodeDto.Text; + dataTypeDefinition.ParentId = dto.NodeDto.ParentId; + dataTypeDefinition.Path = dto.NodeDto.Path; + dataTypeDefinition.SortOrder = dto.NodeDto.SortOrder; + dataTypeDefinition.Trashed = dto.NodeDto.Trashed; + dataTypeDefinition.CreatorId = dto.NodeDto.UserId.Value; + + //on initial construction we don't want to have dirty properties tracked + // http://issues.umbraco.org/issue/U4-1946 + dataTypeDefinition.ResetDirtyProperties(false); + return dataTypeDefinition; + } + finally + { + dataTypeDefinition.EnableChangeTracking(); + } } public DataTypeDto BuildDto(IDataTypeDefinition entity) diff --git a/src/Umbraco.Core/Persistence/Factories/DictionaryItemFactory.cs b/src/Umbraco.Core/Persistence/Factories/DictionaryItemFactory.cs index 1b9d73bdd4..4bcfea58ca 100644 --- a/src/Umbraco.Core/Persistence/Factories/DictionaryItemFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/DictionaryItemFactory.cs @@ -10,15 +10,23 @@ namespace Umbraco.Core.Persistence.Factories public IDictionaryItem BuildEntity(DictionaryDto dto) { - var item = new DictionaryItem(dto.Parent, dto.Key) - { - Id = dto.PrimaryKey, - Key = dto.UniqueId - }; - //on initial construction we don't want to have dirty properties tracked - // http://issues.umbraco.org/issue/U4-1946 - item.ResetDirtyProperties(false); - return item; + var item = new DictionaryItem(dto.Parent, dto.Key); + + try + { + item.DisableChangeTracking(); + + item.Id = dto.PrimaryKey; + item.Key = dto.UniqueId; + //on initial construction we don't want to have dirty properties tracked + // http://issues.umbraco.org/issue/U4-1946 + item.ResetDirtyProperties(false); + return item; + } + finally + { + item.EnableChangeTracking(); + } } public DictionaryDto BuildDto(IDictionaryItem entity) diff --git a/src/Umbraco.Core/Persistence/Factories/DictionaryTranslationFactory.cs b/src/Umbraco.Core/Persistence/Factories/DictionaryTranslationFactory.cs index 65297b9529..2a931f6069 100644 --- a/src/Umbraco.Core/Persistence/Factories/DictionaryTranslationFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/DictionaryTranslationFactory.cs @@ -17,13 +17,23 @@ namespace Umbraco.Core.Persistence.Factories public IDictionaryTranslation BuildEntity(LanguageTextDto dto) { - var item = new DictionaryTranslation(dto.LanguageId, dto.Value, _uniqueId) - {Id = dto.PrimaryKey}; + var item = new DictionaryTranslation(dto.LanguageId, dto.Value, _uniqueId); - //on initial construction we don't want to have dirty properties tracked - // http://issues.umbraco.org/issue/U4-1946 - item.ResetDirtyProperties(false); - return item; + try + { + item.DisableChangeTracking(); + + item.Id = dto.PrimaryKey; + + //on initial construction we don't want to have dirty properties tracked + // http://issues.umbraco.org/issue/U4-1946 + item.ResetDirtyProperties(false); + return item; + } + finally + { + item.EnableChangeTracking(); + } } public LanguageTextDto BuildDto(IDictionaryTranslation entity) diff --git a/src/Umbraco.Core/Persistence/Factories/MacroFactory.cs b/src/Umbraco.Core/Persistence/Factories/MacroFactory.cs index 66b493ea4d..2ec20b08eb 100644 --- a/src/Umbraco.Core/Persistence/Factories/MacroFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/MacroFactory.cs @@ -12,15 +12,26 @@ namespace Umbraco.Core.Persistence.Factories public IMacro BuildEntity(MacroDto dto) { var model = new Macro(dto.Id, dto.UseInEditor, dto.RefreshRate, dto.Alias, dto.Name, dto.ScriptType, dto.ScriptAssembly, dto.Xslt, dto.CacheByPage, dto.CachePersonalized, dto.DontRender, dto.Python); - foreach (var p in dto.MacroPropertyDtos) + + + try { - model.Properties.Add(new MacroProperty(p.Id, p.Alias, p.Name, p.SortOrder, p.EditorAlias)); + model.DisableChangeTracking(); + + foreach (var p in dto.MacroPropertyDtos) + { + model.Properties.Add(new MacroProperty(p.Id, p.Alias, p.Name, p.SortOrder, p.EditorAlias)); + } + + //on initial construction we don't want to have dirty properties tracked + // http://issues.umbraco.org/issue/U4-1946 + model.ResetDirtyProperties(false); + return model; + } + finally + { + model.EnableChangeTracking(); } - - //on initial construction we don't want to have dirty properties tracked - // http://issues.umbraco.org/issue/U4-1946 - model.ResetDirtyProperties(false); - return model; } public MacroDto BuildDto(IMacro entity) diff --git a/src/Umbraco.Core/Persistence/Factories/MediaFactory.cs b/src/Umbraco.Core/Persistence/Factories/MediaFactory.cs index 2d8edcac52..0fcb654cb7 100644 --- a/src/Umbraco.Core/Persistence/Factories/MediaFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/MediaFactory.cs @@ -29,24 +29,32 @@ namespace Umbraco.Core.Persistence.Factories public IMedia BuildEntity(ContentVersionDto dto) { - var media = new Models.Media(dto.ContentDto.NodeDto.Text, dto.ContentDto.NodeDto.ParentId, _contentType) - { - Id = _id, - Key = dto.ContentDto.NodeDto.UniqueId, - Path = dto.ContentDto.NodeDto.Path, - CreatorId = dto.ContentDto.NodeDto.UserId.Value, - Level = dto.ContentDto.NodeDto.Level, - ParentId = dto.ContentDto.NodeDto.ParentId, - SortOrder = dto.ContentDto.NodeDto.SortOrder, - Trashed = dto.ContentDto.NodeDto.Trashed, - CreateDate = dto.ContentDto.NodeDto.CreateDate, - UpdateDate = dto.VersionDate, - Version = dto.VersionId - }; - //on initial construction we don't want to have dirty properties tracked - // http://issues.umbraco.org/issue/U4-1946 - media.ResetDirtyProperties(false); - return media; + var media = new Models.Media(dto.ContentDto.NodeDto.Text, dto.ContentDto.NodeDto.ParentId, _contentType); + + try + { + media.DisableChangeTracking(); + + media.Id = _id; + media.Key = dto.ContentDto.NodeDto.UniqueId; + media.Path = dto.ContentDto.NodeDto.Path; + media.CreatorId = dto.ContentDto.NodeDto.UserId.Value; + media.Level = dto.ContentDto.NodeDto.Level; + media.ParentId = dto.ContentDto.NodeDto.ParentId; + media.SortOrder = dto.ContentDto.NodeDto.SortOrder; + media.Trashed = dto.ContentDto.NodeDto.Trashed; + media.CreateDate = dto.ContentDto.NodeDto.CreateDate; + media.UpdateDate = dto.VersionDate; + media.Version = dto.VersionId; + //on initial construction we don't want to have dirty properties tracked + // http://issues.umbraco.org/issue/U4-1946 + media.ResetDirtyProperties(false); + return media; + } + finally + { + media.EnableChangeTracking(); + } } public ContentVersionDto BuildDto(IMedia entity) diff --git a/src/Umbraco.Core/Persistence/Factories/MemberFactory.cs b/src/Umbraco.Core/Persistence/Factories/MemberFactory.cs index a35c472f24..2901f48539 100644 --- a/src/Umbraco.Core/Persistence/Factories/MemberFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/MemberFactory.cs @@ -31,26 +31,35 @@ namespace Umbraco.Core.Persistence.Factories public IMember BuildEntity(MemberDto dto) { var member = new Member( - dto.ContentVersionDto.ContentDto.NodeDto.Text, - dto.Email,dto.LoginName,dto.Password, _contentType) + dto.ContentVersionDto.ContentDto.NodeDto.Text, + dto.Email, dto.LoginName, dto.Password, _contentType); + + try { - Id = _id, - Key = dto.ContentVersionDto.ContentDto.NodeDto.UniqueId, - Path = dto.ContentVersionDto.ContentDto.NodeDto.Path, - CreatorId = dto.ContentVersionDto.ContentDto.NodeDto.UserId.Value, - Level = dto.ContentVersionDto.ContentDto.NodeDto.Level, - ParentId = dto.ContentVersionDto.ContentDto.NodeDto.ParentId, - SortOrder = dto.ContentVersionDto.ContentDto.NodeDto.SortOrder, - Trashed = dto.ContentVersionDto.ContentDto.NodeDto.Trashed, - CreateDate = dto.ContentVersionDto.ContentDto.NodeDto.CreateDate, - UpdateDate = dto.ContentVersionDto.VersionDate, - Version = dto.ContentVersionDto.VersionId - }; - member.ProviderUserKey = member.Key; - //on initial construction we don't want to have dirty properties tracked - // http://issues.umbraco.org/issue/U4-1946 - member.ResetDirtyProperties(false); - return member; + member.DisableChangeTracking(); + + member.Id = _id; + member.Key = dto.ContentVersionDto.ContentDto.NodeDto.UniqueId; + member.Path = dto.ContentVersionDto.ContentDto.NodeDto.Path; + member.CreatorId = dto.ContentVersionDto.ContentDto.NodeDto.UserId.Value; + member.Level = dto.ContentVersionDto.ContentDto.NodeDto.Level; + member.ParentId = dto.ContentVersionDto.ContentDto.NodeDto.ParentId; + member.SortOrder = dto.ContentVersionDto.ContentDto.NodeDto.SortOrder; + member.Trashed = dto.ContentVersionDto.ContentDto.NodeDto.Trashed; + member.CreateDate = dto.ContentVersionDto.ContentDto.NodeDto.CreateDate; + member.UpdateDate = dto.ContentVersionDto.VersionDate; + member.Version = dto.ContentVersionDto.VersionId; + + member.ProviderUserKey = member.Key; + //on initial construction we don't want to have dirty properties tracked + // http://issues.umbraco.org/issue/U4-1946 + member.ResetDirtyProperties(false); + return member; + } + finally + { + member.EnableChangeTracking(); + } } public MemberDto BuildDto(IMember entity) diff --git a/src/Umbraco.Core/Persistence/Factories/MemberGroupFactory.cs b/src/Umbraco.Core/Persistence/Factories/MemberGroupFactory.cs index 9544d170e2..a4e069e85c 100644 --- a/src/Umbraco.Core/Persistence/Factories/MemberGroupFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/MemberGroupFactory.cs @@ -18,18 +18,26 @@ namespace Umbraco.Core.Persistence.Factories public IMemberGroup BuildEntity(NodeDto dto) { - var template = new MemberGroup + var group = new MemberGroup(); + + try { - CreateDate = dto.CreateDate, - Id = dto.NodeId, - Key = dto.UniqueId, - Name = dto.Text - }; + group.DisableChangeTracking(); - //on initial construction we don't want to have dirty properties tracked - // http://issues.umbraco.org/issue/U4-1946 - template.ResetDirtyProperties(false); - return template; + group.CreateDate = dto.CreateDate; + group.Id = dto.NodeId; + group.Key = dto.UniqueId; + group.Name = dto.Text; + + //on initial construction we don't want to have dirty properties tracked + // http://issues.umbraco.org/issue/U4-1946 + group.ResetDirtyProperties(false); + return group; + } + finally + { + group.EnableChangeTracking(); + } } public NodeDto BuildDto(IMemberGroup entity) diff --git a/src/Umbraco.Core/Persistence/Factories/MemberTypeReadOnlyFactory.cs b/src/Umbraco.Core/Persistence/Factories/MemberTypeReadOnlyFactory.cs index eebbc34eda..10650528a4 100644 --- a/src/Umbraco.Core/Persistence/Factories/MemberTypeReadOnlyFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/MemberTypeReadOnlyFactory.cs @@ -12,48 +12,56 @@ namespace Umbraco.Core.Persistence.Factories public IMemberType BuildEntity(MemberTypeReadOnlyDto dto) { var standardPropertyTypes = Constants.Conventions.Member.GetStandardPropertyTypeStubs(); - - var memberType = new MemberType(dto.ParentId) - { - Alias = dto.Alias, - AllowedAsRoot = dto.AllowAtRoot, - CreateDate = dto.CreateDate, - CreatorId = dto.UserId.HasValue ? dto.UserId.Value : 0, - Description = dto.Description, - Icon = dto.Icon, - Id = dto.NodeId, - IsContainer = dto.IsContainer, - Key = dto.UniqueId.Value, - Level = dto.Level, - Name = dto.Text, - Path = dto.Path, - SortOrder = dto.SortOrder, - Thumbnail = dto.Thumbnail, - Trashed = dto.Trashed, - UpdateDate = dto.CreateDate, - AllowedContentTypes = Enumerable.Empty() - }; - var propertyTypeGroupCollection = GetPropertyTypeGroupCollection(dto, memberType, standardPropertyTypes); - memberType.PropertyGroups = propertyTypeGroupCollection; + var memberType = new MemberType(dto.ParentId); - var propertyTypes = GetPropertyTypes(dto, memberType, standardPropertyTypes); - - //By Convention we add 9 stnd PropertyTypes - This is only here to support loading of types that didn't have these conventions before. - foreach (var standardPropertyType in standardPropertyTypes) + try { - if(dto.PropertyTypes.Any(x => x.Alias.Equals(standardPropertyType.Key))) continue; - - //Add the standard PropertyType to the current list - propertyTypes.Add(standardPropertyType.Value); + memberType.DisableChangeTracking(); - //Internal dictionary for adding "MemberCanEdit" and "VisibleOnProfile" properties to each PropertyType - memberType.MemberTypePropertyTypes.Add(standardPropertyType.Key, - new MemberTypePropertyProfileAccess(false, false)); + memberType.Alias = dto.Alias; + memberType.AllowedAsRoot = dto.AllowAtRoot; + memberType.CreateDate = dto.CreateDate; + memberType.CreatorId = dto.UserId.HasValue ? dto.UserId.Value : 0; + memberType.Description = dto.Description; + memberType.Icon = dto.Icon; + memberType.Id = dto.NodeId; + memberType.IsContainer = dto.IsContainer; + memberType.Key = dto.UniqueId.Value; + memberType.Level = dto.Level; + memberType.Name = dto.Text; + memberType.Path = dto.Path; + memberType.SortOrder = dto.SortOrder; + memberType.Thumbnail = dto.Thumbnail; + memberType.Trashed = dto.Trashed; + memberType.UpdateDate = dto.CreateDate; + memberType.AllowedContentTypes = Enumerable.Empty(); + + var propertyTypeGroupCollection = GetPropertyTypeGroupCollection(dto, memberType, standardPropertyTypes); + memberType.PropertyGroups = propertyTypeGroupCollection; + + var propertyTypes = GetPropertyTypes(dto, memberType, standardPropertyTypes); + + //By Convention we add 9 stnd PropertyTypes - This is only here to support loading of types that didn't have these conventions before. + foreach (var standardPropertyType in standardPropertyTypes) + { + if (dto.PropertyTypes.Any(x => x.Alias.Equals(standardPropertyType.Key))) continue; + + //Add the standard PropertyType to the current list + propertyTypes.Add(standardPropertyType.Value); + + //Internal dictionary for adding "MemberCanEdit" and "VisibleOnProfile" properties to each PropertyType + memberType.MemberTypePropertyTypes.Add(standardPropertyType.Key, + new MemberTypePropertyProfileAccess(false, false)); + } + memberType.NoGroupPropertyTypes = propertyTypes; + + return memberType; + } + finally + { + memberType.EnableChangeTracking(); } - memberType.NoGroupPropertyTypes = propertyTypes; - - return memberType; } private PropertyGroupCollection GetPropertyTypeGroupCollection(MemberTypeReadOnlyDto dto, MemberType memberType, Dictionary standardProps) diff --git a/src/Umbraco.Core/Persistence/Factories/PropertyFactory.cs b/src/Umbraco.Core/Persistence/Factories/PropertyFactory.cs index 8d51b627ea..a69539e9ea 100644 --- a/src/Umbraco.Core/Persistence/Factories/PropertyFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/PropertyFactory.cs @@ -42,12 +42,22 @@ namespace Umbraco.Core.Persistence.Factories : propertyType.CreatePropertyFromRawValue(propertyDataDto.GetValue, propertyDataDto.VersionId.Value, propertyDataDto.Id); - //on initial construction we don't want to have dirty properties tracked - property.CreateDate = _createDate; - property.UpdateDate = _updateDate; - // http://issues.umbraco.org/issue/U4-1946 - property.ResetDirtyProperties(false); - properties.Add(property); + try + { + //on initial construction we don't want to have dirty properties tracked + property.DisableChangeTracking(); + + property.CreateDate = _createDate; + property.UpdateDate = _updateDate; + // http://issues.umbraco.org/issue/U4-1946 + property.ResetDirtyProperties(false); + properties.Add(property); + } + finally + { + property.EnableChangeTracking(); + } + } return properties; diff --git a/src/Umbraco.Core/Persistence/Factories/PropertyGroupFactory.cs b/src/Umbraco.Core/Persistence/Factories/PropertyGroupFactory.cs index 2dfb996bb3..e1db8dcebf 100644 --- a/src/Umbraco.Core/Persistence/Factories/PropertyGroupFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/PropertyGroupFactory.cs @@ -39,47 +39,65 @@ namespace Umbraco.Core.Persistence.Factories { var group = new PropertyGroup(); - // if the group is defined on the current content type, - // assign its identifier, else it will be zero - if (groupDto.ContentTypeNodeId == _contentTypeId) - group.Id = groupDto.Id; - - group.Name = groupDto.Text; - group.SortOrder = groupDto.SortOrder; - group.PropertyTypes = new PropertyTypeCollection(); - group.Key = groupDto.UniqueId; - - //Because we are likely to have a group with no PropertyTypes we need to ensure that these are excluded - var typeDtos = groupDto.PropertyTypeDtos.Where(x => x.Id > 0); - foreach (var typeDto in typeDtos) + try { - var tempGroupDto = groupDto; - var propertyType = _propertyTypeCtor(typeDto.DataTypeDto.PropertyEditorAlias, - typeDto.DataTypeDto.DbType.EnumParse(true), - typeDto.Alias); + group.DisableChangeTracking(); - propertyType.Alias = typeDto.Alias; - propertyType.DataTypeDefinitionId = typeDto.DataTypeId; - propertyType.Description = typeDto.Description; - propertyType.Id = typeDto.Id; - propertyType.Key = typeDto.UniqueId; - propertyType.Name = typeDto.Name; - propertyType.Mandatory = typeDto.Mandatory; - propertyType.SortOrder = typeDto.SortOrder; - propertyType.ValidationRegExp = typeDto.ValidationRegExp; - propertyType.PropertyGroupId = new Lazy(() => tempGroupDto.Id); - propertyType.CreateDate = _createDate; - propertyType.UpdateDate = _updateDate; + // if the group is defined on the current content type, + // assign its identifier, else it will be zero + if (groupDto.ContentTypeNodeId == _contentTypeId) + group.Id = groupDto.Id; + group.Name = groupDto.Text; + group.SortOrder = groupDto.SortOrder; + group.PropertyTypes = new PropertyTypeCollection(); + group.Key = groupDto.UniqueId; + + //Because we are likely to have a group with no PropertyTypes we need to ensure that these are excluded + var typeDtos = groupDto.PropertyTypeDtos.Where(x => x.Id > 0); + foreach (var typeDto in typeDtos) + { + var tempGroupDto = groupDto; + var propertyType = _propertyTypeCtor(typeDto.DataTypeDto.PropertyEditorAlias, + typeDto.DataTypeDto.DbType.EnumParse(true), + typeDto.Alias); + + try + { + propertyType.DisableChangeTracking(); + + propertyType.Alias = typeDto.Alias; + propertyType.DataTypeDefinitionId = typeDto.DataTypeId; + propertyType.Description = typeDto.Description; + propertyType.Id = typeDto.Id; + propertyType.Key = typeDto.UniqueId; + propertyType.Name = typeDto.Name; + propertyType.Mandatory = typeDto.Mandatory; + propertyType.SortOrder = typeDto.SortOrder; + propertyType.ValidationRegExp = typeDto.ValidationRegExp; + propertyType.PropertyGroupId = new Lazy(() => tempGroupDto.Id); + propertyType.CreateDate = _createDate; + propertyType.UpdateDate = _updateDate; + + //on initial construction we don't want to have dirty properties tracked + // http://issues.umbraco.org/issue/U4-1946 + propertyType.ResetDirtyProperties(false); + group.PropertyTypes.Add(propertyType); + } + finally + { + propertyType.EnableChangeTracking(); + } + } //on initial construction we don't want to have dirty properties tracked // http://issues.umbraco.org/issue/U4-1946 - propertyType.ResetDirtyProperties(false); - group.PropertyTypes.Add(propertyType); + group.ResetDirtyProperties(false); + propertyGroups.Add(group); + } + finally + { + group.EnableChangeTracking(); } - //on initial construction we don't want to have dirty properties tracked - // http://issues.umbraco.org/issue/U4-1946 - group.ResetDirtyProperties(false); - propertyGroups.Add(group); } return propertyGroups; diff --git a/src/Umbraco.Core/Persistence/Factories/RelationFactory.cs b/src/Umbraco.Core/Persistence/Factories/RelationFactory.cs index 5d614fb6d3..47adf75d89 100644 --- a/src/Umbraco.Core/Persistence/Factories/RelationFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/RelationFactory.cs @@ -16,17 +16,26 @@ namespace Umbraco.Core.Persistence.Factories public IRelation BuildEntity(RelationDto dto) { - var entity = new Relation(dto.ParentId, dto.ChildId, _relationType) + var entity = new Relation(dto.ParentId, dto.ChildId, _relationType); + + try { - Comment = dto.Comment, - CreateDate = dto.Datetime, - Id = dto.Id, - UpdateDate = dto.Datetime - }; - //on initial construction we don't want to have dirty properties tracked - // http://issues.umbraco.org/issue/U4-1946 - entity.ResetDirtyProperties(false); - return entity; + entity.DisableChangeTracking(); + + entity.Comment = dto.Comment; + entity.CreateDate = dto.Datetime; + entity.Id = dto.Id; + entity.UpdateDate = dto.Datetime; + + //on initial construction we don't want to have dirty properties tracked + // http://issues.umbraco.org/issue/U4-1946 + entity.ResetDirtyProperties(false); + return entity; + } + finally + { + entity.EnableChangeTracking(); + } } public RelationDto BuildDto(IRelation entity) diff --git a/src/Umbraco.Core/Persistence/Factories/RelationTypeFactory.cs b/src/Umbraco.Core/Persistence/Factories/RelationTypeFactory.cs index 358b652d0b..98d4f30042 100644 --- a/src/Umbraco.Core/Persistence/Factories/RelationTypeFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/RelationTypeFactory.cs @@ -9,16 +9,25 @@ namespace Umbraco.Core.Persistence.Factories public IRelationType BuildEntity(RelationTypeDto dto) { - var entity = new RelationType(dto.ChildObjectType, dto.ParentObjectType, dto.Alias) + var entity = new RelationType(dto.ChildObjectType, dto.ParentObjectType, dto.Alias); + + try { - Id = dto.Id, - IsBidirectional = dto.Dual, - Name = dto.Name - }; - //on initial construction we don't want to have dirty properties tracked - // http://issues.umbraco.org/issue/U4-1946 - entity.ResetDirtyProperties(false); - return entity; + entity.DisableChangeTracking(); + + entity.Id = dto.Id; + entity.IsBidirectional = dto.Dual; + entity.Name = dto.Name; + + //on initial construction we don't want to have dirty properties tracked + // http://issues.umbraco.org/issue/U4-1946 + entity.ResetDirtyProperties(false); + return entity; + } + finally + { + entity.EnableChangeTracking(); + } } public RelationTypeDto BuildDto(IRelationType entity) diff --git a/src/Umbraco.Core/Persistence/Factories/TaskFactory.cs b/src/Umbraco.Core/Persistence/Factories/TaskFactory.cs index 81a6703324..d60403abea 100644 --- a/src/Umbraco.Core/Persistence/Factories/TaskFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/TaskFactory.cs @@ -12,20 +12,28 @@ namespace Umbraco.Core.Persistence.Factories { public Task BuildEntity(TaskDto dto) { - var entity = new Task(new TaskType(dto.TaskTypeDto.Alias) { Id = dto.TaskTypeDto.Id }) + var entity = new Task(new TaskType(dto.TaskTypeDto.Alias) { Id = dto.TaskTypeDto.Id }); + + try { - Closed = dto.Closed, - AssigneeUserId = dto.UserId, - Comment = dto.Comment, - CreateDate = dto.DateTime, - EntityId = dto.NodeId, - Id = dto.Id, - OwnerUserId = dto.ParentUserId, - }; - //on initial construction we don't want to have dirty properties tracked - // http://issues.umbraco.org/issue/U4-1946 - entity.ResetDirtyProperties(false); - return entity; + entity.DisableChangeTracking(); + + entity.Closed = dto.Closed; + entity.AssigneeUserId = dto.UserId; + entity.Comment = dto.Comment; + entity.CreateDate = dto.DateTime; + entity.EntityId = dto.NodeId; + entity.Id = dto.Id; + entity.OwnerUserId = dto.ParentUserId; + //on initial construction we don't want to have dirty properties tracked + // http://issues.umbraco.org/issue/U4-1946 + entity.ResetDirtyProperties(false); + return entity; + } + finally + { + entity.EnableChangeTracking(); + } } public TaskDto BuildDto(Task entity) diff --git a/src/Umbraco.Core/Persistence/Factories/TemplateFactory.cs b/src/Umbraco.Core/Persistence/Factories/TemplateFactory.cs index 60cde916b6..ecff14d99c 100644 --- a/src/Umbraco.Core/Persistence/Factories/TemplateFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/TemplateFactory.cs @@ -35,23 +35,31 @@ namespace Umbraco.Core.Persistence.Factories public Template BuildEntity(TemplateDto dto, IEnumerable childDefinitions, Func getFileContent) { - var template = new Template(dto.NodeDto.Text, dto.Alias, getFileContent) - { - CreateDate = dto.NodeDto.CreateDate, - Id = dto.NodeId, - Key = dto.NodeDto.UniqueId, - Path = dto.NodeDto.Path - }; + var template = new Template(dto.NodeDto.Text, dto.Alias, getFileContent); - template.IsMasterTemplate = childDefinitions.Any(x => x.ParentId == dto.NodeId); + try + { + template.DisableChangeTracking(); - if(dto.NodeDto.ParentId > 0) - template.MasterTemplateId = new Lazy(() => dto.NodeDto.ParentId); + template.CreateDate = dto.NodeDto.CreateDate; + template.Id = dto.NodeId; + template.Key = dto.NodeDto.UniqueId; + template.Path = dto.NodeDto.Path; - //on initial construction we don't want to have dirty properties tracked - // http://issues.umbraco.org/issue/U4-1946 - template.ResetDirtyProperties(false); - return template; + template.IsMasterTemplate = childDefinitions.Any(x => x.ParentId == dto.NodeId); + + if (dto.NodeDto.ParentId > 0) + template.MasterTemplateId = new Lazy(() => dto.NodeDto.ParentId); + + //on initial construction we don't want to have dirty properties tracked + // http://issues.umbraco.org/issue/U4-1946 + template.ResetDirtyProperties(false); + return template; + } + finally + { + template.EnableChangeTracking(); + } } public TemplateDto BuildDto(Template entity) diff --git a/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs b/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs index 660cc95029..18073c088e 100644 --- a/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/UmbracoEntityFactory.cs @@ -28,44 +28,52 @@ namespace Umbraco.Core.Persistence.Factories { var asDictionary = (IDictionary)d; - var entity = new UmbracoEntity(d.trashed) - { - CreateDate = d.createDate, - CreatorId = d.nodeUser, - Id = d.id, - Key = d.uniqueID, - Level = d.level, - Name = d.text, - NodeObjectTypeId = d.nodeObjectType, - ParentId = d.parentID, - Path = d.path, - SortOrder = d.sortOrder, - HasChildren = d.children > 0, - ContentTypeAlias = asDictionary.ContainsKey("alias") ? (d.alias ?? string.Empty) : string.Empty, - ContentTypeIcon = asDictionary.ContainsKey("icon") ? (d.icon ?? string.Empty) : string.Empty, - ContentTypeThumbnail = asDictionary.ContainsKey("thumbnail") ? (d.thumbnail ?? string.Empty) : string.Empty, - }; + var entity = new UmbracoEntity(d.trashed); - var publishedVersion = default(Guid); - //some content items don't have a published version - if (asDictionary.ContainsKey("publishedVersion") && asDictionary["publishedVersion"] != null) + try { - Guid.TryParse(d.publishedVersion.ToString(), out publishedVersion); - } - var newestVersion = default(Guid); - if (asDictionary.ContainsKey("newestVersion") && d.newestVersion != null) - { - Guid.TryParse(d.newestVersion.ToString(), out newestVersion); - } + entity.DisableChangeTracking(); - entity.IsPublished = publishedVersion != default(Guid) || (newestVersion != default(Guid) && publishedVersion == newestVersion); - entity.IsDraft = newestVersion != default(Guid) && (publishedVersion == default(Guid) || publishedVersion != newestVersion); - entity.HasPendingChanges = (publishedVersion != default(Guid) && newestVersion != default(Guid)) && publishedVersion != newestVersion; - - //Now we can assign the additional data! - AddAdditionalData(entity, asDictionary); - - return entity; + entity.CreateDate = d.createDate; + entity.CreatorId = d.nodeUser; + entity.Id = d.id; + entity.Key = d.uniqueID; + entity.Level = d.level; + entity.Name = d.text; + entity.NodeObjectTypeId = d.nodeObjectType; + entity.ParentId = d.parentID; + entity.Path = d.path; + entity.SortOrder = d.sortOrder; + entity.HasChildren = d.children > 0; + entity.ContentTypeAlias = asDictionary.ContainsKey("alias") ? (d.alias ?? string.Empty) : string.Empty; + entity.ContentTypeIcon = asDictionary.ContainsKey("icon") ? (d.icon ?? string.Empty) : string.Empty; + entity.ContentTypeThumbnail = asDictionary.ContainsKey("thumbnail") ? (d.thumbnail ?? string.Empty) : string.Empty; + + var publishedVersion = default(Guid); + //some content items don't have a published version + if (asDictionary.ContainsKey("publishedVersion") && asDictionary["publishedVersion"] != null) + { + Guid.TryParse(d.publishedVersion.ToString(), out publishedVersion); + } + var newestVersion = default(Guid); + if (asDictionary.ContainsKey("newestVersion") && d.newestVersion != null) + { + Guid.TryParse(d.newestVersion.ToString(), out newestVersion); + } + + entity.IsPublished = publishedVersion != default(Guid) || (newestVersion != default(Guid) && publishedVersion == newestVersion); + entity.IsDraft = newestVersion != default(Guid) && (publishedVersion == default(Guid) || publishedVersion != newestVersion); + entity.HasPendingChanges = (publishedVersion != default(Guid) && newestVersion != default(Guid)) && publishedVersion != newestVersion; + + //Now we can assign the additional data! + AddAdditionalData(entity, asDictionary); + + return entity; + } + finally + { + entity.EnableChangeTracking(); + } } public UmbracoEntity BuildEntity(EntityRepository.UmbracoEntityDto dto) diff --git a/src/Umbraco.Core/Persistence/Factories/UserFactory.cs b/src/Umbraco.Core/Persistence/Factories/UserFactory.cs index bf6ff7d09e..0a13c82447 100644 --- a/src/Umbraco.Core/Persistence/Factories/UserFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/UserFactory.cs @@ -21,36 +21,44 @@ namespace Umbraco.Core.Persistence.Factories public IUser BuildEntity(UserDto dto) { var guidId = dto.Id.ToGuid(); - var user = new User(_userType) - { - Id = dto.Id, - Key = guidId, - StartContentId = dto.ContentStartId, - StartMediaId = dto.MediaStartId.HasValue ? dto.MediaStartId.Value : -1, - RawPasswordValue = dto.Password, - Username = dto.Login, - Name = dto.UserName, - IsLockedOut = dto.NoConsole, - IsApproved = dto.Disabled == false, - Email = dto.Email, - Language = dto.UserLanguage, - SecurityStamp = dto.SecurityStampToken, - FailedPasswordAttempts = dto.FailedLoginAttempts ?? 0, - LastLockoutDate = dto.LastLockoutDate ?? DateTime.MinValue, - LastLoginDate = dto.LastLoginDate ?? DateTime.MinValue, - LastPasswordChangeDate = dto.LastPasswordChangeDate ?? DateTime.MinValue - }; + var user = new User(_userType); - foreach (var app in dto.User2AppDtos) + try { - user.AddAllowedSection(app.AppAlias); + user.DisableChangeTracking(); + + user.Id = dto.Id; + user.Key = guidId; + user.StartContentId = dto.ContentStartId; + user.StartMediaId = dto.MediaStartId.HasValue ? dto.MediaStartId.Value : -1; + user.RawPasswordValue = dto.Password; + user.Username = dto.Login; + user.Name = dto.UserName; + user.IsLockedOut = dto.NoConsole; + user.IsApproved = dto.Disabled == false; + user.Email = dto.Email; + user.Language = dto.UserLanguage; + user.SecurityStamp = dto.SecurityStampToken; + user.FailedPasswordAttempts = dto.FailedLoginAttempts ?? 0; + user.LastLockoutDate = dto.LastLockoutDate ?? DateTime.MinValue; + user.LastLoginDate = dto.LastLoginDate ?? DateTime.MinValue; + user.LastPasswordChangeDate = dto.LastPasswordChangeDate ?? DateTime.MinValue; + + foreach (var app in dto.User2AppDtos) + { + user.AddAllowedSection(app.AppAlias); + } + + //on initial construction we don't want to have dirty properties tracked + // http://issues.umbraco.org/issue/U4-1946 + user.ResetDirtyProperties(false); + + return user; + } + finally + { + user.EnableChangeTracking(); } - - //on initial construction we don't want to have dirty properties tracked - // http://issues.umbraco.org/issue/U4-1946 - user.ResetDirtyProperties(false); - - return user; } public UserDto BuildDto(IUser entity) diff --git a/src/Umbraco.Core/Persistence/Factories/UserTypeFactory.cs b/src/Umbraco.Core/Persistence/Factories/UserTypeFactory.cs index b5718b7c3b..5f9cfac994 100644 --- a/src/Umbraco.Core/Persistence/Factories/UserTypeFactory.cs +++ b/src/Umbraco.Core/Persistence/Factories/UserTypeFactory.cs @@ -11,19 +11,27 @@ namespace Umbraco.Core.Persistence.Factories public IUserType BuildEntity(UserTypeDto dto) { - var userType = new UserType - { - Alias = dto.Alias, - Id = dto.Id, - Name = dto.Name, - Permissions = dto.DefaultPermissions.IsNullOrWhiteSpace() - ? Enumerable.Empty() - : dto.DefaultPermissions.ToCharArray().Select(x => x.ToString(CultureInfo.InvariantCulture)) - }; - //on initial construction we don't want to have dirty properties tracked - // http://issues.umbraco.org/issue/U4-1946 - userType.ResetDirtyProperties(false); - return userType; + var userType = new UserType(); + + try + { + userType.DisableChangeTracking(); + + userType.Alias = dto.Alias; + userType.Id = dto.Id; + userType.Name = dto.Name; + userType.Permissions = dto.DefaultPermissions.IsNullOrWhiteSpace() + ? Enumerable.Empty() + : dto.DefaultPermissions.ToCharArray().Select(x => x.ToString(CultureInfo.InvariantCulture)); + //on initial construction we don't want to have dirty properties tracked + // http://issues.umbraco.org/issue/U4-1946 + userType.ResetDirtyProperties(false); + return userType; + } + finally + { + userType.EnableChangeTracking(); + } } public UserTypeDto BuildDto(IUserType entity) diff --git a/src/UmbracoExamine/UmbracoContentIndexer.cs b/src/UmbracoExamine/UmbracoContentIndexer.cs index 92a1fb776e..4fcf51deae 100644 --- a/src/UmbracoExamine/UmbracoContentIndexer.cs +++ b/src/UmbracoExamine/UmbracoContentIndexer.cs @@ -349,7 +349,7 @@ namespace UmbracoExamine protected override void PerformIndexAll(string type) { - const int pageSize = 5000; + const int pageSize = 10000; var pageIndex = 0; switch (type) From d0c030a34c2e5dcb879b270d2fdbcb981a0f8a9e Mon Sep 17 00:00:00 2001 From: Stephan Date: Thu, 26 May 2016 16:49:55 +0200 Subject: [PATCH 092/535] Reduce dictionary allocs in TracksChangesEntityBase --- .../EntityBase/TracksChangesEntityBase.cs | 41 +++++++++---------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/src/Umbraco.Core/Models/EntityBase/TracksChangesEntityBase.cs b/src/Umbraco.Core/Models/EntityBase/TracksChangesEntityBase.cs index 8e4fbc13f5..109084e9b9 100644 --- a/src/Umbraco.Core/Models/EntityBase/TracksChangesEntityBase.cs +++ b/src/Umbraco.Core/Models/EntityBase/TracksChangesEntityBase.cs @@ -18,7 +18,9 @@ namespace Umbraco.Core.Models.EntityBase //TODO: This needs to go on to ICanBeDirty http://issues.umbraco.org/issue/U4-5662 public virtual IEnumerable GetDirtyProperties() { - return _propertyChangedInfo.Where(x => x.Value).Select(x => x.Key); + return _propertyChangedInfo == null + ? Enumerable.Empty() + : _propertyChangedInfo.Where(x => x.Value).Select(x => x.Key); } private bool _changeTrackingEnabled = true; @@ -26,12 +28,12 @@ namespace Umbraco.Core.Models.EntityBase /// /// Tracks the properties that have changed /// - private IDictionary _propertyChangedInfo = new Dictionary(); + private IDictionary _propertyChangedInfo; /// /// Tracks the properties that we're changed before the last commit (or last call to ResetDirtyProperties) /// - private IDictionary _lastPropertyChangedInfo = null; + private IDictionary _lastPropertyChangedInfo; /// /// Property changed event @@ -47,12 +49,12 @@ namespace Umbraco.Core.Models.EntityBase //return if we're not tracking changes if (_changeTrackingEnabled == false) return; + if (_propertyChangedInfo == null) + _propertyChangedInfo = new Dictionary(); + _propertyChangedInfo[propertyInfo.Name] = true; - if (PropertyChanged != null) - { - PropertyChanged(this, new PropertyChangedEventArgs(propertyInfo.Name)); - } + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyInfo.Name)); } /// @@ -62,7 +64,7 @@ namespace Umbraco.Core.Models.EntityBase /// True if Property is dirty, otherwise False public virtual bool IsPropertyDirty(string propertyName) { - return _propertyChangedInfo.Any(x => x.Key == propertyName); + return _propertyChangedInfo != null && _propertyChangedInfo.Any(x => x.Key == propertyName); } /// @@ -71,7 +73,7 @@ namespace Umbraco.Core.Models.EntityBase /// True if entity is dirty, otherwise False public virtual bool IsDirty() { - return _propertyChangedInfo.Any(); + return _propertyChangedInfo != null && _propertyChangedInfo.Any(); } /// @@ -100,7 +102,7 @@ namespace Umbraco.Core.Models.EntityBase { //NOTE: We cannot .Clear() because when we memberwise clone this will be the SAME // instance as the one on the clone, so we need to create a new instance. - _lastPropertyChangedInfo = new Dictionary(); + _lastPropertyChangedInfo = null; } /// @@ -135,13 +137,13 @@ namespace Umbraco.Core.Models.EntityBase //NOTE: We cannot .Clear() because when we memberwise clone this will be the SAME // instance as the one on the clone, so we need to create a new instance. - _propertyChangedInfo = new Dictionary(); + _propertyChangedInfo = null; } public void ResetChangeTrackingCollections() { - _propertyChangedInfo = new Dictionary(); - _lastPropertyChangedInfo = new Dictionary(); + _propertyChangedInfo = null; + _lastPropertyChangedInfo = null; } public void DisableChangeTracking() @@ -179,7 +181,6 @@ namespace Umbraco.Core.Models.EntityBase //Standard Equals comparison (arg1, arg2) => Equals(arg1, arg2), arg => arg.GetHashCode())); - } /// @@ -204,14 +205,10 @@ namespace Umbraco.Core.Models.EntityBase //don't track changes, just set the value (above) if (_changeTrackingEnabled == false) return false; - if (comparer.Equals(initVal, newVal) == false) - { - OnPropertyChanged(propertySelector); - return true; - } - return false; + if (comparer.Equals(initVal, newVal)) return false; + + OnPropertyChanged(propertySelector); + return true; } - - } } \ No newline at end of file From 928e74f24cff21890592b66603ee10129f6542e6 Mon Sep 17 00:00:00 2001 From: Stephan Date: Thu, 26 May 2016 17:14:13 +0200 Subject: [PATCH 093/535] No C# 6 yet --- .../Models/EntityBase/TracksChangesEntityBase.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/Umbraco.Core/Models/EntityBase/TracksChangesEntityBase.cs b/src/Umbraco.Core/Models/EntityBase/TracksChangesEntityBase.cs index 109084e9b9..43da67297f 100644 --- a/src/Umbraco.Core/Models/EntityBase/TracksChangesEntityBase.cs +++ b/src/Umbraco.Core/Models/EntityBase/TracksChangesEntityBase.cs @@ -54,7 +54,8 @@ namespace Umbraco.Core.Models.EntityBase _propertyChangedInfo[propertyInfo.Name] = true; - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyInfo.Name)); + if (PropertyChanged != null) + PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyInfo.Name)); } /// @@ -165,8 +166,8 @@ namespace Umbraco.Core.Models.EntityBase /// /// returns true if the value changed /// - /// This is required because we don't want a property to show up as "dirty" if the value is the same. For example, when we - /// save a document type, nearly all properties are flagged as dirty just because we've 'reset' them, but they are all set + /// This is required because we don't want a property to show up as "dirty" if the value is the same. For example, when we + /// save a document type, nearly all properties are flagged as dirty just because we've 'reset' them, but they are all set /// to the same value, so it's really not dirty. /// internal bool SetPropertyValueAndDetectChanges(Func setValue, T value, PropertyInfo propertySelector) @@ -193,8 +194,8 @@ namespace Umbraco.Core.Models.EntityBase /// The equality comparer to use /// returns true if the value changed /// - /// This is required because we don't want a property to show up as "dirty" if the value is the same. For example, when we - /// save a document type, nearly all properties are flagged as dirty just because we've 'reset' them, but they are all set + /// This is required because we don't want a property to show up as "dirty" if the value is the same. For example, when we + /// save a document type, nearly all properties are flagged as dirty just because we've 'reset' them, but they are all set /// to the same value, so it's really not dirty. /// internal bool SetPropertyValueAndDetectChanges(Func setValue, T value, PropertyInfo propertySelector, IEqualityComparer comparer) From 6a0ca68d173a90ab80cd3ed6935f326d0ebc3c29 Mon Sep 17 00:00:00 2001 From: Stephan Date: Thu, 26 May 2016 18:44:22 +0200 Subject: [PATCH 094/535] Fixing, stupid --- .../Models/EntityBase/TracksChangesEntityBase.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Core/Models/EntityBase/TracksChangesEntityBase.cs b/src/Umbraco.Core/Models/EntityBase/TracksChangesEntityBase.cs index 43da67297f..7e93c8cef2 100644 --- a/src/Umbraco.Core/Models/EntityBase/TracksChangesEntityBase.cs +++ b/src/Umbraco.Core/Models/EntityBase/TracksChangesEntityBase.cs @@ -93,7 +93,7 @@ namespace Umbraco.Core.Models.EntityBase /// True if Property was changed, otherwise False. Returns false if the entity had not been previously changed. public virtual bool WasPropertyDirty(string propertyName) { - return WasDirty() && _lastPropertyChangedInfo.Any(x => x.Key == propertyName); + return WasDirty() && _lastPropertyChangedInfo!= null && _lastPropertyChangedInfo.Any(x => x.Key == propertyName); } /// @@ -133,7 +133,9 @@ namespace Umbraco.Core.Models.EntityBase if (rememberPreviouslyChangedProperties) { //copy the changed properties to the last changed properties - _lastPropertyChangedInfo = _propertyChangedInfo.ToDictionary(v => v.Key, v => v.Value); + _lastPropertyChangedInfo = _propertyChangedInfo == null + ? null + : _propertyChangedInfo.ToDictionary(v => v.Key, v => v.Value); } //NOTE: We cannot .Clear() because when we memberwise clone this will be the SAME From cd3140af217ba541116a9e0d665a6bfecac79dc3 Mon Sep 17 00:00:00 2001 From: bjarnef Date: Thu, 26 May 2016 21:13:25 +0200 Subject: [PATCH 095/535] Fix tiny issues with dropzone border to the left for fixed header and header jump by 1px when it get sticky. --- .../less/components/editor/subheader/umb-editor-sub-header.less | 2 +- .../src/less/components/umb-file-dropzone.less | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/editor/subheader/umb-editor-sub-header.less b/src/Umbraco.Web.UI.Client/src/less/components/editor/subheader/umb-editor-sub-header.less index 3a5367c7c9..b7d6015b76 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/editor/subheader/umb-editor-sub-header.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/editor/subheader/umb-editor-sub-header.less @@ -12,7 +12,7 @@ .umb-editor-sub-header.-umb-sticky-bar { box-shadow: 0 5px 0 rgba(0, 0, 0, 0.08), 0 1px 0 rgba(0, 0, 0, 0.16); transition: box-shadow 1s; - top: 100px; + top: 101px; /* height of header: 100px + its bottom-border: 1px */ transform: translate(0, 50%); } diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-file-dropzone.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-file-dropzone.less index d4e82a6419..6b3c46d927 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-file-dropzone.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-file-dropzone.less @@ -5,7 +5,7 @@ // tall and small version - animate height .dropzone { height: 400px; - width: 100%; + width: auto; padding: 50px 0; border: 1px dashed @grayLight; text-align: center; From e3dae6d77e8b8a7826047b4a603932c396a806e4 Mon Sep 17 00:00:00 2001 From: bjarnef Date: Thu, 26 May 2016 22:24:33 +0200 Subject: [PATCH 096/535] Fix a few translations in da.xml --- src/Umbraco.Web.UI/umbraco/config/lang/da.xml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml index 0280a46e05..c5a0861d13 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml @@ -6,7 +6,7 @@ Tilføj domæne - Revisions spor + Revisionsspor Gennemse elementer Skift dokumenttype Kopier @@ -447,13 +447,13 @@ Tilføj fane - Tilføj property + Tilføj egenskab Tilføj editor Tilføj skabelon Tilføj child node Tilføj child - Rediger data type + Rediger datatype Naviger sektioner @@ -948,7 +948,7 @@ Mange hilsner fra Umbraco robotten Hvis indholdet af felterne skal sendes til en url, skal denne slåes til så specialtegn formateres Denne tekst vil blive brugt hvis ovenstående felter er tomme Dette felt vil blive brugt hvis ovenstående felt er tomt - Ja, med klokkeslet. Dato/tid separator: + Ja, med klokkeslæt. Dato/tid separator: Opgaver tildelt dig @@ -985,10 +985,10 @@ Mange hilsner fra Umbraco robotten Datatyper Ordbog Installerede pakker - Installér et skin' - Installér et starter kit' + Installér et skin + Installér et starterkit Sprog - Installer lokal pakke + Installér lokal pakke Makroer Medietyper Medlemmer @@ -1026,7 +1026,7 @@ Mange hilsner fra Umbraco robotten Du kan ændre dit kodeord, som giver dig adgang til Umbraco Back Office ved at udfylde formularen og klikke på knappen 'Skift dit kodeord' Indholdskanal Beskrivelsesfelt - Deaktivér User + Deaktivér bruger Dokumenttype Redaktør Uddragsfelt @@ -1070,4 +1070,4 @@ Mange hilsner fra Umbraco robotten ...eller indtast din egen validering Feltet er påkrævet - + \ No newline at end of file From 00ae650ee2f401b553d2fee9aa0209d774882ef8 Mon Sep 17 00:00:00 2001 From: bjarnef Date: Thu, 26 May 2016 22:37:49 +0200 Subject: [PATCH 097/535] Modify a few other keys --- src/Umbraco.Web.UI/umbraco/config/lang/da.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml index c5a0861d13..a91731a503 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml @@ -119,12 +119,12 @@ Alias (hvordan ville du f.eks. beskrive billedet via telefonen?) Alternative links - Klik på musen for at redigere dette punkt + Klik for at redigere dette punkt Oprettet af Oprindelig forfatter Opdateret af Oprettet den - tidspunkt for oprettelse + Tidspunkt for oprettelse Dokumenttype Redigerer Nedtagningsdato From 2f1b234d851a0ace002bf9c3613cfe1d990d007b Mon Sep 17 00:00:00 2001 From: bjarnef Date: Thu, 26 May 2016 22:43:15 +0200 Subject: [PATCH 098/535] Fix template translation --- src/Umbraco.Web.UI/umbraco/config/lang/da.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml index a91731a503..9c4899d72c 100644 --- a/src/Umbraco.Web.UI/umbraco/config/lang/da.xml +++ b/src/Umbraco.Web.UI/umbraco/config/lang/da.xml @@ -873,7 +873,7 @@ Mange hilsner fra Umbraco robotten Medlem gemt Stylesheetegenskab gemt Stylesheet gemt - Template gemt + Skabelon gemt Der er opstået en fejl under redigering Bruger gemt Brugertype gemt From 140218b0ed83a2a9e4ff01daa6e66ac5c6ab981d Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 27 May 2016 10:32:55 +0200 Subject: [PATCH 099/535] remove install button + make categories smaller --- .../src/less/components/umb-packages.less | 44 +++++++++---------- .../src/views/packagesNew/edit.html | 19 +++----- 2 files changed, 28 insertions(+), 35 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less index b226517bbf..f68db092a1 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less @@ -2,7 +2,11 @@ width: 100%; margin-top: 40px; - margin-bottom: 30px; + margin-bottom: 40px; + background: @grayLighter; + border-radius: 3px; + padding: 30px; + box-sizing: border-box; } .umb-packages-search input { @@ -13,6 +17,8 @@ padding: 4px 10px; font-size: 16px; border-color: #ececec; + margin-bottom: 0; + border-color: @grayLight; &:hover, &:focus { border-color: @grayLight; @@ -21,19 +27,16 @@ .umb-packages { - display: flex; - flex-wrap: wrap; - - margin: 0 -5px; + margin: 0 -10px; } // List .umb-package { - height: 260px; - width: 200px; - - padding: 20px; + float: left; + padding: 10px; + box-sizing: border-box; + width: 20%; } @@ -71,6 +74,7 @@ padding-top: 10px; padding-right: 10px; padding-left: 10px; + padding-bottom: 10px; text-align: center; background-color: white; @@ -86,27 +90,28 @@ // Info .umb-package-info { - padding-right: 20px; - padding-bottom: 20px; - padding-left: 20px; - + padding-right: 15px; + padding-bottom: 15px; + padding-left: 15px; text-align: center; } // Name .umb-package-name { + font-size: 15px; max-width: 250px; + margin-bottom: 5px; font-weight: bold; - margin-bottom: 10px; - white-space: nowrap; overflow: hidden; text-overflow: ellipsis; line-height: normal; + margin-left: auto; + margin-right: auto; } // Numbers @@ -117,8 +122,6 @@ justify-content: center; opacity: .6; - - margin-bottom: 20px; } .umb-package-numbers small { @@ -204,7 +207,7 @@ flex: 1 0 auto; max-width: 25%; background-color: @blue; - padding: 40px 10px; + padding: 10px; font-size: 13px; border-radius: 3px; color: @white; @@ -213,12 +216,9 @@ margin: 5px; justify-content: center; - text-transform: uppercase; - letter-spacing: 1.3px; - &:hover { background-color: @blueDark; - box-shadow: 0 3px 8px rgba(0,0,0,0.2); + //box-shadow: 0 3px 8px rgba(0,0,0,0.2); } } diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html index cf9c68e7d9..0901a58827 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html @@ -28,21 +28,18 @@ -
    Popular
    -
    +

    Popular

    + -
    Latest
    -
    +

    Latest

    +
    From db21aef15091f7b7a98a2ec609e95d1e8d88ac9b Mon Sep 17 00:00:00 2001 From: Simon Busborg Date: Fri, 27 May 2016 11:59:19 +0200 Subject: [PATCH 100/535] added icons and versions --- .../src/less/components/umb-packages.less | 28 +++++++++++++++++-- .../src/views/packagesNew/edit.controller.js | 18 ++++++++---- .../src/views/packagesNew/edit.html | 9 +++--- 3 files changed, 43 insertions(+), 12 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less index f68db092a1..e07e6f69f2 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less @@ -47,6 +47,8 @@ flex-direction: column; justify-content: center; + position: relative; + height: 100%; width: 100%; @@ -118,22 +120,44 @@ .umb-package-numbers { display: flex; flex-wrap: wrap; - flex-direction: column; + flex-direction: row; justify-content: center; opacity: .6; + + margin-top: 10px; } .umb-package-numbers small { padding: 0 5px; - display: block; + + display: flex; + align-items: center; + justify-content: center; +} + +.umb-package-numbers i { + font-size: 14px; } .umb-package-link:hover .umb-package-numbers { opacity: 1; } +.umb-package-link:hover .umb-package-numbers .icon-hearts { + color: red !important; +} +// Version +.umb-package-version { + display: inline-flex; + font-size: 11px; + font-weight: bold; + padding: 1px 5px; + background: #ececec; + border-radius: 3px; + color: black; +} /* umb-buttons-era */ .umb-era-button { diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.controller.js index e082448933..be816bb62a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.controller.js @@ -41,42 +41,48 @@ "description": "An HTML5 audio player based on jPlayer", "karma": "1", "downloads": "1672", - "icon":"https://our.umbraco.org/media/wiki/150283/635768313097111400_usightlylogopng.png?bgcolor=fff&height=154&width=281&format=png" + "icon":"https://our.umbraco.org/media/wiki/150283/635768313097111400_usightlylogopng.png?bgcolor=fff&height=154&width=281&format=png", + "version":"No good" }, { "name": "Kill IE6", "description": "A simple port of the IE6 warning script (http://code.google.com/p/ie6-upgrade-warning/) to use in your Umbraco websites.", "karma": "11", "downloads": "688", - "icon":"https://our.umbraco.org/media/wiki/9138/634697622367666000_offroadcode-100x100.png?bgcolor=fff&height=154&width=281&format=png" + "icon":"https://our.umbraco.org/media/wiki/9138/634697622367666000_offroadcode-100x100.png?bgcolor=fff&height=154&width=281&format=png", + "version":"Fits perfectly" }, { "name": "Examine Media Indexer", "description": "CogUmbracoExamineMediaIndexer", "karma": "3", "downloads": "1329", - "icon":"https://our.umbraco.org/media/wiki/50703/634782902373558000_cogworks.jpg?bgcolor=fff&height=154&width=281&format=png" + "icon":"https://our.umbraco.org/media/wiki/50703/634782902373558000_cogworks.jpg?bgcolor=fff&height=154&width=281&format=png", + "version":"Fits perfectly" }, { "name": "SVG Icon Picker", "description": "A picker, for picking icons from an SVG spritesheet.", "karma": "5", "downloads": "8", - "icon":"https://our.umbraco.org/media/wiki/154472/635997115126742822_logopng.png?bgcolor=fff&height=154&width=281&format=png" + "icon":"https://our.umbraco.org/media/wiki/154472/635997115126742822_logopng.png?bgcolor=fff&height=154&width=281&format=png", + "version":"Fits perfectly" }, { "name": "Pipeline CRM", "description": "Pipeline is a social CRM that lives in Umbraco back-office. It tracks opportunities and helps teams collaborate with timelines and tasks. It stores information about your customers and your interactions with them. It integrates with your website, capturing opportunities from forms and powering personal portals.", "karma": "3", "downloads": "105", - "icon":"https://our.umbraco.org/media/wiki/152476/635917291068518788_pipeline-crm-logopng.png?bgcolor=fff&height=154&width=281&format=png" + "icon":"https://our.umbraco.org/media/wiki/152476/635917291068518788_pipeline-crm-logopng.png?bgcolor=fff&height=154&width=281&format=png", + "version":"Fits perfectly" }, { "name": "CodeMirror", "description": "CodeMirror Editor for Umbraco", "karma": "1", "downloads": "70", - "icon":"https://our.umbraco.org/media/wiki/151028/635810233171153461_logopng.png?bgcolor=fff&height=154&width=281&format=png" + "icon":"https://our.umbraco.org/media/wiki/151028/635810233171153461_logopng.png?bgcolor=fff&height=154&width=281&format=png", + "version":"No good" } ]; diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html index 0901a58827..24f919a4e9 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html @@ -40,12 +40,13 @@
    {{ package.name }}
    +
    - Downloads {{ package.downloads }} + {{ package.downloads }} - Karma {{ package.karma }} + {{ package.karma }}
    @@ -73,10 +74,10 @@
    - Downloads {{ package.downloads }} + {{ package.downloads }} - Karma {{ package.karma }} + {{ package.karma }}
    From d77986fb180c34e1b34d857a55c7db436b071c9d Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 27 May 2016 13:11:03 +0200 Subject: [PATCH 101/535] open overview html instead of edit html.. add category html and link the two views --- ...t.controller.js => category.controller.js} | 30 +++--- .../src/views/packagesNew/category.html | 35 +++++++ .../views/packagesNew/overview.controller.js | 97 +++++++++++++++++++ .../packagesNew/{edit.html => overview.html} | 4 +- .../Trees/NewPackagesTreeController.cs | 3 + 5 files changed, 152 insertions(+), 17 deletions(-) rename src/Umbraco.Web.UI.Client/src/views/packagesNew/{edit.controller.js => category.controller.js} (86%) create mode 100644 src/Umbraco.Web.UI.Client/src/views/packagesNew/category.html create mode 100644 src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.controller.js rename src/Umbraco.Web.UI.Client/src/views/packagesNew/{edit.html => overview.html} (96%) diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/packagesNew/category.controller.js similarity index 86% rename from src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.controller.js rename to src/Umbraco.Web.UI.Client/src/views/packagesNew/category.controller.js index be816bb62a..1030266e23 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/category.controller.js @@ -1,12 +1,14 @@ (function () { "use strict"; - function PackagesEditController($scope) { + function PackagesCategoryController($scope) { var vm = this; vm.page = {}; - vm.page.name = "Packages"; + vm.page.name = "Category"; + + vm.selectCategory = selectCategory; vm.categories = [ { @@ -41,54 +43,52 @@ "description": "An HTML5 audio player based on jPlayer", "karma": "1", "downloads": "1672", - "icon":"https://our.umbraco.org/media/wiki/150283/635768313097111400_usightlylogopng.png?bgcolor=fff&height=154&width=281&format=png", - "version":"No good" + "icon":"https://our.umbraco.org/media/wiki/150283/635768313097111400_usightlylogopng.png?bgcolor=fff&height=154&width=281&format=png" }, { "name": "Kill IE6", "description": "A simple port of the IE6 warning script (http://code.google.com/p/ie6-upgrade-warning/) to use in your Umbraco websites.", "karma": "11", "downloads": "688", - "icon":"https://our.umbraco.org/media/wiki/9138/634697622367666000_offroadcode-100x100.png?bgcolor=fff&height=154&width=281&format=png", - "version":"Fits perfectly" + "icon":"https://our.umbraco.org/media/wiki/9138/634697622367666000_offroadcode-100x100.png?bgcolor=fff&height=154&width=281&format=png" }, { "name": "Examine Media Indexer", "description": "CogUmbracoExamineMediaIndexer", "karma": "3", "downloads": "1329", - "icon":"https://our.umbraco.org/media/wiki/50703/634782902373558000_cogworks.jpg?bgcolor=fff&height=154&width=281&format=png", - "version":"Fits perfectly" + "icon":"https://our.umbraco.org/media/wiki/50703/634782902373558000_cogworks.jpg?bgcolor=fff&height=154&width=281&format=png" }, { "name": "SVG Icon Picker", "description": "A picker, for picking icons from an SVG spritesheet.", "karma": "5", "downloads": "8", - "icon":"https://our.umbraco.org/media/wiki/154472/635997115126742822_logopng.png?bgcolor=fff&height=154&width=281&format=png", - "version":"Fits perfectly" + "icon":"https://our.umbraco.org/media/wiki/154472/635997115126742822_logopng.png?bgcolor=fff&height=154&width=281&format=png" }, { "name": "Pipeline CRM", "description": "Pipeline is a social CRM that lives in Umbraco back-office. It tracks opportunities and helps teams collaborate with timelines and tasks. It stores information about your customers and your interactions with them. It integrates with your website, capturing opportunities from forms and powering personal portals.", "karma": "3", "downloads": "105", - "icon":"https://our.umbraco.org/media/wiki/152476/635917291068518788_pipeline-crm-logopng.png?bgcolor=fff&height=154&width=281&format=png", - "version":"Fits perfectly" + "icon":"https://our.umbraco.org/media/wiki/152476/635917291068518788_pipeline-crm-logopng.png?bgcolor=fff&height=154&width=281&format=png" }, { "name": "CodeMirror", "description": "CodeMirror Editor for Umbraco", "karma": "1", "downloads": "70", - "icon":"https://our.umbraco.org/media/wiki/151028/635810233171153461_logopng.png?bgcolor=fff&height=154&width=281&format=png", - "version":"No good" + "icon":"https://our.umbraco.org/media/wiki/151028/635810233171153461_logopng.png?bgcolor=fff&height=154&width=281&format=png" } ]; + function selectCategory(category) { + + } + } - angular.module("umbraco").controller("Umbraco.Editors.Packages.EditController", PackagesEditController); + angular.module("umbraco").controller("Umbraco.Editors.Packages.CategoryController", PackagesCategoryController); })(); diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/category.html b/src/Umbraco.Web.UI.Client/src/views/packagesNew/category.html new file mode 100644 index 0000000000..0262b2c8ae --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/category.html @@ -0,0 +1,35 @@ +
    + + + +
    + + + + + + + + + This is my category + + + + + + + Breadcrumbs here + + + + + + +
    + +
    diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.controller.js b/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.controller.js new file mode 100644 index 0000000000..d50249dafd --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.controller.js @@ -0,0 +1,97 @@ +(function () { + "use strict"; + + function PackagesOverviewController($scope, $route, $location) { + + var vm = this; + + vm.page = {}; + vm.page.name = "Packages"; + + vm.selectCategory = selectCategory; + + vm.categories = [ + { + "icon": "icon-male-and-female", + "name": "Collaboration" + }, + { + "icon": "icon-molecular-network", + "name": "Backoffice extensions" + }, + { + "icon": "icon-brackets", + "name": "Developer tools" + }, + { + "icon": "icon-wand", + "name": "Starter kits" + }, + { + "icon": "icon-medal", + "name": "Umbraco Pro" + }, + { + "icon": "icon-wrench", + "name": "Website utilities" + } + ]; + + vm.packages = [ + { + "name": "uSightly", + "description": "An HTML5 audio player based on jPlayer", + "karma": "1", + "downloads": "1672", + "icon":"https://our.umbraco.org/media/wiki/150283/635768313097111400_usightlylogopng.png?bgcolor=fff&height=154&width=281&format=png" + }, + { + "name": "Kill IE6", + "description": "A simple port of the IE6 warning script (http://code.google.com/p/ie6-upgrade-warning/) to use in your Umbraco websites.", + "karma": "11", + "downloads": "688", + "icon":"https://our.umbraco.org/media/wiki/9138/634697622367666000_offroadcode-100x100.png?bgcolor=fff&height=154&width=281&format=png" + }, + { + "name": "Examine Media Indexer", + "description": "CogUmbracoExamineMediaIndexer", + "karma": "3", + "downloads": "1329", + "icon":"https://our.umbraco.org/media/wiki/50703/634782902373558000_cogworks.jpg?bgcolor=fff&height=154&width=281&format=png" + }, + { + "name": "SVG Icon Picker", + "description": "A picker, for picking icons from an SVG spritesheet.", + "karma": "5", + "downloads": "8", + "icon":"https://our.umbraco.org/media/wiki/154472/635997115126742822_logopng.png?bgcolor=fff&height=154&width=281&format=png" + }, + { + "name": "Pipeline CRM", + "description": "Pipeline is a social CRM that lives in Umbraco back-office. It tracks opportunities and helps teams collaborate with timelines and tasks. It stores information about your customers and your interactions with them. It integrates with your website, capturing opportunities from forms and powering personal portals.", + "karma": "3", + "downloads": "105", + "icon":"https://our.umbraco.org/media/wiki/152476/635917291068518788_pipeline-crm-logopng.png?bgcolor=fff&height=154&width=281&format=png" + }, + { + "name": "CodeMirror", + "description": "CodeMirror Editor for Umbraco", + "karma": "1", + "downloads": "70", + "icon":"https://our.umbraco.org/media/wiki/151028/635810233171153461_logopng.png?bgcolor=fff&height=154&width=281&format=png" + } + ]; + + function selectCategory(category) { + var section = $route.current.params.section; + var tree = $route.current.params.tree; + var path = "/" + section + "/" + tree + "/category"; + $location.path(path); + } + + + } + + angular.module("umbraco").controller("Umbraco.Editors.Packages.OverviewController", PackagesOverviewController); + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html b/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.html similarity index 96% rename from src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html rename to src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.html index 24f919a4e9..837f3b32b2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.html @@ -1,4 +1,4 @@ -
    +
    @@ -21,7 +21,7 @@
    - +
    {{ category.name }}
    diff --git a/src/Umbraco.Web/Trees/NewPackagesTreeController.cs b/src/Umbraco.Web/Trees/NewPackagesTreeController.cs index c6c4e67841..9d3726540a 100644 --- a/src/Umbraco.Web/Trees/NewPackagesTreeController.cs +++ b/src/Umbraco.Web/Trees/NewPackagesTreeController.cs @@ -26,10 +26,13 @@ namespace Umbraco.Web.Trees { protected override TreeNodeCollection GetTreeNodes(string id, FormDataCollection queryStrings) { + var baseUrl = Constants.Applications.Developer + "/packagesNew/"; + var nodes = new TreeNodeCollection(); var node = CreateTreeNode("1", id, queryStrings, "Name", "icon-folder", false, ""); node.Path = "path"; + node.RoutePath = baseUrl + "overview"; //node.NodeType = "container"; //TODO: This isn't the best way to ensure a noop process for clicking a node but it works for now. //node.AdditionalData["jsClickCallback"] = "javascript:void(0);"; From a04cb1d97010f9b86581683a66f2494d8823546e Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Fri, 27 May 2016 14:29:30 +0200 Subject: [PATCH 102/535] added details view --- .../views/packagesNew/details.controller.js | 92 +++++++++++++++++++ .../src/views/packagesNew/details.html | 35 +++++++ .../views/packagesNew/overview.controller.js | 8 ++ .../src/views/packagesNew/overview.html | 4 +- 4 files changed, 137 insertions(+), 2 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/views/packagesNew/details.controller.js create mode 100644 src/Umbraco.Web.UI.Client/src/views/packagesNew/details.html diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/details.controller.js b/src/Umbraco.Web.UI.Client/src/views/packagesNew/details.controller.js new file mode 100644 index 0000000000..9b4313b743 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/details.controller.js @@ -0,0 +1,92 @@ +(function () { + "use strict"; + + function PackageDetailsController($scope) { + + var vm = this; + + vm.page = {}; + + vm.package = { + "name": "Merchello", + "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur dignissim purus pulvinar odio iaculis, sit amet euismod arcu volutpat. Sed ut hendrerit sem. Vestibulum enim nisl, luctus quis cursus et, porttitor a ligula. Donec sed congue urna. Integer tincidunt ultrices lorem vitae suscipit. Sed non turpis massa. Donec et velit ante. Sed interdum lectus id lorem congue, sit amet lacinia ex placerat. In id orci sed augue cursus sodales.", + "compatibility": [ + { + "version": "7.4.x", + "compatibility": "100%" + }, + { + "version": "7.3.x", + "compatibility": "86%" + }, + { + "version": "7.2.x", + "compatibility": "93%" + }, + { + "version": "7.1.x", + "compatibility": "100%" + }, + { + "version": "7.0.x", + "compatibility": "untested" + }, + { + "version": "6.1.x", + "compatibility": "untested" + }, + { + "version": "6.0.x", + "compatibility": "untested" + }, + { + "version": "4.11.x", + "compatibility": "untested" + }, + { + "version": "4.10.x", + "compatibility": "untested" + }, + { + "version": "4.9.1", + "compatibility": "untested" + }, + { + "version": "4.9.0", + "compatibility": "untested" + } + ], + "information": { + "owner": "Rusty Swayne", + "contributors": [ + { + "name": "Lee" + }, + { + "name": "Jason Prothero" + } + ], + "created": "18/12/2013", + "currentVersion": "2.0.0", + ".netVersion": "4.5", + "license": "MIT", + "downloads": "4198", + "karma": "53" + }, + "externalSources": [ + { + "name": "Source code", + "url": "https://github.com/merchello/Merchello" + }, + { + "name": "Issue tracker", + "url": "http://issues.merchello.com/youtrack/oauth?state=%2Fyoutrack%2FrootGo" + } + ] + }; + + } + + angular.module("umbraco").controller("Umbraco.Editors.Packages.DetailsController", PackageDetailsController); + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/details.html b/src/Umbraco.Web.UI.Client/src/views/packagesNew/details.html new file mode 100644 index 0000000000..595dc03868 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/details.html @@ -0,0 +1,35 @@ +
    + + + +
    + + + + + + + + +
    {{ vm.package | json }}
    + +
    + + + + + Breadcrumbs here + + + + +
    + +
    + +
    diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.controller.js b/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.controller.js index d50249dafd..820e1d2cf1 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.controller.js @@ -9,6 +9,7 @@ vm.page.name = "Packages"; vm.selectCategory = selectCategory; + vm.showPackageDetails = showPackageDetails; vm.categories = [ { @@ -89,6 +90,13 @@ $location.path(path); } + function showPackageDetails(selectedPackage) { + var section = $route.current.params.section; + var tree = $route.current.params.tree; + var path = "/" + section + "/" + tree + "/details"; + $location.path(path); + } + } diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.html b/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.html index 837f3b32b2..724ea7af84 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.html +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.html @@ -32,7 +32,7 @@
    - +
    @@ -61,7 +61,7 @@
    - +
    From 5b9d0638084f81c71a644233fa2a1e864b098896 Mon Sep 17 00:00:00 2001 From: Simon Busborg Date: Fri, 27 May 2016 14:52:31 +0200 Subject: [PATCH 103/535] Changed categories --- .../src/less/components/umb-packages.less | 54 +++++++++---- .../views/packagesNew/category.controller.js | 8 +- .../src/views/packagesNew/category.html | 78 ++++++++++++++++++- .../views/packagesNew/overview.controller.js | 8 +- .../src/views/packagesNew/overview.html | 21 ++++- 5 files changed, 147 insertions(+), 22 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less index e07e6f69f2..658c690f39 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less @@ -27,7 +27,7 @@ .umb-packages { - margin: 0 -10px; + // margin: 0 -10px; } @@ -225,31 +225,32 @@ margin-bottom: 30px; } + + .umb-packages-category { display: flex; align-items: center; flex: 1 0 auto; - max-width: 25%; - background-color: @blue; - padding: 10px; - font-size: 13px; - border-radius: 3px; - color: @white; - box-sizing: border-box; - flex: 1 0 auto; - margin: 5px; justify-content: center; - &:hover { - background-color: @blueDark; - //box-shadow: 0 3px 8px rgba(0,0,0,0.2); - } + opacity: .6; + + max-width: 25%; + + font-size: 13px; + font-weight: bold; + color: @black; + + box-sizing: border-box; + + justify-content: center; } + .umb-packages-category:hover, .umb-packages-category:focus { text-decoration: none; - color: @white; + opacity: 1; } .umb-packages-category-icon { @@ -258,3 +259,26 @@ display: none; } + +// Collapsed +.umb-packages-categories.-collapsed { + margin-bottom: 0; +} + +.umb-packages-categories.-collapsed .umb-packages-category { + margin-right: 20px; + + &:last-child { + margin-right: 0; + } +} + +.-ma0 { + margin: 0 !important; +} + +.-collapsed .umb-packages-category.-active { + color: @black; + opacity: 1; + border-bottom: 2px solid @black; +} diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/category.controller.js b/src/Umbraco.Web.UI.Client/src/views/packagesNew/category.controller.js index 1030266e23..3dbf0403a0 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/category.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/category.controller.js @@ -13,7 +13,13 @@ vm.categories = [ { "icon": "icon-male-and-female", - "name": "Collaboration" + "name": "All", + "active": false + }, + { + "icon": "icon-male-and-female", + "name": "Collaboration", + "active": true }, { "icon": "icon-molecular-network", diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/category.html b/src/Umbraco.Web.UI.Client/src/views/packagesNew/category.html index 0262b2c8ae..a012264d75 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/category.html +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/category.html @@ -1,4 +1,4 @@ -
    +
    @@ -16,7 +16,81 @@ - This is my category + + + + + + + + + + + + +

    Popular

    + + + +

    Latest

    + diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.controller.js b/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.controller.js index 820e1d2cf1..e01f818cb0 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.controller.js @@ -14,7 +14,13 @@ vm.categories = [ { "icon": "icon-male-and-female", - "name": "Collaboration" + "name": "All", + "active": true + }, + { + "icon": "icon-male-and-female", + "name": "Collaboration", + "active": false }, { "icon": "icon-molecular-network", diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.html b/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.html index 724ea7af84..3d18e27411 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.html +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.html @@ -1,4 +1,4 @@ -
    +
    @@ -16,16 +16,31 @@ + + + + + + + + + + -
    +

    Popular

    From 24959f44954b328f4a85cf6f30a5c79b33fef767 Mon Sep 17 00:00:00 2001 From: Jeremy Pyne Date: Fri, 27 May 2016 16:51:34 -0400 Subject: [PATCH 104/535] Macro's inserted in the grid should block link clicks so that users done accidentally navigate away from backoffice when trying to edit macro settings. --- .../src/views/propertyeditors/grid/editors/macro.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/macro.html b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/macro.html index 732b551b52..f36a870423 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/macro.html +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/macro.html @@ -7,7 +7,7 @@
    From b168923d5f8880c64e0b08663ccd64fcc28b6a98 Mon Sep 17 00:00:00 2001 From: Darren Ferguson Date: Sun, 29 May 2016 15:46:42 +0100 Subject: [PATCH 105/535] http://issues.umbraco.org/issue/U4-7032 : Include a password checker for Active Directory - as ability to authenticate via AD was removed in 7.3 --- ...eDirectoryBackOfficeUserPasswordChecker.cs | 25 +++++++++++++++++++ src/Umbraco.Core/Umbraco.Core.csproj | 2 ++ 2 files changed, 27 insertions(+) create mode 100644 src/Umbraco.Core/Security/ActiveDirectoryBackOfficeUserPasswordChecker.cs diff --git a/src/Umbraco.Core/Security/ActiveDirectoryBackOfficeUserPasswordChecker.cs b/src/Umbraco.Core/Security/ActiveDirectoryBackOfficeUserPasswordChecker.cs new file mode 100644 index 0000000000..aef4f3dc76 --- /dev/null +++ b/src/Umbraco.Core/Security/ActiveDirectoryBackOfficeUserPasswordChecker.cs @@ -0,0 +1,25 @@ +using System.Configuration; +using System.DirectoryServices.AccountManagement; +using System.Threading.Tasks; +using Umbraco.Core.Models.Identity; + +namespace Umbraco.Core.Security +{ + public class ActiveDirectoryBackOfficeUserPasswordChecker : IBackOfficeUserPasswordChecker + { + public Task CheckPasswordAsync(BackOfficeIdentityUser user, string password) + { + bool isValid; + using (var pc = new PrincipalContext(ContextType.Domain, ConfigurationManager.AppSettings["ActiveDirectoryDomain"])) + { + isValid = pc.ValidateCredentials(user.UserName, password); + } + + var result = isValid + ? BackOfficeUserPasswordCheckerResult.ValidCredentials + : BackOfficeUserPasswordCheckerResult.InvalidCredentials; + + return Task.FromResult(result); + } + } +} diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj index 141622687e..72bf9ddd42 100644 --- a/src/Umbraco.Core/Umbraco.Core.csproj +++ b/src/Umbraco.Core/Umbraco.Core.csproj @@ -110,6 +110,7 @@ False ..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll + @@ -485,6 +486,7 @@ + From 521329feaca483edadcb793c6531b092d499e01b Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 30 May 2016 09:15:28 +0200 Subject: [PATCH 106/535] send id to category and details view --- .../src/views/packagesNew/category.controller.js | 2 +- .../src/views/packagesNew/details.controller.js | 2 +- .../src/views/packagesNew/overview.controller.js | 16 ++++++++++++++-- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/category.controller.js b/src/Umbraco.Web.UI.Client/src/views/packagesNew/category.controller.js index 3dbf0403a0..61332e850f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/category.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/category.controller.js @@ -1,7 +1,7 @@ (function () { "use strict"; - function PackagesCategoryController($scope) { + function PackagesCategoryController($scope, $routeParams) { var vm = this; diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/details.controller.js b/src/Umbraco.Web.UI.Client/src/views/packagesNew/details.controller.js index 9b4313b743..834c894c0c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/details.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/details.controller.js @@ -1,7 +1,7 @@ (function () { "use strict"; - function PackageDetailsController($scope) { + function PackageDetailsController($scope, $routeParams) { var vm = this; diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.controller.js b/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.controller.js index e01f818cb0..d98212e8fe 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.controller.js @@ -13,6 +13,7 @@ vm.categories = [ { + "id": 1, "icon": "icon-male-and-female", "name": "All", "active": true @@ -23,22 +24,27 @@ "active": false }, { + "id": 2, "icon": "icon-molecular-network", "name": "Backoffice extensions" }, { + "id": 3, "icon": "icon-brackets", "name": "Developer tools" }, { + "id": 4, "icon": "icon-wand", "name": "Starter kits" }, { + "id": 5, "icon": "icon-medal", "name": "Umbraco Pro" }, { + "id": 6, "icon": "icon-wrench", "name": "Website utilities" } @@ -46,6 +52,7 @@ vm.packages = [ { + "id": 1, "name": "uSightly", "description": "An HTML5 audio player based on jPlayer", "karma": "1", @@ -53,6 +60,7 @@ "icon":"https://our.umbraco.org/media/wiki/150283/635768313097111400_usightlylogopng.png?bgcolor=fff&height=154&width=281&format=png" }, { + "id": 2, "name": "Kill IE6", "description": "A simple port of the IE6 warning script (http://code.google.com/p/ie6-upgrade-warning/) to use in your Umbraco websites.", "karma": "11", @@ -60,6 +68,7 @@ "icon":"https://our.umbraco.org/media/wiki/9138/634697622367666000_offroadcode-100x100.png?bgcolor=fff&height=154&width=281&format=png" }, { + "id": 3, "name": "Examine Media Indexer", "description": "CogUmbracoExamineMediaIndexer", "karma": "3", @@ -67,6 +76,7 @@ "icon":"https://our.umbraco.org/media/wiki/50703/634782902373558000_cogworks.jpg?bgcolor=fff&height=154&width=281&format=png" }, { + "id": 4, "name": "SVG Icon Picker", "description": "A picker, for picking icons from an SVG spritesheet.", "karma": "5", @@ -74,6 +84,7 @@ "icon":"https://our.umbraco.org/media/wiki/154472/635997115126742822_logopng.png?bgcolor=fff&height=154&width=281&format=png" }, { + "id": 5, "name": "Pipeline CRM", "description": "Pipeline is a social CRM that lives in Umbraco back-office. It tracks opportunities and helps teams collaborate with timelines and tasks. It stores information about your customers and your interactions with them. It integrates with your website, capturing opportunities from forms and powering personal portals.", "karma": "3", @@ -81,6 +92,7 @@ "icon":"https://our.umbraco.org/media/wiki/152476/635917291068518788_pipeline-crm-logopng.png?bgcolor=fff&height=154&width=281&format=png" }, { + "id": 6, "name": "CodeMirror", "description": "CodeMirror Editor for Umbraco", "karma": "1", @@ -92,14 +104,14 @@ function selectCategory(category) { var section = $route.current.params.section; var tree = $route.current.params.tree; - var path = "/" + section + "/" + tree + "/category"; + var path = "/" + section + "/" + tree + "/category/" + category.id; $location.path(path); } function showPackageDetails(selectedPackage) { var section = $route.current.params.section; var tree = $route.current.params.tree; - var path = "/" + section + "/" + tree + "/details"; + var path = "/" + section + "/" + tree + "/details/" + selectedPackage.id; $location.path(path); } From 885d14bcb6c35b24605ced274b1e5e0b9d43c48e Mon Sep 17 00:00:00 2001 From: Simon Busborg Date: Mon, 30 May 2016 10:01:34 +0200 Subject: [PATCH 107/535] Fixes: U4-8455 IE11 - Image Cropper stretches the image when zooming --- src/Umbraco.Web.UI.Client/src/less/property-editors.less | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/property-editors.less b/src/Umbraco.Web.UI.Client/src/less/property-editors.less index 96deaef09a..85a1d9e36c 100644 --- a/src/Umbraco.Web.UI.Client/src/less/property-editors.less +++ b/src/Umbraco.Web.UI.Client/src/less/property-editors.less @@ -298,7 +298,7 @@ ul.color-picker li a { } .umb-cropper img { - max-width: initial; + max-width: none; } .umb-cropper .overlay, .umb-cropper-gravity .overlay { From 720a46686b31d1b2a9e0a732ee8c371c7dcc5f95 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Mon, 30 May 2016 12:02:13 +0200 Subject: [PATCH 108/535] U4-8500 Get c# docs building (#1291) fetches docfx, builds the metadata and builds the docs with the correct filters builds the UI docs from the same powershell script --- .gitignore | 8 +- apidocs/docfx.filter.yml | 18 ++ apidocs/docfx.json | 75 +++++ apidocs/index.md | 7 + apidocs/toc.yml | 5 + .../partials/class.tmpl.partial | 257 ++++++++++++++++++ .../partials/footer.tmpl.partial | 13 + .../partials/head.tmpl.partial | 18 ++ .../partials/namespace.tmpl.partial | 18 ++ .../partials/navbar.tmpl.partial | 22 ++ .../partials/rest.tmpl.partial | 101 +++++++ apidocs/umbracotemplate/styles/main.css | 73 +++++ build/ApiDocs/TOC.css | 170 ------------ build/ApiDocs/csharp-api-docs.shfbproj | 172 ------------ build/BuildDocs.bat | 20 ++ build/BuildDocs.ps1 | 109 ++++++-- .../docs/src/api/index.ngdoc | 12 +- src/Umbraco.Web.UI.Client/docs/umb-docs.css | 78 ++++++ src/Umbraco.Web.UI.Client/gruntFile.js | 8 +- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 2 +- src/umbraco.sln | 7 +- 21 files changed, 819 insertions(+), 374 deletions(-) create mode 100644 apidocs/docfx.filter.yml create mode 100644 apidocs/docfx.json create mode 100644 apidocs/index.md create mode 100644 apidocs/toc.yml create mode 100644 apidocs/umbracotemplate/partials/class.tmpl.partial create mode 100644 apidocs/umbracotemplate/partials/footer.tmpl.partial create mode 100644 apidocs/umbracotemplate/partials/head.tmpl.partial create mode 100644 apidocs/umbracotemplate/partials/namespace.tmpl.partial create mode 100644 apidocs/umbracotemplate/partials/navbar.tmpl.partial create mode 100644 apidocs/umbracotemplate/partials/rest.tmpl.partial create mode 100644 apidocs/umbracotemplate/styles/main.css delete mode 100644 build/ApiDocs/TOC.css delete mode 100644 build/ApiDocs/csharp-api-docs.shfbproj create mode 100644 build/BuildDocs.bat create mode 100644 src/Umbraco.Web.UI.Client/docs/umb-docs.css diff --git a/.gitignore b/.gitignore index 576beabdf9..543a67d7ff 100644 --- a/.gitignore +++ b/.gitignore @@ -132,4 +132,10 @@ src/umbraco.sln.ide/* build/UmbracoCms.*/ src/.vs/ src/Umbraco.Web.UI/umbraco/js/install.loader.js -src/Umbraco.Tests/media \ No newline at end of file +src/Umbraco.Tests/media +tools/docfx/* +apidocs/_site/* +apidocs/api/* +build/docs.zip +build/ui-docs.zip +build/csharp-docs.zip diff --git a/apidocs/docfx.filter.yml b/apidocs/docfx.filter.yml new file mode 100644 index 0000000000..e96fbaafff --- /dev/null +++ b/apidocs/docfx.filter.yml @@ -0,0 +1,18 @@ +apiRules: + - include: + uidRegex: ^Umbraco\.Core + - exclude: + uidRegex: ^umbraco\.Web\.org + - include: + uidRegex: ^Umbraco\.Web + - exclude: + hasAttribute: + uid: System.ComponentModel.EditorBrowsableAttribute + ctorArguments: + - System.ComponentModel.EditorBrowsableState.Never + - exclude: + uidRegex: ^umbraco\. + - exclude: + uidRegex: ^CookComputing\. + - exclude: + uidRegex: ^.*$ \ No newline at end of file diff --git a/apidocs/docfx.json b/apidocs/docfx.json new file mode 100644 index 0000000000..520622a0e0 --- /dev/null +++ b/apidocs/docfx.json @@ -0,0 +1,75 @@ +{ + "metadata": [ + { + "src": [ + { + "files": [ + "Umbraco.Core/Umbraco.Core.csproj", + "Umbraco.Web/Umbraco.Web.csproj" + ], + "exclude": [ + "**/obj/**", + "**/bin/**", + "_site/**" + ], + "cwd": "../src" + } + ], + "dest": "../apidocs/api", + "filter": "../apidocs/docfx.filter.yml" + } + ], + "build": { + "content": [ + { + "files": [ + "api/**.yml", + "api/index.md" + ] + }, + { + "files": [ + "articles/**.md", + "articles/**/toc.yml", + "toc.yml", + "*.md" + ], + "exclude": [ + "obj/**", + "_site/**" + ] + } + ], + "resource": [ + { + "files": [ + "images/**" + ], + "exclude": [ + "obj/**", + "_site/**" + ] + } + ], + "overwrite": [ + { + "files": [ + "**.md" + ], + "exclude": [ + "obj/**", + "_site/**" + ] + } + ], + "globalMetadata": { + "_appTitle": "Umbraco c# Api docs", + "_enableSearch": true, + "_disableContribution": false + }, + "dest": "_site", + "template": [ + "default", "umbracotemplate" + ] + } +} \ No newline at end of file diff --git a/apidocs/index.md b/apidocs/index.md new file mode 100644 index 0000000000..b90b816312 --- /dev/null +++ b/apidocs/index.md @@ -0,0 +1,7 @@ + +# Umbraco c# API reference + +## Quick Links: + +### [Umbraco.Core](api/Umbraco.Core.html) docs +### [Umbraco.Web](api/Umbraco.Web.html) docs diff --git a/apidocs/toc.yml b/apidocs/toc.yml new file mode 100644 index 0000000000..6817825066 --- /dev/null +++ b/apidocs/toc.yml @@ -0,0 +1,5 @@ + +- name: Umbraco.Core Documentation + href: https://our.umbraco.org/apidocs/csharp/api/Umbraco.Core.html +- name: Umbraco.Web Documentation + href: https://our.umbraco.org/apidocs/csharp/api/Umbraco.Web.html \ No newline at end of file diff --git a/apidocs/umbracotemplate/partials/class.tmpl.partial b/apidocs/umbracotemplate/partials/class.tmpl.partial new file mode 100644 index 0000000000..9153a863a4 --- /dev/null +++ b/apidocs/umbracotemplate/partials/class.tmpl.partial @@ -0,0 +1,257 @@ +{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}} + +{{^_disableContribution}} +{{#sourceurl}}{{__global.viewSource}}{{/sourceurl}} +{{/_disableContribution}} +

    {{>partials/title}}

    +
    {{{summary}}}
    +
    {{{conceptual}}}
    +{{#inheritance.0}} +
    +
    {{__global.inheritance}}
    +{{#inheritance}} +
    {{{specName.0.value}}}
    +{{/inheritance}} +
    {{item.name.0.value}}
    +
    +{{/inheritance.0}} +
    {{__global.namespace}}:{{namespace}}
    +
    {{__global.assembly}}:{{assemblies.0}}.dll
    +
    {{__global.syntax}}
    +
    +
    {{syntax.content.0.value}}
    +
    +{{#syntax.parameters.0}} +
    {{__global.parameters}}
    + + + + + + + + + +{{/syntax.parameters.0}} +{{#syntax.parameters}} + + + + + +{{/syntax.parameters}} +{{#syntax.parameters.0}} + +
    {{__global.type}}{{__global.name}}{{__global.description}}
    {{{type.specName.0.value}}}{{{id}}}{{{description}}}
    +{{/syntax.parameters.0}} +{{#syntax.return}} +
    {{__global.returns}}
    + + + + + + + + + + + + + +
    {{__global.type}}{{__global.description}}
    {{{type.specName.0.value}}}{{{description}}}
    +{{/syntax.return}} +{{#syntax.typeParameters.0}} +
    {{__global.typeParameters}}
    + + + + + + + + +{{/syntax.typeParameters.0}} +{{#syntax.typeParameters}} + + + + +{{/syntax.typeParameters}} +{{#syntax.typeParameters.0}} + +
    {{__global.name}}{{__global.description}}
    {{{id}}}{{{description}}}
    +{{/syntax.typeParameters.0}} +{{#remarks}} +
    {{__global.remarks}}
    +
    {{{remarks}}}
    +{{/remarks}} +{{#example.0}} +
    {{__global.examples}}
    +{{/example.0}} +{{#example}} +{{{.}}} +{{/example}} +{{#children}} +

    {{>partials/classSubtitle}}

    +{{#children}} +{{^_disableContribution}} +{{#sourceurl}} + + {{__global.viewSource}} +{{/sourceurl}} +{{/_disableContribution}} +

    {{name.0.value}}

    +
    {{{summary}}}
    +
    {{{conceptual}}}
    +
    {{__global.declaration}}
    +{{#syntax}} +
    +
    {{syntax.content.0.value}}
    +
    +{{#parameters.0}} +
    {{__global.parameters}}
    + + + + + + + + + +{{/parameters.0}} +{{#parameters}} + + + + + +{{/parameters}} +{{#parameters.0}} + +
    {{__global.type}}{{__global.name}}{{__global.description}}
    {{{type.specName.0.value}}}{{{id}}}{{{description}}}
    +{{/parameters.0}} +{{#return}} +
    {{__global.returns}}
    + + + + + + + + + + + + + +
    {{__global.type}}{{__global.description}}
    {{{type.specName.0.value}}}{{{description}}}
    +{{/return}} +{{#typeParameters.0}} +
    {{__global.typeParameters}}
    + + + + + + + + +{{/typeParameters.0}} +{{#typeParameters}} + + + + +{{/typeParameters}} +{{#typeParameters.0}} + +
    {{__global.name}}{{__global.description}}
    {{{id}}}{{{description}}}
    +{{/typeParameters.0}} +{{#fieldValue}} +
    {{__global.fieldValue}}
    + + + + + + + + + + + + + +
    {{__global.type}}{{__global.description}}
    {{{type.specName.0.value}}}{{{description}}}
    +{{/fieldValue}} +{{#propertyValue}} +
    {{__global.propertyValue}}
    + + + + + + + + + + + + + +
    {{__global.type}}{{__global.description}}
    {{{type.specName.0.value}}}{{{description}}}
    +{{/propertyValue}} +{{#eventType}} +
    {{__global.eventType}}
    + + + + + + + + + + + + + +
    {{__global.type}}{{__global.description}}
    {{{type.specName.0.value}}}{{{description}}}
    +{{/eventType}} +{{/syntax}} +{{#remarks}} +
    {{__global.remarks}}
    +
    {{{remarks}}}
    +{{/remarks}} +{{#example.0}} +
    {{__global.examples}}
    +{{/example.0}} +{{#example}} +{{{.}}} +{{/example}} +{{#exceptions.0}} +
    {{__global.exceptions}}
    + + + + + + + + +{{/exceptions.0}} +{{#exceptions}} + + + + +{{/exceptions}} +{{#exceptions.0}} + +
    {{__global.type}}{{__global.condition}}
    {{{type.specName.0.value}}}{{{description}}}
    +{{/exceptions.0}} +{{/children}} +{{/children}} diff --git a/apidocs/umbracotemplate/partials/footer.tmpl.partial b/apidocs/umbracotemplate/partials/footer.tmpl.partial new file mode 100644 index 0000000000..69f51a101f --- /dev/null +++ b/apidocs/umbracotemplate/partials/footer.tmpl.partial @@ -0,0 +1,13 @@ +{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}} + +
    +
    + +
    diff --git a/apidocs/umbracotemplate/partials/head.tmpl.partial b/apidocs/umbracotemplate/partials/head.tmpl.partial new file mode 100644 index 0000000000..591e1c1885 --- /dev/null +++ b/apidocs/umbracotemplate/partials/head.tmpl.partial @@ -0,0 +1,18 @@ +{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}} + + + + + {{#title}}{{title}}{{/title}}{{^title}}{{>partials/title}}{{/title}} {{#_appTitle}}| {{_appTitle}} {{/_appTitle}} + + + + {{#_description}}{{/_description}} + + + + + + + {{#_enableSearch}}{{/_enableSearch}} + diff --git a/apidocs/umbracotemplate/partials/namespace.tmpl.partial b/apidocs/umbracotemplate/partials/namespace.tmpl.partial new file mode 100644 index 0000000000..80ca30799a --- /dev/null +++ b/apidocs/umbracotemplate/partials/namespace.tmpl.partial @@ -0,0 +1,18 @@ +{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}} + +{{^_disableContribution}} +{{#sourceurl}} +{{__global.viewSource}} +{{/sourceurl}} +{{/_disableContribution}} +

    {{>partials/title}}

    +
    {{{summary}}}
    +
    {{{conceptual}}}
    +
    {{{remarks}}}
    +{{#children}} +

    {{>partials/namespaceSubtitle}}

    + {{#children}} +

    {{{specName.0.value}}}

    +
    {{{summary}}}
    + {{/children}} +{{/children}} diff --git a/apidocs/umbracotemplate/partials/navbar.tmpl.partial b/apidocs/umbracotemplate/partials/navbar.tmpl.partial new file mode 100644 index 0000000000..e9ee0af1c7 --- /dev/null +++ b/apidocs/umbracotemplate/partials/navbar.tmpl.partial @@ -0,0 +1,22 @@ +{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}} + + diff --git a/apidocs/umbracotemplate/partials/rest.tmpl.partial b/apidocs/umbracotemplate/partials/rest.tmpl.partial new file mode 100644 index 0000000000..4306bf7db1 --- /dev/null +++ b/apidocs/umbracotemplate/partials/rest.tmpl.partial @@ -0,0 +1,101 @@ +{{!Copyright (c) Microsoft. All rights reserved. Licensed under the MIT license. See LICENSE file in the project root for full license information.}} + +{{^_disableContribution}} +{{#sourceurl}}View Source{{/sourceurl}} +{{/_disableContribution}} +

    {{name}}

    +{{#summary}} +
    {{{summary}}}
    +{{/summary}} +{{#description}} +
    {{{description}}}
    +{{/description}} +{{#conceptual}} +
    {{{conceptual}}}
    +{{/conceptual}} +{{#children}} +{{^_disableContribution}} +{{#sourceurl}} + + View Source +{{/sourceurl}} +{{/_disableContribution}} +

    {{operationId}}

    +{{#summary}} +
    {{{summary}}}
    +{{/summary}} +{{#description}} +
    {{{description}}}
    +{{/description}} +{{#conceptual}} +
    {{{conceptual}}}
    +{{/conceptual}} +
    Request
    +
    +
    {{operation}} {{path}}
    +
    +{{#parameters.0}} +
    Parameters
    + + + + + + + + + + +{{/parameters.0}} +{{#parameters}} + + + + + + + {{/parameters}} + {{#parameters.0}} + +
    NameTypeValueNotes
    {{#required}}*{{/required}}{{name}}{{type}}{{default}}{{{description}}}
    +{{/parameters.0}} +{{#responses.0}} +
    +
    Responses
    + + + + + + + + + +{{/responses.0}} +{{#responses}} + + + + + + {{/responses}} + {{#responses.0}} + +
    Status CodeDescriptionSamples
    {{statusCode}}{{{description}}} + {{#examples}} +
    + Mime type: {{mimeType}} +
    +
    {{content}}
    + {{/examples}} +
    +
    +{{/responses.0}} +{{#footer}} + +{{/footer}} +{{/children}} +{{#footer}} + +{{/footer}} + diff --git a/apidocs/umbracotemplate/styles/main.css b/apidocs/umbracotemplate/styles/main.css new file mode 100644 index 0000000000..7756b2f7d4 --- /dev/null +++ b/apidocs/umbracotemplate/styles/main.css @@ -0,0 +1,73 @@ +body { + color: rgba(0,0,0,.8); +} +.navbar-inverse { + background: #a3db78; +} +.navbar-inverse .navbar-nav>li>a, .navbar-inverse .navbar-text { + color: rgba(0,0,0,.8); +} + +.navbar-inverse { + border-color: transparent; +} + +.sidetoc { + background-color: #f5fbf1; +} +body .toc { + background-color: #f5fbf1; +} +.sidefilter { + background-color: #daf0c9; +} +.subnav { + background-color: #f5fbf1; +} + +.navbar-inverse .navbar-nav>.active>a { + color: rgba(0,0,0,.8); + background-color: #daf0c9; +} + +.navbar-inverse .navbar-nav>.active>a:focus, .navbar-inverse .navbar-nav>.active>a:hover { + color: rgba(0,0,0,.8); + background-color: #daf0c9; +} + +.btn-primary { + color: rgba(0,0,0,.8); + background-color: #fff; + border-color: rgba(0,0,0,.8); +} +.btn-primary:hover { + background-color: #daf0c9; + color: rgba(0,0,0,.8); + border-color: rgba(0,0,0,.8); +} + +.toc .nav > li > a { + color: rgba(0,0,0,.8); +} + +button, a { + color: #f36f21; +} + +button:hover, +button:focus, +a:hover, +a:focus { + color: #143653; + text-decoration: none; +} + +.navbar-header .navbar-brand { + background: url(https://our.umbraco.org/assets/images/logo.svg) left center no-repeat; + background-size: 40px auto; + width:50px; +} + +.toc .nav > li.active > a { + color: #f36f21; +} diff --git a/build/ApiDocs/TOC.css b/build/ApiDocs/TOC.css deleted file mode 100644 index 9c32aba214..0000000000 --- a/build/ApiDocs/TOC.css +++ /dev/null @@ -1,170 +0,0 @@ -/* File : TOC.css -// Author : Eric Woodruff (Eric@EWoodruff.us) -// Updated : 09/07/2007 -// -// Stylesheet for the table of content -*/ - -* -{ - margin: 0px 0px 0px 0px; - padding: 0px 0px 0px 0px; -} - -body -{ - font-family: Segoe UI, Arial, Verdana, Helvetica, sans-serif; - font-size: 0.9em; - background-color: white; - color: White; - overflow: hidden; -} - -input -{ - padding:5px; - margin: 3px 0px 3px 0px -} - -img -{ - border: 0; - margin-left: 5px; - margin-right: 2px; -} - -img.TreeNodeImg -{ - cursor: pointer; -} - -img.TOCLink -{ - cursor: pointer; - margin-left: 0; - margin-right: 0; -} - -a.SelectedNode, a.UnselectedNode -{ - color: #333; - text-decoration: none; - padding: 1px 3px 1px 3px; - white-space: nowrap; -} - -a.SelectedNode -{ - background-color: #ffffff; - border: solid 1px #999999; - padding: 0px 2px 0px 2px; -} - -a.UnselectedNode:hover, a.SelectedNode:hover -{ - background-color: #cccccc; - border: solid 1px #999999; - padding: 0px 2px 0px 2px; -} - -.Visible -{ - display: block; - margin-left: 2em; -} - -.Hidden -{ - display: none; -} - -.Tree -{ - background-color: #fff; - color: #333; - width: 300px; - overflow: auto; -} - -.TreeNode, .TreeItem -{ - white-space: nowrap; - margin: 2px 2px 2px 2px; -} - -.TOCDiv -{ - position: relative; - float: left; - width: 300px; - height: 100%; -} - -.TOCSizer -{ - clear: none; - float: left; - width: 10px; - height: 100%; - background-image: url("Splitter.gif"); - background-position:center center; - background-repeat:no-repeat; - position: relative; - cursor: w-resize; - border-left: solid 1px #CCC; -} - -.TopicContent -{ - position: relative; - float: right; - background-color: white; - height: 100%; -} - -.SearchOpts -{ - padding: 5px 5px 10px 5px; - color: black; - width: 300px; - border-bottom: solid lightgrey 1px; - height: 110px !important; -} - -.NavOpts -{ - padding: 5px 5px 6px 5px; - color: black; - width: 300px; - border-bottom: solid lightgrey 1px; -} - -.NavOpts img { - display:inline-block; - margin: 0px 5px 0px 5px; -} - -.IndexOpts -{ - padding: 5px 5px 6px 5px; - color: black; - width: 300px; - border-bottom: solid lightgrey 1px; -} - -.IndexItem -{ - white-space: nowrap; - margin: 2px 2px 2px 2px; -} - -.IndexSubItem -{ - white-space: nowrap; - margin: 2px 2px 2px 12px; -} - -.PaddedText -{ - margin: 10px 10px 10px 10px; -} diff --git a/build/ApiDocs/csharp-api-docs.shfbproj b/build/ApiDocs/csharp-api-docs.shfbproj deleted file mode 100644 index f635f2e2ee..0000000000 --- a/build/ApiDocs/csharp-api-docs.shfbproj +++ /dev/null @@ -1,172 +0,0 @@ - - - - - Debug - AnyCPU - 2.0 - {cb4d85f1-7390-40ee-b41f-a724bb8fddea} - 1.9.5.0 - - Documentation - Documentation - Documentation - - .NET Framework 4.5 - .\Output\ - UmbracoClassLibrary - en-US - OnlyErrors - csharp-api-docs.log - Website - True - False - False - False - True - CSharp - Blank - False - VS2010 - False - Guid - Umbraco .Net Class Library - AboveNamespaces - Attributes, InheritedMembers, InheritedFrameworkMembers, Protected, SealedProtected - - - - - - - None - None - False - True - Summary, AutoDocumentCtors, AutoDocumentDispose - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/build/BuildDocs.bat b/build/BuildDocs.bat new file mode 100644 index 0000000000..9d0a04e1cd --- /dev/null +++ b/build/BuildDocs.bat @@ -0,0 +1,20 @@ +@ECHO OFF +SETLOCAL + +SET release=%1 +ECHO Installing Npm NuGet Package + +SET nuGetFolder=%CD%\..\src\packages\ +ECHO Configured packages folder: %nuGetFolder% +ECHO Current folder: %CD% + +%CD%\..\src\.nuget\NuGet.exe install Npm.js -OutputDirectory %nuGetFolder% -Verbosity quiet + +for /f "delims=" %%A in ('dir %nuGetFolder%node.js.* /b') do set "nodePath=%nuGetFolder%%%A\" +for /f "delims=" %%A in ('dir %nuGetFolder%npm.js.* /b') do set "npmPath=%nuGetFolder%%%A\tools\" + +ECHO Adding Npm and Node to path +REM SETLOCAL is on, so changes to the path not persist to the actual user's path +PATH=%npmPath%;%nodePath%;%PATH% + +Powershell.exe -ExecutionPolicy Unrestricted -File .\BuildDocs.ps1 \ No newline at end of file diff --git a/build/BuildDocs.ps1 b/build/BuildDocs.ps1 index 6f46a43fde..dcb3a85cc1 100644 --- a/build/BuildDocs.ps1 +++ b/build/BuildDocs.ps1 @@ -1,27 +1,100 @@ -##We cannot continue if sandcastle is not installed determined by env variable: SHFBROOT +$PSScriptFilePath = (Get-Item $MyInvocation.MyCommand.Path); +$RepoRoot = (get-item $PSScriptFilePath).Directory.Parent.FullName; +$SolutionRoot = Join-Path -Path $RepoRoot "src"; +$ToolsRoot = Join-Path -Path $RepoRoot "tools"; +$DocFx = Join-Path -Path $ToolsRoot "docfx\docfx.exe" +$DocFxFolder = (Join-Path -Path $ToolsRoot "docfx") +$DocFxJson = Join-Path -Path $RepoRoot "apidocs\docfx.json" +$7Zip = Join-Path -Path $ToolsRoot "7zip\7za.exe" +$DocFxSiteOutput = Join-Path -Path $RepoRoot "apidocs\_site\*.*" +$NgDocsSiteOutput = Join-Path -Path $RepoRoot "src\Umbraco.Web.UI.Client\docs\api\*.*" +$ProgFiles86 = [Environment]::GetEnvironmentVariable("ProgramFiles(x86)"); +$MSBuild = "$ProgFiles86\MSBuild\14.0\Bin\MSBuild.exe" -if (-not (Test-Path Env:\SHFBROOT)) -{ - throw "The docs cannot be build, install Sandcastle help file builder" + +################ Do the UI docs + +"Changing to Umbraco.Web.UI.Client folder" +cd .. +cd src\Umbraco.Web.UI.Client +Write-Host $(Get-Location) + +"Creating build folder so MSBuild doesn't run the whole grunt build" +if (-Not (Test-Path "build")) { + md "build" } -$PSScriptFilePath = (Get-Item $MyInvocation.MyCommand.Path).FullName -$BuildRoot = Split-Path -Path $PSScriptFilePath -Parent -$OutputPath = Join-Path -Path $BuildRoot -ChildPath "ApiDocs\Output" -$ProjFile = Join-Path -Path $BuildRoot -ChildPath "ApiDocs\csharp-api-docs.shfbproj" +"Installing node" +# Check if Install-Product exists, should only exist on the build server +if (Get-Command Install-Product -errorAction SilentlyContinue) +{ + Install-Product node '' +} -"Building docs with project file: $ProjFile" +"Installing node modules" +& npm install -$MSBuild = "$Env:SYSTEMROOT\Microsoft.NET\Framework\v4.0.30319\msbuild.exe" +"Installing grunt" +& npm install -g grunt-cli -# build it! -& $MSBuild "$ProjFile" +"Moving back to build folder" +cd .. +cd .. +cd build +Write-Host $(Get-Location) -# remove files left over -Remove-Item $BuildRoot\* -include csharp-api-docs.shfbproj_* + & grunt --gruntfile ../src/umbraco.web.ui.client/gruntfile.js docs -# copy our custom styles in -Copy-Item $BuildRoot\ApiDocs\TOC.css $OutputPath\TOC.css +# change baseUrl +$BaseUrl = "https://our.umbraco.org/apidocs/ui/" +$IndexPath = "../src/umbraco.web.ui.client/docs/api/index.html" +(Get-Content $IndexPath).replace('location.href.replace(rUrl, indexFile)', "`'" + $BaseUrl + "`'") | Set-Content $IndexPath +# zip it -"" -"Done!" \ No newline at end of file +& $7Zip a -tzip ui-docs.zip $NgDocsSiteOutput -r + +################ Do the c# docs + +# Build the solution in debug mode +$SolutionPath = Join-Path -Path $SolutionRoot -ChildPath "umbraco.sln" +& $MSBuild "$SolutionPath" /p:Configuration=Debug /maxcpucount /t:Clean +if (-not $?) +{ + throw "The MSBuild process returned an error code." +} +& $MSBuild "$SolutionPath" /p:Configuration=Debug /maxcpucount +if (-not $?) +{ + throw "The MSBuild process returned an error code." +} + +# Go get docfx if we don't hae it +$FileExists = Test-Path $DocFx +If ($FileExists -eq $False) { + + If(!(Test-Path $DocFxFolder)) + { + New-Item $DocFxFolder -type directory + } + + $DocFxZip = Join-Path -Path $ToolsRoot "docfx\docfx.zip" + $DocFxSource = "https://github.com/dotnet/docfx/releases/download/v1.9.4/docfx.zip" + Invoke-WebRequest $DocFxSource -OutFile $DocFxZip + + #unzip it + & $7Zip e $DocFxZip "-o$DocFxFolder" +} + +#clear site +If(Test-Path(Join-Path -Path $RepoRoot "apidocs\_site")) +{ + Remove-Item $DocFxSiteOutput -recurse +} + +# run it! +& $DocFx metadata $DocFxJson +& $DocFx build $DocFxJson + +# zip it + +& $7Zip a -tzip csharp-docs.zip $DocFxSiteOutput -r diff --git a/src/Umbraco.Web.UI.Client/docs/src/api/index.ngdoc b/src/Umbraco.Web.UI.Client/docs/src/api/index.ngdoc index a7cf500744..74cc458b90 100644 --- a/src/Umbraco.Web.UI.Client/docs/src/api/index.ngdoc +++ b/src/Umbraco.Web.UI.Client/docs/src/api/index.ngdoc @@ -2,15 +2,9 @@ @name Umbraco 7 JS documentation @description -#Belle +#Umbraco Backoffice UI API documentation -Umbraco 7 UI, codename "Belle" Built on AngularJS, Lazyload.js and Twitter Bootstrap - -##Introduction -Slides from the initial demonstration of Belle done at the Umbraco DK Fest can be found here: - -http://rawgithub.com/umbraco/Belle/master/Presentation/index.html - +This documentation relates to the angular, js, css and less APIs for developing back office components ##Running the site with mocked data @@ -45,7 +39,7 @@ So run the command: sudo npm install grunt-cli -g -Now that you have node and grunt installed, you can open `/Umbraco.Belle.Client` in either `cmd.exe` or terminal and run: +Now that you have node and grunt installed, you can open `/Umbraco.Web.UI.Client` in either `cmd.exe` or terminal and run: grunt dev diff --git a/src/Umbraco.Web.UI.Client/docs/umb-docs.css b/src/Umbraco.Web.UI.Client/docs/umb-docs.css new file mode 100644 index 0000000000..eef0fcee39 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/docs/umb-docs.css @@ -0,0 +1,78 @@ + +html { + font-family: 'Segoe UI', Tahoma, Helvetica, sans-serif; +} +body { + font-family: 'Segoe UI', Tahoma, Helvetica, sans-serif; + +} + +.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 { + font-family: inherit; + font-weight: 400; + line-height: 1.1; + color: inherit; +} + +.content code { + font-family: inherit; +} + +.navbar .brand { + display: block; + float: left; + padding: 10px 20px 10px; + margin-left: -20px; + font-size: 20px; + font-weight: 200; + color: rgba(0,0,0,.8); + text-shadow: none; +} + +.navbar-fixed-top .navbar-inner { + min-height: 50px; + background: #a3db78; +} + +.form-search .well { + background-color: #f5fbf1; +} + +.form-search > ul.nav > li.module { + background-color: #daf0c9; +} + +.breadcrumb { + background-color: #f5fbf1; +} + +a { + color: #f36f21; +} +a:hover { + text-decoration: none; + color: rgba(0,0,0,.8); +} +.nav-list > .active > a, .nav-list > .active > a:hover, .nav-list > .active > a:focus, +.form-search > .nav-list > .active > a, .form-search > .nav-list > .active > a:hover, .form-search > .nav-list > .active > a:focus { + color: #f36f21; + text-shadow: none; + background-color: inherit; +} + +.form-search > ul.nav > li > a { + color: rgba(0,0,0,.8); + text-shadow: none; +} + +.form-search > ul.nav > li > a:hover { + text-decoration: none; + background-color: inherit; + text-shadow: none; + color: #000; +} + +.header img { + width: 50px; + margin-top: 5px; +} diff --git a/src/Umbraco.Web.UI.Client/gruntFile.js b/src/Umbraco.Web.UI.Client/gruntFile.js index 0500e24c31..fcae3e6b62 100644 --- a/src/Umbraco.Web.UI.Client/gruntFile.js +++ b/src/Umbraco.Web.UI.Client/gruntFile.js @@ -380,8 +380,12 @@ module.exports = function (grunt) { options: { dest: 'docs/api', startPage: '/api', - title: "Umbraco 7", + title: "Umbraco Backoffice UI API Documentation", html5Mode: false, + styles: [ + 'docs/umb-docs.css' + ], + image: "https://our.umbraco.org/assets/images/logo.svg" }, api: { src: ['src/common/**/*.js', 'docs/src/api/**/*.ngdoc'], @@ -390,7 +394,7 @@ module.exports = function (grunt) { tutorials: { src: [], title: '' - } + } }, eslint:{ diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 33d150490b..4bd0be1308 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -2426,7 +2426,7 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\" - + diff --git a/src/umbraco.sln b/src/umbraco.sln index d97aebf4f2..f9267c0412 100644 --- a/src/umbraco.sln +++ b/src/umbraco.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.24720.0 +VisualStudioVersion = 14.0.25123.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Umbraco.Web.UI", "Umbraco.Web.UI\Umbraco.Web.UI.csproj", "{4C4C194C-B5E4-4991-8F87-4373E24CC19F}" EndProject @@ -9,6 +9,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{2849E9D4 ..\build\Build.bat = ..\build\Build.bat ..\build\Build.proj = ..\build\Build.proj ..\build\BuildBelle.bat = ..\build\BuildBelle.bat + ..\build\BuildDocs.ps1 = ..\build\BuildDocs.ps1 ..\build\RevertToCleanInstall.bat = ..\build\RevertToCleanInstall.bat ..\build\RevertToEmptyInstall.bat = ..\build\RevertToEmptyInstall.bat SolutionInfo.cs = SolutionInfo.cs @@ -19,8 +20,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{2849E9D4 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Docs", "Docs", "{FD962632-184C-4005-A5F3-E705D92FC645}" ProjectSection(SolutionItems) = preProject + ..\apidocs\docfx.filter.yml = ..\apidocs\docfx.filter.yml + ..\apidocs\docfx.json = ..\apidocs\docfx.json + ..\apidocs\index.md = ..\apidocs\index.md ..\LICENSE.md = ..\LICENSE.md ..\README.md = ..\README.md + ..\apidocs\toc.yml = ..\apidocs\toc.yml EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{B5BD12C1-A454-435E-8A46-FF4A364C0382}" From def690b8c368f784094e5f4c98b75a28f639eb47 Mon Sep 17 00:00:00 2001 From: Darren Ferguson Date: Mon, 30 May 2016 11:15:03 +0100 Subject: [PATCH 109/535] Fix U4-8532 - No built in Active Directory authentication in Umbraco 7.3+ --- .../ActiveDirectoryBackOfficeUserPasswordChecker.cs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Core/Security/ActiveDirectoryBackOfficeUserPasswordChecker.cs b/src/Umbraco.Core/Security/ActiveDirectoryBackOfficeUserPasswordChecker.cs index aef4f3dc76..819fa87a56 100644 --- a/src/Umbraco.Core/Security/ActiveDirectoryBackOfficeUserPasswordChecker.cs +++ b/src/Umbraco.Core/Security/ActiveDirectoryBackOfficeUserPasswordChecker.cs @@ -7,10 +7,16 @@ namespace Umbraco.Core.Security { public class ActiveDirectoryBackOfficeUserPasswordChecker : IBackOfficeUserPasswordChecker { + public virtual string ActiveDirectoryDomain { + get { + return ConfigurationManager.AppSettings["ActiveDirectoryDomain"]; + } + } + public Task CheckPasswordAsync(BackOfficeIdentityUser user, string password) { bool isValid; - using (var pc = new PrincipalContext(ContextType.Domain, ConfigurationManager.AppSettings["ActiveDirectoryDomain"])) + using (var pc = new PrincipalContext(ContextType.Domain, ActiveDirectoryDomain)) { isValid = pc.ValidateCredentials(user.UserName, password); } From 9190855bcf6bca61a83df98c14a1e78c439665d0 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Mon, 30 May 2016 14:08:30 +0200 Subject: [PATCH 110/535] add configuration to disable folder select --- .../propertyeditors/mediapicker/mediapicker.controller.js | 2 ++ .../PropertyEditors/MultipleMediaPickerPropertyEditor.cs | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js index 9969af937d..bbf61a32d3 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js @@ -6,6 +6,7 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl //check the pre-values for multi-picker var multiPicker = $scope.model.config.multiPicker && $scope.model.config.multiPicker !== '0' ? true : false; var onlyImages = $scope.model.config.onlyImages && $scope.model.config.onlyImages !== '0' ? true : false; + var disableFolderSelect = $scope.model.config.disableFolderSelect && $scope.model.config.disableFolderSelect !== '0' ? true : false; if (!$scope.model.config.startNodeId) { userService.getCurrentUser().then(function (userData) { @@ -68,6 +69,7 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl startNodeId: $scope.model.config.startNodeId, multiPicker: multiPicker, onlyImages: onlyImages, + disableFolderSelect: disableFolderSelect, show: true, submit: function(model) { diff --git a/src/Umbraco.Web/PropertyEditors/MultipleMediaPickerPropertyEditor.cs b/src/Umbraco.Web/PropertyEditors/MultipleMediaPickerPropertyEditor.cs index bbb3ee6c17..37587d1c54 100644 --- a/src/Umbraco.Web/PropertyEditors/MultipleMediaPickerPropertyEditor.cs +++ b/src/Umbraco.Web/PropertyEditors/MultipleMediaPickerPropertyEditor.cs @@ -23,7 +23,10 @@ namespace Umbraco.Web.PropertyEditors public bool MultiPicker { get; set; } [PreValueField("onlyImages", "Pick only images", "boolean", Description = "Only let the editor choose images from media.")] - public bool OnlyImages { get; set; } + public bool OnlyImages { get; set; } + + [PreValueField("disableFolderSelect", "Disable folder select", "boolean", Description = "Do not allow folders to be picked.")] + public bool DisableFolderSelect { get; set; } [PreValueField("startNodeId", "Start node", "mediapicker")] public int StartNodeId { get; set; } From 4aa4a0301369d35b9c436ef82accf33a95520add Mon Sep 17 00:00:00 2001 From: Shannon Date: Mon, 30 May 2016 14:25:47 +0200 Subject: [PATCH 111/535] U4-8511 Update moment.js to the version to 2.10.3 for release --- src/Umbraco.Web.UI.Client/bower.json | 3 +- src/Umbraco.Web.UI.Client/gruntFile.js | 4 + .../lib/moment/moment-with-locales.js | 9156 ----------------- 3 files changed, 6 insertions(+), 9157 deletions(-) delete mode 100644 src/Umbraco.Web.UI.Client/lib/moment/moment-with-locales.js diff --git a/src/Umbraco.Web.UI.Client/bower.json b/src/Umbraco.Web.UI.Client/bower.json index ab78d10380..d1397b5d4e 100644 --- a/src/Umbraco.Web.UI.Client/bower.json +++ b/src/Umbraco.Web.UI.Client/bower.json @@ -26,6 +26,7 @@ "ng-file-upload": "~7.3.8", "tinymce": "~4.1.10", "codemirror": "~5.3.0", - "angular-local-storage": "~0.2.3" + "angular-local-storage": "~0.2.3", + "moment": "~2.10.3" } } diff --git a/src/Umbraco.Web.UI.Client/gruntFile.js b/src/Umbraco.Web.UI.Client/gruntFile.js index fcae3e6b62..d5b785c54c 100644 --- a/src/Umbraco.Web.UI.Client/gruntFile.js +++ b/src/Umbraco.Web.UI.Client/gruntFile.js @@ -463,6 +463,10 @@ module.exports = function (grunt) { expand: true, ignorePackages: ['bootstrap'], packageSpecific: { + 'moment': { + keepExpandedHierarchy: false, + files: ['min/moment-with-locales.js'] + }, 'typeahead.js': { keepExpandedHierarchy: false, files: ['dist/typeahead.bundle.min.js'] diff --git a/src/Umbraco.Web.UI.Client/lib/moment/moment-with-locales.js b/src/Umbraco.Web.UI.Client/lib/moment/moment-with-locales.js deleted file mode 100644 index 23d06ef355..0000000000 --- a/src/Umbraco.Web.UI.Client/lib/moment/moment-with-locales.js +++ /dev/null @@ -1,9156 +0,0 @@ -//! moment.js -//! version : 2.8.3 -//! authors : Tim Wood, Iskren Chernev, Moment.js contributors -//! license : MIT -//! momentjs.com - -(function (undefined) { - /************************************ - Constants - ************************************/ - - var moment, - VERSION = '2.8.3', - // the global-scope this is NOT the global object in Node.js - globalScope = typeof global !== 'undefined' ? global : this, - oldGlobalMoment, - round = Math.round, - hasOwnProperty = Object.prototype.hasOwnProperty, - i, - - YEAR = 0, - MONTH = 1, - DATE = 2, - HOUR = 3, - MINUTE = 4, - SECOND = 5, - MILLISECOND = 6, - - // internal storage for locale config files - locales = {}, - - // extra moment internal properties (plugins register props here) - momentProperties = [], - - // check for nodeJS - hasModule = (typeof module !== 'undefined' && module.exports), - - // ASP.NET json date format regex - aspNetJsonRegex = /^\/?Date\((\-?\d+)/i, - aspNetTimeSpanJsonRegex = /(\-)?(?:(\d*)\.)?(\d+)\:(\d+)(?:\:(\d+)\.?(\d{3})?)?/, - - // from http://docs.closure-library.googlecode.com/git/closure_goog_date_date.js.source.html - // somewhat more in line with 4.4.3.2 2004 spec, but allows decimal anywhere - isoDurationRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/, - - // format tokens - formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g, - localFormattingTokens = /(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g, - - // parsing token regexes - parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99 - parseTokenOneToThreeDigits = /\d{1,3}/, // 0 - 999 - parseTokenOneToFourDigits = /\d{1,4}/, // 0 - 9999 - parseTokenOneToSixDigits = /[+\-]?\d{1,6}/, // -999,999 - 999,999 - parseTokenDigits = /\d+/, // nonzero number of digits - parseTokenWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, // any word (or two) characters or numbers including two/three word month in arabic. - parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z - parseTokenT = /T/i, // T (ISO separator) - parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123 - parseTokenOrdinal = /\d{1,2}/, - - //strict parsing regexes - parseTokenOneDigit = /\d/, // 0 - 9 - parseTokenTwoDigits = /\d\d/, // 00 - 99 - parseTokenThreeDigits = /\d{3}/, // 000 - 999 - parseTokenFourDigits = /\d{4}/, // 0000 - 9999 - parseTokenSixDigits = /[+-]?\d{6}/, // -999,999 - 999,999 - parseTokenSignedNumber = /[+-]?\d+/, // -inf - inf - - // iso 8601 regex - // 0000-00-00 0000-W00 or 0000-W00-0 + T + 00 or 00:00 or 00:00:00 or 00:00:00.000 + +00:00 or +0000 or +00) - isoRegex = /^\s*(?:[+-]\d{6}|\d{4})-(?:(\d\d-\d\d)|(W\d\d$)|(W\d\d-\d)|(\d\d\d))((T| )(\d\d(:\d\d(:\d\d(\.\d+)?)?)?)?([\+\-]\d\d(?::?\d\d)?|\s*Z)?)?$/, - - isoFormat = 'YYYY-MM-DDTHH:mm:ssZ', - - isoDates = [ - ['YYYYYY-MM-DD', /[+-]\d{6}-\d{2}-\d{2}/], - ['YYYY-MM-DD', /\d{4}-\d{2}-\d{2}/], - ['GGGG-[W]WW-E', /\d{4}-W\d{2}-\d/], - ['GGGG-[W]WW', /\d{4}-W\d{2}/], - ['YYYY-DDD', /\d{4}-\d{3}/] - ], - - // iso time formats and regexes - isoTimes = [ - ['HH:mm:ss.SSSS', /(T| )\d\d:\d\d:\d\d\.\d+/], - ['HH:mm:ss', /(T| )\d\d:\d\d:\d\d/], - ['HH:mm', /(T| )\d\d:\d\d/], - ['HH', /(T| )\d\d/] - ], - - // timezone chunker '+10:00' > ['10', '00'] or '-1530' > ['-15', '30'] - parseTimezoneChunker = /([\+\-]|\d\d)/gi, - - // getter and setter names - proxyGettersAndSetters = 'Date|Hours|Minutes|Seconds|Milliseconds'.split('|'), - unitMillisecondFactors = { - 'Milliseconds' : 1, - 'Seconds' : 1e3, - 'Minutes' : 6e4, - 'Hours' : 36e5, - 'Days' : 864e5, - 'Months' : 2592e6, - 'Years' : 31536e6 - }, - - unitAliases = { - ms : 'millisecond', - s : 'second', - m : 'minute', - h : 'hour', - d : 'day', - D : 'date', - w : 'week', - W : 'isoWeek', - M : 'month', - Q : 'quarter', - y : 'year', - DDD : 'dayOfYear', - e : 'weekday', - E : 'isoWeekday', - gg: 'weekYear', - GG: 'isoWeekYear' - }, - - camelFunctions = { - dayofyear : 'dayOfYear', - isoweekday : 'isoWeekday', - isoweek : 'isoWeek', - weekyear : 'weekYear', - isoweekyear : 'isoWeekYear' - }, - - // format function strings - formatFunctions = {}, - - // default relative time thresholds - relativeTimeThresholds = { - s: 45, // seconds to minute - m: 45, // minutes to hour - h: 22, // hours to day - d: 26, // days to month - M: 11 // months to year - }, - - // tokens to ordinalize and pad - ordinalizeTokens = 'DDD w W M D d'.split(' '), - paddedTokens = 'M D H h m s w W'.split(' '), - - formatTokenFunctions = { - M : function () { - return this.month() + 1; - }, - MMM : function (format) { - return this.localeData().monthsShort(this, format); - }, - MMMM : function (format) { - return this.localeData().months(this, format); - }, - D : function () { - return this.date(); - }, - DDD : function () { - return this.dayOfYear(); - }, - d : function () { - return this.day(); - }, - dd : function (format) { - return this.localeData().weekdaysMin(this, format); - }, - ddd : function (format) { - return this.localeData().weekdaysShort(this, format); - }, - dddd : function (format) { - return this.localeData().weekdays(this, format); - }, - w : function () { - return this.week(); - }, - W : function () { - return this.isoWeek(); - }, - YY : function () { - return leftZeroFill(this.year() % 100, 2); - }, - YYYY : function () { - return leftZeroFill(this.year(), 4); - }, - YYYYY : function () { - return leftZeroFill(this.year(), 5); - }, - YYYYYY : function () { - var y = this.year(), sign = y >= 0 ? '+' : '-'; - return sign + leftZeroFill(Math.abs(y), 6); - }, - gg : function () { - return leftZeroFill(this.weekYear() % 100, 2); - }, - gggg : function () { - return leftZeroFill(this.weekYear(), 4); - }, - ggggg : function () { - return leftZeroFill(this.weekYear(), 5); - }, - GG : function () { - return leftZeroFill(this.isoWeekYear() % 100, 2); - }, - GGGG : function () { - return leftZeroFill(this.isoWeekYear(), 4); - }, - GGGGG : function () { - return leftZeroFill(this.isoWeekYear(), 5); - }, - e : function () { - return this.weekday(); - }, - E : function () { - return this.isoWeekday(); - }, - a : function () { - return this.localeData().meridiem(this.hours(), this.minutes(), true); - }, - A : function () { - return this.localeData().meridiem(this.hours(), this.minutes(), false); - }, - H : function () { - return this.hours(); - }, - h : function () { - return this.hours() % 12 || 12; - }, - m : function () { - return this.minutes(); - }, - s : function () { - return this.seconds(); - }, - S : function () { - return toInt(this.milliseconds() / 100); - }, - SS : function () { - return leftZeroFill(toInt(this.milliseconds() / 10), 2); - }, - SSS : function () { - return leftZeroFill(this.milliseconds(), 3); - }, - SSSS : function () { - return leftZeroFill(this.milliseconds(), 3); - }, - Z : function () { - var a = -this.zone(), - b = '+'; - if (a < 0) { - a = -a; - b = '-'; - } - return b + leftZeroFill(toInt(a / 60), 2) + ':' + leftZeroFill(toInt(a) % 60, 2); - }, - ZZ : function () { - var a = -this.zone(), - b = '+'; - if (a < 0) { - a = -a; - b = '-'; - } - return b + leftZeroFill(toInt(a / 60), 2) + leftZeroFill(toInt(a) % 60, 2); - }, - z : function () { - return this.zoneAbbr(); - }, - zz : function () { - return this.zoneName(); - }, - X : function () { - return this.unix(); - }, - Q : function () { - return this.quarter(); - } - }, - - deprecations = {}, - - lists = ['months', 'monthsShort', 'weekdays', 'weekdaysShort', 'weekdaysMin']; - - // Pick the first defined of two or three arguments. dfl comes from - // default. - function dfl(a, b, c) { - switch (arguments.length) { - case 2: return a != null ? a : b; - case 3: return a != null ? a : b != null ? b : c; - default: throw new Error('Implement me'); - } - } - - function hasOwnProp(a, b) { - return hasOwnProperty.call(a, b); - } - - function defaultParsingFlags() { - // We need to deep clone this object, and es5 standard is not very - // helpful. - return { - empty : false, - unusedTokens : [], - unusedInput : [], - overflow : -2, - charsLeftOver : 0, - nullInput : false, - invalidMonth : null, - invalidFormat : false, - userInvalidated : false, - iso: false - }; - } - - function printMsg(msg) { - if (moment.suppressDeprecationWarnings === false && - typeof console !== 'undefined' && console.warn) { - console.warn('Deprecation warning: ' + msg); - } - } - - function deprecate(msg, fn) { - var firstTime = true; - return extend(function () { - if (firstTime) { - printMsg(msg); - firstTime = false; - } - return fn.apply(this, arguments); - }, fn); - } - - function deprecateSimple(name, msg) { - if (!deprecations[name]) { - printMsg(msg); - deprecations[name] = true; - } - } - - function padToken(func, count) { - return function (a) { - return leftZeroFill(func.call(this, a), count); - }; - } - function ordinalizeToken(func, period) { - return function (a) { - return this.localeData().ordinal(func.call(this, a), period); - }; - } - - while (ordinalizeTokens.length) { - i = ordinalizeTokens.pop(); - formatTokenFunctions[i + 'o'] = ordinalizeToken(formatTokenFunctions[i], i); - } - while (paddedTokens.length) { - i = paddedTokens.pop(); - formatTokenFunctions[i + i] = padToken(formatTokenFunctions[i], 2); - } - formatTokenFunctions.DDDD = padToken(formatTokenFunctions.DDD, 3); - - - /************************************ - Constructors - ************************************/ - - function Locale() { - } - - // Moment prototype object - function Moment(config, skipOverflow) { - if (skipOverflow !== false) { - checkOverflow(config); - } - copyConfig(this, config); - this._d = new Date(+config._d); - } - - // Duration Constructor - function Duration(duration) { - var normalizedInput = normalizeObjectUnits(duration), - years = normalizedInput.year || 0, - quarters = normalizedInput.quarter || 0, - months = normalizedInput.month || 0, - weeks = normalizedInput.week || 0, - days = normalizedInput.day || 0, - hours = normalizedInput.hour || 0, - minutes = normalizedInput.minute || 0, - seconds = normalizedInput.second || 0, - milliseconds = normalizedInput.millisecond || 0; - - // representation for dateAddRemove - this._milliseconds = +milliseconds + - seconds * 1e3 + // 1000 - minutes * 6e4 + // 1000 * 60 - hours * 36e5; // 1000 * 60 * 60 - // Because of dateAddRemove treats 24 hours as different from a - // day when working around DST, we need to store them separately - this._days = +days + - weeks * 7; - // It is impossible translate months into days without knowing - // which months you are are talking about, so we have to store - // it separately. - this._months = +months + - quarters * 3 + - years * 12; - - this._data = {}; - - this._locale = moment.localeData(); - - this._bubble(); - } - - /************************************ - Helpers - ************************************/ - - - function extend(a, b) { - for (var i in b) { - if (hasOwnProp(b, i)) { - a[i] = b[i]; - } - } - - if (hasOwnProp(b, 'toString')) { - a.toString = b.toString; - } - - if (hasOwnProp(b, 'valueOf')) { - a.valueOf = b.valueOf; - } - - return a; - } - - function copyConfig(to, from) { - var i, prop, val; - - if (typeof from._isAMomentObject !== 'undefined') { - to._isAMomentObject = from._isAMomentObject; - } - if (typeof from._i !== 'undefined') { - to._i = from._i; - } - if (typeof from._f !== 'undefined') { - to._f = from._f; - } - if (typeof from._l !== 'undefined') { - to._l = from._l; - } - if (typeof from._strict !== 'undefined') { - to._strict = from._strict; - } - if (typeof from._tzm !== 'undefined') { - to._tzm = from._tzm; - } - if (typeof from._isUTC !== 'undefined') { - to._isUTC = from._isUTC; - } - if (typeof from._offset !== 'undefined') { - to._offset = from._offset; - } - if (typeof from._pf !== 'undefined') { - to._pf = from._pf; - } - if (typeof from._locale !== 'undefined') { - to._locale = from._locale; - } - - if (momentProperties.length > 0) { - for (i in momentProperties) { - prop = momentProperties[i]; - val = from[prop]; - if (typeof val !== 'undefined') { - to[prop] = val; - } - } - } - - return to; - } - - function absRound(number) { - if (number < 0) { - return Math.ceil(number); - } else { - return Math.floor(number); - } - } - - // left zero fill a number - // see http://jsperf.com/left-zero-filling for performance comparison - function leftZeroFill(number, targetLength, forceSign) { - var output = '' + Math.abs(number), - sign = number >= 0; - - while (output.length < targetLength) { - output = '0' + output; - } - return (sign ? (forceSign ? '+' : '') : '-') + output; - } - - function positiveMomentsDifference(base, other) { - var res = {milliseconds: 0, months: 0}; - - res.months = other.month() - base.month() + - (other.year() - base.year()) * 12; - if (base.clone().add(res.months, 'M').isAfter(other)) { - --res.months; - } - - res.milliseconds = +other - +(base.clone().add(res.months, 'M')); - - return res; - } - - function momentsDifference(base, other) { - var res; - other = makeAs(other, base); - if (base.isBefore(other)) { - res = positiveMomentsDifference(base, other); - } else { - res = positiveMomentsDifference(other, base); - res.milliseconds = -res.milliseconds; - res.months = -res.months; - } - - return res; - } - - // TODO: remove 'name' arg after deprecation is removed - function createAdder(direction, name) { - return function (val, period) { - var dur, tmp; - //invert the arguments, but complain about it - if (period !== null && !isNaN(+period)) { - deprecateSimple(name, 'moment().' + name + '(period, number) is deprecated. Please use moment().' + name + '(number, period).'); - tmp = val; val = period; period = tmp; - } - - val = typeof val === 'string' ? +val : val; - dur = moment.duration(val, period); - addOrSubtractDurationFromMoment(this, dur, direction); - return this; - }; - } - - function addOrSubtractDurationFromMoment(mom, duration, isAdding, updateOffset) { - var milliseconds = duration._milliseconds, - days = duration._days, - months = duration._months; - updateOffset = updateOffset == null ? true : updateOffset; - - if (milliseconds) { - mom._d.setTime(+mom._d + milliseconds * isAdding); - } - if (days) { - rawSetter(mom, 'Date', rawGetter(mom, 'Date') + days * isAdding); - } - if (months) { - rawMonthSetter(mom, rawGetter(mom, 'Month') + months * isAdding); - } - if (updateOffset) { - moment.updateOffset(mom, days || months); - } - } - - // check if is an array - function isArray(input) { - return Object.prototype.toString.call(input) === '[object Array]'; - } - - function isDate(input) { - return Object.prototype.toString.call(input) === '[object Date]' || - input instanceof Date; - } - - // compare two arrays, return the number of differences - function compareArrays(array1, array2, dontConvert) { - var len = Math.min(array1.length, array2.length), - lengthDiff = Math.abs(array1.length - array2.length), - diffs = 0, - i; - for (i = 0; i < len; i++) { - if ((dontConvert && array1[i] !== array2[i]) || - (!dontConvert && toInt(array1[i]) !== toInt(array2[i]))) { - diffs++; - } - } - return diffs + lengthDiff; - } - - function normalizeUnits(units) { - if (units) { - var lowered = units.toLowerCase().replace(/(.)s$/, '$1'); - units = unitAliases[units] || camelFunctions[lowered] || lowered; - } - return units; - } - - function normalizeObjectUnits(inputObject) { - var normalizedInput = {}, - normalizedProp, - prop; - - for (prop in inputObject) { - if (hasOwnProp(inputObject, prop)) { - normalizedProp = normalizeUnits(prop); - if (normalizedProp) { - normalizedInput[normalizedProp] = inputObject[prop]; - } - } - } - - return normalizedInput; - } - - function makeList(field) { - var count, setter; - - if (field.indexOf('week') === 0) { - count = 7; - setter = 'day'; - } - else if (field.indexOf('month') === 0) { - count = 12; - setter = 'month'; - } - else { - return; - } - - moment[field] = function (format, index) { - var i, getter, - method = moment._locale[field], - results = []; - - if (typeof format === 'number') { - index = format; - format = undefined; - } - - getter = function (i) { - var m = moment().utc().set(setter, i); - return method.call(moment._locale, m, format || ''); - }; - - if (index != null) { - return getter(index); - } - else { - for (i = 0; i < count; i++) { - results.push(getter(i)); - } - return results; - } - }; - } - - function toInt(argumentForCoercion) { - var coercedNumber = +argumentForCoercion, - value = 0; - - if (coercedNumber !== 0 && isFinite(coercedNumber)) { - if (coercedNumber >= 0) { - value = Math.floor(coercedNumber); - } else { - value = Math.ceil(coercedNumber); - } - } - - return value; - } - - function daysInMonth(year, month) { - return new Date(Date.UTC(year, month + 1, 0)).getUTCDate(); - } - - function weeksInYear(year, dow, doy) { - return weekOfYear(moment([year, 11, 31 + dow - doy]), dow, doy).week; - } - - function daysInYear(year) { - return isLeapYear(year) ? 366 : 365; - } - - function isLeapYear(year) { - return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; - } - - function checkOverflow(m) { - var overflow; - if (m._a && m._pf.overflow === -2) { - overflow = - m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH : - m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE : - m._a[HOUR] < 0 || m._a[HOUR] > 23 ? HOUR : - m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE : - m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND : - m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND : - -1; - - if (m._pf._overflowDayOfYear && (overflow < YEAR || overflow > DATE)) { - overflow = DATE; - } - - m._pf.overflow = overflow; - } - } - - function isValid(m) { - if (m._isValid == null) { - m._isValid = !isNaN(m._d.getTime()) && - m._pf.overflow < 0 && - !m._pf.empty && - !m._pf.invalidMonth && - !m._pf.nullInput && - !m._pf.invalidFormat && - !m._pf.userInvalidated; - - if (m._strict) { - m._isValid = m._isValid && - m._pf.charsLeftOver === 0 && - m._pf.unusedTokens.length === 0; - } - } - return m._isValid; - } - - function normalizeLocale(key) { - return key ? key.toLowerCase().replace('_', '-') : key; - } - - // pick the locale from the array - // try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each - // substring from most specific to least, but move to the next array item if it's a more specific variant than the current root - function chooseLocale(names) { - var i = 0, j, next, locale, split; - - while (i < names.length) { - split = normalizeLocale(names[i]).split('-'); - j = split.length; - next = normalizeLocale(names[i + 1]); - next = next ? next.split('-') : null; - while (j > 0) { - locale = loadLocale(split.slice(0, j).join('-')); - if (locale) { - return locale; - } - if (next && next.length >= j && compareArrays(split, next, true) >= j - 1) { - //the next array item is better than a shallower substring of this one - break; - } - j--; - } - i++; - } - return null; - } - - function loadLocale(name) { - var oldLocale = null; - if (!locales[name] && hasModule) { - try { - oldLocale = moment.locale(); - require('./locale/' + name); - // because defineLocale currently also sets the global locale, we want to undo that for lazy loaded locales - moment.locale(oldLocale); - } catch (e) { } - } - return locales[name]; - } - - // Return a moment from input, that is local/utc/zone equivalent to model. - function makeAs(input, model) { - return model._isUTC ? moment(input).zone(model._offset || 0) : - moment(input).local(); - } - - /************************************ - Locale - ************************************/ - - - extend(Locale.prototype, { - - set : function (config) { - var prop, i; - for (i in config) { - prop = config[i]; - if (typeof prop === 'function') { - this[i] = prop; - } else { - this['_' + i] = prop; - } - } - }, - - _months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'), - months : function (m) { - return this._months[m.month()]; - }, - - _monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), - monthsShort : function (m) { - return this._monthsShort[m.month()]; - }, - - monthsParse : function (monthName) { - var i, mom, regex; - - if (!this._monthsParse) { - this._monthsParse = []; - } - - for (i = 0; i < 12; i++) { - // make the regex if we don't have it already - if (!this._monthsParse[i]) { - mom = moment.utc([2000, i]); - regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, ''); - this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i'); - } - // test the regex - if (this._monthsParse[i].test(monthName)) { - return i; - } - } - }, - - _weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), - weekdays : function (m) { - return this._weekdays[m.day()]; - }, - - _weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), - weekdaysShort : function (m) { - return this._weekdaysShort[m.day()]; - }, - - _weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), - weekdaysMin : function (m) { - return this._weekdaysMin[m.day()]; - }, - - weekdaysParse : function (weekdayName) { - var i, mom, regex; - - if (!this._weekdaysParse) { - this._weekdaysParse = []; - } - - for (i = 0; i < 7; i++) { - // make the regex if we don't have it already - if (!this._weekdaysParse[i]) { - mom = moment([2000, 1]).day(i); - regex = '^' + this.weekdays(mom, '') + '|^' + this.weekdaysShort(mom, '') + '|^' + this.weekdaysMin(mom, ''); - this._weekdaysParse[i] = new RegExp(regex.replace('.', ''), 'i'); - } - // test the regex - if (this._weekdaysParse[i].test(weekdayName)) { - return i; - } - } - }, - - _longDateFormat : { - LT : 'h:mm A', - L : 'MM/DD/YYYY', - LL : 'MMMM D, YYYY', - LLL : 'MMMM D, YYYY LT', - LLLL : 'dddd, MMMM D, YYYY LT' - }, - longDateFormat : function (key) { - var output = this._longDateFormat[key]; - if (!output && this._longDateFormat[key.toUpperCase()]) { - output = this._longDateFormat[key.toUpperCase()].replace(/MMMM|MM|DD|dddd/g, function (val) { - return val.slice(1); - }); - this._longDateFormat[key] = output; - } - return output; - }, - - isPM : function (input) { - // IE8 Quirks Mode & IE7 Standards Mode do not allow accessing strings like arrays - // Using charAt should be more compatible. - return ((input + '').toLowerCase().charAt(0) === 'p'); - }, - - _meridiemParse : /[ap]\.?m?\.?/i, - meridiem : function (hours, minutes, isLower) { - if (hours > 11) { - return isLower ? 'pm' : 'PM'; - } else { - return isLower ? 'am' : 'AM'; - } - }, - - _calendar : { - sameDay : '[Today at] LT', - nextDay : '[Tomorrow at] LT', - nextWeek : 'dddd [at] LT', - lastDay : '[Yesterday at] LT', - lastWeek : '[Last] dddd [at] LT', - sameElse : 'L' - }, - calendar : function (key, mom) { - var output = this._calendar[key]; - return typeof output === 'function' ? output.apply(mom) : output; - }, - - _relativeTime : { - future : 'in %s', - past : '%s ago', - s : 'a few seconds', - m : 'a minute', - mm : '%d minutes', - h : 'an hour', - hh : '%d hours', - d : 'a day', - dd : '%d days', - M : 'a month', - MM : '%d months', - y : 'a year', - yy : '%d years' - }, - - relativeTime : function (number, withoutSuffix, string, isFuture) { - var output = this._relativeTime[string]; - return (typeof output === 'function') ? - output(number, withoutSuffix, string, isFuture) : - output.replace(/%d/i, number); - }, - - pastFuture : function (diff, output) { - var format = this._relativeTime[diff > 0 ? 'future' : 'past']; - return typeof format === 'function' ? format(output) : format.replace(/%s/i, output); - }, - - ordinal : function (number) { - return this._ordinal.replace('%d', number); - }, - _ordinal : '%d', - - preparse : function (string) { - return string; - }, - - postformat : function (string) { - return string; - }, - - week : function (mom) { - return weekOfYear(mom, this._week.dow, this._week.doy).week; - }, - - _week : { - dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. - }, - - _invalidDate: 'Invalid date', - invalidDate: function () { - return this._invalidDate; - } - }); - - /************************************ - Formatting - ************************************/ - - - function removeFormattingTokens(input) { - if (input.match(/\[[\s\S]/)) { - return input.replace(/^\[|\]$/g, ''); - } - return input.replace(/\\/g, ''); - } - - function makeFormatFunction(format) { - var array = format.match(formattingTokens), i, length; - - for (i = 0, length = array.length; i < length; i++) { - if (formatTokenFunctions[array[i]]) { - array[i] = formatTokenFunctions[array[i]]; - } else { - array[i] = removeFormattingTokens(array[i]); - } - } - - return function (mom) { - var output = ''; - for (i = 0; i < length; i++) { - output += array[i] instanceof Function ? array[i].call(mom, format) : array[i]; - } - return output; - }; - } - - // format date using native date object - function formatMoment(m, format) { - if (!m.isValid()) { - return m.localeData().invalidDate(); - } - - format = expandFormat(format, m.localeData()); - - if (!formatFunctions[format]) { - formatFunctions[format] = makeFormatFunction(format); - } - - return formatFunctions[format](m); - } - - function expandFormat(format, locale) { - var i = 5; - - function replaceLongDateFormatTokens(input) { - return locale.longDateFormat(input) || input; - } - - localFormattingTokens.lastIndex = 0; - while (i >= 0 && localFormattingTokens.test(format)) { - format = format.replace(localFormattingTokens, replaceLongDateFormatTokens); - localFormattingTokens.lastIndex = 0; - i -= 1; - } - - return format; - } - - - /************************************ - Parsing - ************************************/ - - - // get the regex to find the next token - function getParseRegexForToken(token, config) { - var a, strict = config._strict; - switch (token) { - case 'Q': - return parseTokenOneDigit; - case 'DDDD': - return parseTokenThreeDigits; - case 'YYYY': - case 'GGGG': - case 'gggg': - return strict ? parseTokenFourDigits : parseTokenOneToFourDigits; - case 'Y': - case 'G': - case 'g': - return parseTokenSignedNumber; - case 'YYYYYY': - case 'YYYYY': - case 'GGGGG': - case 'ggggg': - return strict ? parseTokenSixDigits : parseTokenOneToSixDigits; - case 'S': - if (strict) { - return parseTokenOneDigit; - } - /* falls through */ - case 'SS': - if (strict) { - return parseTokenTwoDigits; - } - /* falls through */ - case 'SSS': - if (strict) { - return parseTokenThreeDigits; - } - /* falls through */ - case 'DDD': - return parseTokenOneToThreeDigits; - case 'MMM': - case 'MMMM': - case 'dd': - case 'ddd': - case 'dddd': - return parseTokenWord; - case 'a': - case 'A': - return config._locale._meridiemParse; - case 'X': - return parseTokenTimestampMs; - case 'Z': - case 'ZZ': - return parseTokenTimezone; - case 'T': - return parseTokenT; - case 'SSSS': - return parseTokenDigits; - case 'MM': - case 'DD': - case 'YY': - case 'GG': - case 'gg': - case 'HH': - case 'hh': - case 'mm': - case 'ss': - case 'ww': - case 'WW': - return strict ? parseTokenTwoDigits : parseTokenOneOrTwoDigits; - case 'M': - case 'D': - case 'd': - case 'H': - case 'h': - case 'm': - case 's': - case 'w': - case 'W': - case 'e': - case 'E': - return parseTokenOneOrTwoDigits; - case 'Do': - return parseTokenOrdinal; - default : - a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), 'i')); - return a; - } - } - - function timezoneMinutesFromString(string) { - string = string || ''; - var possibleTzMatches = (string.match(parseTokenTimezone) || []), - tzChunk = possibleTzMatches[possibleTzMatches.length - 1] || [], - parts = (tzChunk + '').match(parseTimezoneChunker) || ['-', 0, 0], - minutes = +(parts[1] * 60) + toInt(parts[2]); - - return parts[0] === '+' ? -minutes : minutes; - } - - // function to convert string input to date - function addTimeToArrayFromToken(token, input, config) { - var a, datePartArray = config._a; - - switch (token) { - // QUARTER - case 'Q': - if (input != null) { - datePartArray[MONTH] = (toInt(input) - 1) * 3; - } - break; - // MONTH - case 'M' : // fall through to MM - case 'MM' : - if (input != null) { - datePartArray[MONTH] = toInt(input) - 1; - } - break; - case 'MMM' : // fall through to MMMM - case 'MMMM' : - a = config._locale.monthsParse(input); - // if we didn't find a month name, mark the date as invalid. - if (a != null) { - datePartArray[MONTH] = a; - } else { - config._pf.invalidMonth = input; - } - break; - // DAY OF MONTH - case 'D' : // fall through to DD - case 'DD' : - if (input != null) { - datePartArray[DATE] = toInt(input); - } - break; - case 'Do' : - if (input != null) { - datePartArray[DATE] = toInt(parseInt(input, 10)); - } - break; - // DAY OF YEAR - case 'DDD' : // fall through to DDDD - case 'DDDD' : - if (input != null) { - config._dayOfYear = toInt(input); - } - - break; - // YEAR - case 'YY' : - datePartArray[YEAR] = moment.parseTwoDigitYear(input); - break; - case 'YYYY' : - case 'YYYYY' : - case 'YYYYYY' : - datePartArray[YEAR] = toInt(input); - break; - // AM / PM - case 'a' : // fall through to A - case 'A' : - config._isPm = config._locale.isPM(input); - break; - // 24 HOUR - case 'H' : // fall through to hh - case 'HH' : // fall through to hh - case 'h' : // fall through to hh - case 'hh' : - datePartArray[HOUR] = toInt(input); - break; - // MINUTE - case 'm' : // fall through to mm - case 'mm' : - datePartArray[MINUTE] = toInt(input); - break; - // SECOND - case 's' : // fall through to ss - case 'ss' : - datePartArray[SECOND] = toInt(input); - break; - // MILLISECOND - case 'S' : - case 'SS' : - case 'SSS' : - case 'SSSS' : - datePartArray[MILLISECOND] = toInt(('0.' + input) * 1000); - break; - // UNIX TIMESTAMP WITH MS - case 'X': - config._d = new Date(parseFloat(input) * 1000); - break; - // TIMEZONE - case 'Z' : // fall through to ZZ - case 'ZZ' : - config._useUTC = true; - config._tzm = timezoneMinutesFromString(input); - break; - // WEEKDAY - human - case 'dd': - case 'ddd': - case 'dddd': - a = config._locale.weekdaysParse(input); - // if we didn't get a weekday name, mark the date as invalid - if (a != null) { - config._w = config._w || {}; - config._w['d'] = a; - } else { - config._pf.invalidWeekday = input; - } - break; - // WEEK, WEEK DAY - numeric - case 'w': - case 'ww': - case 'W': - case 'WW': - case 'd': - case 'e': - case 'E': - token = token.substr(0, 1); - /* falls through */ - case 'gggg': - case 'GGGG': - case 'GGGGG': - token = token.substr(0, 2); - if (input) { - config._w = config._w || {}; - config._w[token] = toInt(input); - } - break; - case 'gg': - case 'GG': - config._w = config._w || {}; - config._w[token] = moment.parseTwoDigitYear(input); - } - } - - function dayOfYearFromWeekInfo(config) { - var w, weekYear, week, weekday, dow, doy, temp; - - w = config._w; - if (w.GG != null || w.W != null || w.E != null) { - dow = 1; - doy = 4; - - // TODO: We need to take the current isoWeekYear, but that depends on - // how we interpret now (local, utc, fixed offset). So create - // a now version of current config (take local/utc/offset flags, and - // create now). - weekYear = dfl(w.GG, config._a[YEAR], weekOfYear(moment(), 1, 4).year); - week = dfl(w.W, 1); - weekday = dfl(w.E, 1); - } else { - dow = config._locale._week.dow; - doy = config._locale._week.doy; - - weekYear = dfl(w.gg, config._a[YEAR], weekOfYear(moment(), dow, doy).year); - week = dfl(w.w, 1); - - if (w.d != null) { - // weekday -- low day numbers are considered next week - weekday = w.d; - if (weekday < dow) { - ++week; - } - } else if (w.e != null) { - // local weekday -- counting starts from begining of week - weekday = w.e + dow; - } else { - // default to begining of week - weekday = dow; - } - } - temp = dayOfYearFromWeeks(weekYear, week, weekday, doy, dow); - - config._a[YEAR] = temp.year; - config._dayOfYear = temp.dayOfYear; - } - - // convert an array to a date. - // the array should mirror the parameters below - // note: all values past the year are optional and will default to the lowest possible value. - // [year, month, day , hour, minute, second, millisecond] - function dateFromConfig(config) { - var i, date, input = [], currentDate, yearToUse; - - if (config._d) { - return; - } - - currentDate = currentDateArray(config); - - //compute day of the year from weeks and weekdays - if (config._w && config._a[DATE] == null && config._a[MONTH] == null) { - dayOfYearFromWeekInfo(config); - } - - //if the day of the year is set, figure out what it is - if (config._dayOfYear) { - yearToUse = dfl(config._a[YEAR], currentDate[YEAR]); - - if (config._dayOfYear > daysInYear(yearToUse)) { - config._pf._overflowDayOfYear = true; - } - - date = makeUTCDate(yearToUse, 0, config._dayOfYear); - config._a[MONTH] = date.getUTCMonth(); - config._a[DATE] = date.getUTCDate(); - } - - // Default to current date. - // * if no year, month, day of month are given, default to today - // * if day of month is given, default month and year - // * if month is given, default only year - // * if year is given, don't default anything - for (i = 0; i < 3 && config._a[i] == null; ++i) { - config._a[i] = input[i] = currentDate[i]; - } - - // Zero out whatever was not defaulted, including time - for (; i < 7; i++) { - config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i]; - } - - config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input); - // Apply timezone offset from input. The actual zone can be changed - // with parseZone. - if (config._tzm != null) { - config._d.setUTCMinutes(config._d.getUTCMinutes() + config._tzm); - } - } - - function dateFromObject(config) { - var normalizedInput; - - if (config._d) { - return; - } - - normalizedInput = normalizeObjectUnits(config._i); - config._a = [ - normalizedInput.year, - normalizedInput.month, - normalizedInput.day, - normalizedInput.hour, - normalizedInput.minute, - normalizedInput.second, - normalizedInput.millisecond - ]; - - dateFromConfig(config); - } - - function currentDateArray(config) { - var now = new Date(); - if (config._useUTC) { - return [ - now.getUTCFullYear(), - now.getUTCMonth(), - now.getUTCDate() - ]; - } else { - return [now.getFullYear(), now.getMonth(), now.getDate()]; - } - } - - // date from string and format string - function makeDateFromStringAndFormat(config) { - if (config._f === moment.ISO_8601) { - parseISO(config); - return; - } - - config._a = []; - config._pf.empty = true; - - // This array is used to make a Date, either with `new Date` or `Date.UTC` - var string = '' + config._i, - i, parsedInput, tokens, token, skipped, - stringLength = string.length, - totalParsedInputLength = 0; - - tokens = expandFormat(config._f, config._locale).match(formattingTokens) || []; - - for (i = 0; i < tokens.length; i++) { - token = tokens[i]; - parsedInput = (string.match(getParseRegexForToken(token, config)) || [])[0]; - if (parsedInput) { - skipped = string.substr(0, string.indexOf(parsedInput)); - if (skipped.length > 0) { - config._pf.unusedInput.push(skipped); - } - string = string.slice(string.indexOf(parsedInput) + parsedInput.length); - totalParsedInputLength += parsedInput.length; - } - // don't parse if it's not a known token - if (formatTokenFunctions[token]) { - if (parsedInput) { - config._pf.empty = false; - } - else { - config._pf.unusedTokens.push(token); - } - addTimeToArrayFromToken(token, parsedInput, config); - } - else if (config._strict && !parsedInput) { - config._pf.unusedTokens.push(token); - } - } - - // add remaining unparsed input length to the string - config._pf.charsLeftOver = stringLength - totalParsedInputLength; - if (string.length > 0) { - config._pf.unusedInput.push(string); - } - - // handle am pm - if (config._isPm && config._a[HOUR] < 12) { - config._a[HOUR] += 12; - } - // if is 12 am, change hours to 0 - if (config._isPm === false && config._a[HOUR] === 12) { - config._a[HOUR] = 0; - } - - dateFromConfig(config); - checkOverflow(config); - } - - function unescapeFormat(s) { - return s.replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g, function (matched, p1, p2, p3, p4) { - return p1 || p2 || p3 || p4; - }); - } - - // Code from http://stackoverflow.com/questions/3561493/is-there-a-regexp-escape-function-in-javascript - function regexpEscape(s) { - return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); - } - - // date from string and array of format strings - function makeDateFromStringAndArray(config) { - var tempConfig, - bestMoment, - - scoreToBeat, - i, - currentScore; - - if (config._f.length === 0) { - config._pf.invalidFormat = true; - config._d = new Date(NaN); - return; - } - - for (i = 0; i < config._f.length; i++) { - currentScore = 0; - tempConfig = copyConfig({}, config); - if (config._useUTC != null) { - tempConfig._useUTC = config._useUTC; - } - tempConfig._pf = defaultParsingFlags(); - tempConfig._f = config._f[i]; - makeDateFromStringAndFormat(tempConfig); - - if (!isValid(tempConfig)) { - continue; - } - - // if there is any input that was not parsed add a penalty for that format - currentScore += tempConfig._pf.charsLeftOver; - - //or tokens - currentScore += tempConfig._pf.unusedTokens.length * 10; - - tempConfig._pf.score = currentScore; - - if (scoreToBeat == null || currentScore < scoreToBeat) { - scoreToBeat = currentScore; - bestMoment = tempConfig; - } - } - - extend(config, bestMoment || tempConfig); - } - - // date from iso format - function parseISO(config) { - var i, l, - string = config._i, - match = isoRegex.exec(string); - - if (match) { - config._pf.iso = true; - for (i = 0, l = isoDates.length; i < l; i++) { - if (isoDates[i][1].exec(string)) { - // match[5] should be 'T' or undefined - config._f = isoDates[i][0] + (match[6] || ' '); - break; - } - } - for (i = 0, l = isoTimes.length; i < l; i++) { - if (isoTimes[i][1].exec(string)) { - config._f += isoTimes[i][0]; - break; - } - } - if (string.match(parseTokenTimezone)) { - config._f += 'Z'; - } - makeDateFromStringAndFormat(config); - } else { - config._isValid = false; - } - } - - // date from iso format or fallback - function makeDateFromString(config) { - parseISO(config); - if (config._isValid === false) { - delete config._isValid; - moment.createFromInputFallback(config); - } - } - - function map(arr, fn) { - var res = [], i; - for (i = 0; i < arr.length; ++i) { - res.push(fn(arr[i], i)); - } - return res; - } - - function makeDateFromInput(config) { - var input = config._i, matched; - if (input === undefined) { - config._d = new Date(); - } else if (isDate(input)) { - config._d = new Date(+input); - } else if ((matched = aspNetJsonRegex.exec(input)) !== null) { - config._d = new Date(+matched[1]); - } else if (typeof input === 'string') { - makeDateFromString(config); - } else if (isArray(input)) { - config._a = map(input.slice(0), function (obj) { - return parseInt(obj, 10); - }); - dateFromConfig(config); - } else if (typeof(input) === 'object') { - dateFromObject(config); - } else if (typeof(input) === 'number') { - // from milliseconds - config._d = new Date(input); - } else { - moment.createFromInputFallback(config); - } - } - - function makeDate(y, m, d, h, M, s, ms) { - //can't just apply() to create a date: - //http://stackoverflow.com/questions/181348/instantiating-a-javascript-object-by-calling-prototype-constructor-apply - var date = new Date(y, m, d, h, M, s, ms); - - //the date constructor doesn't accept years < 1970 - if (y < 1970) { - date.setFullYear(y); - } - return date; - } - - function makeUTCDate(y) { - var date = new Date(Date.UTC.apply(null, arguments)); - if (y < 1970) { - date.setUTCFullYear(y); - } - return date; - } - - function parseWeekday(input, locale) { - if (typeof input === 'string') { - if (!isNaN(input)) { - input = parseInt(input, 10); - } - else { - input = locale.weekdaysParse(input); - if (typeof input !== 'number') { - return null; - } - } - } - return input; - } - - /************************************ - Relative Time - ************************************/ - - - // helper function for moment.fn.from, moment.fn.fromNow, and moment.duration.fn.humanize - function substituteTimeAgo(string, number, withoutSuffix, isFuture, locale) { - return locale.relativeTime(number || 1, !!withoutSuffix, string, isFuture); - } - - function relativeTime(posNegDuration, withoutSuffix, locale) { - var duration = moment.duration(posNegDuration).abs(), - seconds = round(duration.as('s')), - minutes = round(duration.as('m')), - hours = round(duration.as('h')), - days = round(duration.as('d')), - months = round(duration.as('M')), - years = round(duration.as('y')), - - args = seconds < relativeTimeThresholds.s && ['s', seconds] || - minutes === 1 && ['m'] || - minutes < relativeTimeThresholds.m && ['mm', minutes] || - hours === 1 && ['h'] || - hours < relativeTimeThresholds.h && ['hh', hours] || - days === 1 && ['d'] || - days < relativeTimeThresholds.d && ['dd', days] || - months === 1 && ['M'] || - months < relativeTimeThresholds.M && ['MM', months] || - years === 1 && ['y'] || ['yy', years]; - - args[2] = withoutSuffix; - args[3] = +posNegDuration > 0; - args[4] = locale; - return substituteTimeAgo.apply({}, args); - } - - - /************************************ - Week of Year - ************************************/ - - - // firstDayOfWeek 0 = sun, 6 = sat - // the day of the week that starts the week - // (usually sunday or monday) - // firstDayOfWeekOfYear 0 = sun, 6 = sat - // the first week is the week that contains the first - // of this day of the week - // (eg. ISO weeks use thursday (4)) - function weekOfYear(mom, firstDayOfWeek, firstDayOfWeekOfYear) { - var end = firstDayOfWeekOfYear - firstDayOfWeek, - daysToDayOfWeek = firstDayOfWeekOfYear - mom.day(), - adjustedMoment; - - - if (daysToDayOfWeek > end) { - daysToDayOfWeek -= 7; - } - - if (daysToDayOfWeek < end - 7) { - daysToDayOfWeek += 7; - } - - adjustedMoment = moment(mom).add(daysToDayOfWeek, 'd'); - return { - week: Math.ceil(adjustedMoment.dayOfYear() / 7), - year: adjustedMoment.year() - }; - } - - //http://en.wikipedia.org/wiki/ISO_week_date#Calculating_a_date_given_the_year.2C_week_number_and_weekday - function dayOfYearFromWeeks(year, week, weekday, firstDayOfWeekOfYear, firstDayOfWeek) { - var d = makeUTCDate(year, 0, 1).getUTCDay(), daysToAdd, dayOfYear; - - d = d === 0 ? 7 : d; - weekday = weekday != null ? weekday : firstDayOfWeek; - daysToAdd = firstDayOfWeek - d + (d > firstDayOfWeekOfYear ? 7 : 0) - (d < firstDayOfWeek ? 7 : 0); - dayOfYear = 7 * (week - 1) + (weekday - firstDayOfWeek) + daysToAdd + 1; - - return { - year: dayOfYear > 0 ? year : year - 1, - dayOfYear: dayOfYear > 0 ? dayOfYear : daysInYear(year - 1) + dayOfYear - }; - } - - /************************************ - Top Level Functions - ************************************/ - - function makeMoment(config) { - var input = config._i, - format = config._f; - - config._locale = config._locale || moment.localeData(config._l); - - if (input === null || (format === undefined && input === '')) { - return moment.invalid({nullInput: true}); - } - - if (typeof input === 'string') { - config._i = input = config._locale.preparse(input); - } - - if (moment.isMoment(input)) { - return new Moment(input, true); - } else if (format) { - if (isArray(format)) { - makeDateFromStringAndArray(config); - } else { - makeDateFromStringAndFormat(config); - } - } else { - makeDateFromInput(config); - } - - return new Moment(config); - } - - moment = function (input, format, locale, strict) { - var c; - - if (typeof(locale) === 'boolean') { - strict = locale; - locale = undefined; - } - // object construction must be done this way. - // https://github.com/moment/moment/issues/1423 - c = {}; - c._isAMomentObject = true; - c._i = input; - c._f = format; - c._l = locale; - c._strict = strict; - c._isUTC = false; - c._pf = defaultParsingFlags(); - - return makeMoment(c); - }; - - moment.suppressDeprecationWarnings = false; - - moment.createFromInputFallback = deprecate( - 'moment construction falls back to js Date. This is ' + - 'discouraged and will be removed in upcoming major ' + - 'release. Please refer to ' + - 'https://github.com/moment/moment/issues/1407 for more info.', - function (config) { - config._d = new Date(config._i); - } - ); - - // Pick a moment m from moments so that m[fn](other) is true for all - // other. This relies on the function fn to be transitive. - // - // moments should either be an array of moment objects or an array, whose - // first element is an array of moment objects. - function pickBy(fn, moments) { - var res, i; - if (moments.length === 1 && isArray(moments[0])) { - moments = moments[0]; - } - if (!moments.length) { - return moment(); - } - res = moments[0]; - for (i = 1; i < moments.length; ++i) { - if (moments[i][fn](res)) { - res = moments[i]; - } - } - return res; - } - - moment.min = function () { - var args = [].slice.call(arguments, 0); - - return pickBy('isBefore', args); - }; - - moment.max = function () { - var args = [].slice.call(arguments, 0); - - return pickBy('isAfter', args); - }; - - // creating with utc - moment.utc = function (input, format, locale, strict) { - var c; - - if (typeof(locale) === 'boolean') { - strict = locale; - locale = undefined; - } - // object construction must be done this way. - // https://github.com/moment/moment/issues/1423 - c = {}; - c._isAMomentObject = true; - c._useUTC = true; - c._isUTC = true; - c._l = locale; - c._i = input; - c._f = format; - c._strict = strict; - c._pf = defaultParsingFlags(); - - return makeMoment(c).utc(); - }; - - // creating with unix timestamp (in seconds) - moment.unix = function (input) { - return moment(input * 1000); - }; - - // duration - moment.duration = function (input, key) { - var duration = input, - // matching against regexp is expensive, do it on demand - match = null, - sign, - ret, - parseIso, - diffRes; - - if (moment.isDuration(input)) { - duration = { - ms: input._milliseconds, - d: input._days, - M: input._months - }; - } else if (typeof input === 'number') { - duration = {}; - if (key) { - duration[key] = input; - } else { - duration.milliseconds = input; - } - } else if (!!(match = aspNetTimeSpanJsonRegex.exec(input))) { - sign = (match[1] === '-') ? -1 : 1; - duration = { - y: 0, - d: toInt(match[DATE]) * sign, - h: toInt(match[HOUR]) * sign, - m: toInt(match[MINUTE]) * sign, - s: toInt(match[SECOND]) * sign, - ms: toInt(match[MILLISECOND]) * sign - }; - } else if (!!(match = isoDurationRegex.exec(input))) { - sign = (match[1] === '-') ? -1 : 1; - parseIso = function (inp) { - // We'd normally use ~~inp for this, but unfortunately it also - // converts floats to ints. - // inp may be undefined, so careful calling replace on it. - var res = inp && parseFloat(inp.replace(',', '.')); - // apply sign while we're at it - return (isNaN(res) ? 0 : res) * sign; - }; - duration = { - y: parseIso(match[2]), - M: parseIso(match[3]), - d: parseIso(match[4]), - h: parseIso(match[5]), - m: parseIso(match[6]), - s: parseIso(match[7]), - w: parseIso(match[8]) - }; - } else if (typeof duration === 'object' && - ('from' in duration || 'to' in duration)) { - diffRes = momentsDifference(moment(duration.from), moment(duration.to)); - - duration = {}; - duration.ms = diffRes.milliseconds; - duration.M = diffRes.months; - } - - ret = new Duration(duration); - - if (moment.isDuration(input) && hasOwnProp(input, '_locale')) { - ret._locale = input._locale; - } - - return ret; - }; - - // version number - moment.version = VERSION; - - // default format - moment.defaultFormat = isoFormat; - - // constant that refers to the ISO standard - moment.ISO_8601 = function () {}; - - // Plugins that add properties should also add the key here (null value), - // so we can properly clone ourselves. - moment.momentProperties = momentProperties; - - // This function will be called whenever a moment is mutated. - // It is intended to keep the offset in sync with the timezone. - moment.updateOffset = function () {}; - - // This function allows you to set a threshold for relative time strings - moment.relativeTimeThreshold = function (threshold, limit) { - if (relativeTimeThresholds[threshold] === undefined) { - return false; - } - if (limit === undefined) { - return relativeTimeThresholds[threshold]; - } - relativeTimeThresholds[threshold] = limit; - return true; - }; - - moment.lang = deprecate( - 'moment.lang is deprecated. Use moment.locale instead.', - function (key, value) { - return moment.locale(key, value); - } - ); - - // This function will load locale and then set the global locale. If - // no arguments are passed in, it will simply return the current global - // locale key. - moment.locale = function (key, values) { - var data; - if (key) { - if (typeof(values) !== 'undefined') { - data = moment.defineLocale(key, values); - } - else { - data = moment.localeData(key); - } - - if (data) { - moment.duration._locale = moment._locale = data; - } - } - - return moment._locale._abbr; - }; - - moment.defineLocale = function (name, values) { - if (values !== null) { - values.abbr = name; - if (!locales[name]) { - locales[name] = new Locale(); - } - locales[name].set(values); - - // backwards compat for now: also set the locale - moment.locale(name); - - return locales[name]; - } else { - // useful for testing - delete locales[name]; - return null; - } - }; - - moment.langData = deprecate( - 'moment.langData is deprecated. Use moment.localeData instead.', - function (key) { - return moment.localeData(key); - } - ); - - // returns locale data - moment.localeData = function (key) { - var locale; - - if (key && key._locale && key._locale._abbr) { - key = key._locale._abbr; - } - - if (!key) { - return moment._locale; - } - - if (!isArray(key)) { - //short-circuit everything else - locale = loadLocale(key); - if (locale) { - return locale; - } - key = [key]; - } - - return chooseLocale(key); - }; - - // compare moment object - moment.isMoment = function (obj) { - return obj instanceof Moment || - (obj != null && hasOwnProp(obj, '_isAMomentObject')); - }; - - // for typechecking Duration objects - moment.isDuration = function (obj) { - return obj instanceof Duration; - }; - - for (i = lists.length - 1; i >= 0; --i) { - makeList(lists[i]); - } - - moment.normalizeUnits = function (units) { - return normalizeUnits(units); - }; - - moment.invalid = function (flags) { - var m = moment.utc(NaN); - if (flags != null) { - extend(m._pf, flags); - } - else { - m._pf.userInvalidated = true; - } - - return m; - }; - - moment.parseZone = function () { - return moment.apply(null, arguments).parseZone(); - }; - - moment.parseTwoDigitYear = function (input) { - return toInt(input) + (toInt(input) > 68 ? 1900 : 2000); - }; - - /************************************ - Moment Prototype - ************************************/ - - - extend(moment.fn = Moment.prototype, { - - clone : function () { - return moment(this); - }, - - valueOf : function () { - return +this._d + ((this._offset || 0) * 60000); - }, - - unix : function () { - return Math.floor(+this / 1000); - }, - - toString : function () { - return this.clone().locale('en').format('ddd MMM DD YYYY HH:mm:ss [GMT]ZZ'); - }, - - toDate : function () { - return this._offset ? new Date(+this) : this._d; - }, - - toISOString : function () { - var m = moment(this).utc(); - if (0 < m.year() && m.year() <= 9999) { - return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); - } else { - return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]'); - } - }, - - toArray : function () { - var m = this; - return [ - m.year(), - m.month(), - m.date(), - m.hours(), - m.minutes(), - m.seconds(), - m.milliseconds() - ]; - }, - - isValid : function () { - return isValid(this); - }, - - isDSTShifted : function () { - if (this._a) { - return this.isValid() && compareArrays(this._a, (this._isUTC ? moment.utc(this._a) : moment(this._a)).toArray()) > 0; - } - - return false; - }, - - parsingFlags : function () { - return extend({}, this._pf); - }, - - invalidAt: function () { - return this._pf.overflow; - }, - - utc : function (keepLocalTime) { - return this.zone(0, keepLocalTime); - }, - - local : function (keepLocalTime) { - if (this._isUTC) { - this.zone(0, keepLocalTime); - this._isUTC = false; - - if (keepLocalTime) { - this.add(this._dateTzOffset(), 'm'); - } - } - return this; - }, - - format : function (inputString) { - var output = formatMoment(this, inputString || moment.defaultFormat); - return this.localeData().postformat(output); - }, - - add : createAdder(1, 'add'), - - subtract : createAdder(-1, 'subtract'), - - diff : function (input, units, asFloat) { - var that = makeAs(input, this), - zoneDiff = (this.zone() - that.zone()) * 6e4, - diff, output, daysAdjust; - - units = normalizeUnits(units); - - if (units === 'year' || units === 'month') { - // average number of days in the months in the given dates - diff = (this.daysInMonth() + that.daysInMonth()) * 432e5; // 24 * 60 * 60 * 1000 / 2 - // difference in months - output = ((this.year() - that.year()) * 12) + (this.month() - that.month()); - // adjust by taking difference in days, average number of days - // and dst in the given months. - daysAdjust = (this - moment(this).startOf('month')) - - (that - moment(that).startOf('month')); - // same as above but with zones, to negate all dst - daysAdjust -= ((this.zone() - moment(this).startOf('month').zone()) - - (that.zone() - moment(that).startOf('month').zone())) * 6e4; - output += daysAdjust / diff; - if (units === 'year') { - output = output / 12; - } - } else { - diff = (this - that); - output = units === 'second' ? diff / 1e3 : // 1000 - units === 'minute' ? diff / 6e4 : // 1000 * 60 - units === 'hour' ? diff / 36e5 : // 1000 * 60 * 60 - units === 'day' ? (diff - zoneDiff) / 864e5 : // 1000 * 60 * 60 * 24, negate dst - units === 'week' ? (diff - zoneDiff) / 6048e5 : // 1000 * 60 * 60 * 24 * 7, negate dst - diff; - } - return asFloat ? output : absRound(output); - }, - - from : function (time, withoutSuffix) { - return moment.duration({to: this, from: time}).locale(this.locale()).humanize(!withoutSuffix); - }, - - fromNow : function (withoutSuffix) { - return this.from(moment(), withoutSuffix); - }, - - calendar : function (time) { - // We want to compare the start of today, vs this. - // Getting start-of-today depends on whether we're zone'd or not. - var now = time || moment(), - sod = makeAs(now, this).startOf('day'), - diff = this.diff(sod, 'days', true), - format = diff < -6 ? 'sameElse' : - diff < -1 ? 'lastWeek' : - diff < 0 ? 'lastDay' : - diff < 1 ? 'sameDay' : - diff < 2 ? 'nextDay' : - diff < 7 ? 'nextWeek' : 'sameElse'; - return this.format(this.localeData().calendar(format, this)); - }, - - isLeapYear : function () { - return isLeapYear(this.year()); - }, - - isDST : function () { - return (this.zone() < this.clone().month(0).zone() || - this.zone() < this.clone().month(5).zone()); - }, - - day : function (input) { - var day = this._isUTC ? this._d.getUTCDay() : this._d.getDay(); - if (input != null) { - input = parseWeekday(input, this.localeData()); - return this.add(input - day, 'd'); - } else { - return day; - } - }, - - month : makeAccessor('Month', true), - - startOf : function (units) { - units = normalizeUnits(units); - // the following switch intentionally omits break keywords - // to utilize falling through the cases. - switch (units) { - case 'year': - this.month(0); - /* falls through */ - case 'quarter': - case 'month': - this.date(1); - /* falls through */ - case 'week': - case 'isoWeek': - case 'day': - this.hours(0); - /* falls through */ - case 'hour': - this.minutes(0); - /* falls through */ - case 'minute': - this.seconds(0); - /* falls through */ - case 'second': - this.milliseconds(0); - /* falls through */ - } - - // weeks are a special case - if (units === 'week') { - this.weekday(0); - } else if (units === 'isoWeek') { - this.isoWeekday(1); - } - - // quarters are also special - if (units === 'quarter') { - this.month(Math.floor(this.month() / 3) * 3); - } - - return this; - }, - - endOf: function (units) { - units = normalizeUnits(units); - return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms'); - }, - - isAfter: function (input, units) { - units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); - if (units === 'millisecond') { - input = moment.isMoment(input) ? input : moment(input); - return +this > +input; - } else { - return +this.clone().startOf(units) > +moment(input).startOf(units); - } - }, - - isBefore: function (input, units) { - units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond'); - if (units === 'millisecond') { - input = moment.isMoment(input) ? input : moment(input); - return +this < +input; - } else { - return +this.clone().startOf(units) < +moment(input).startOf(units); - } - }, - - isSame: function (input, units) { - units = normalizeUnits(units || 'millisecond'); - if (units === 'millisecond') { - input = moment.isMoment(input) ? input : moment(input); - return +this === +input; - } else { - return +this.clone().startOf(units) === +makeAs(input, this).startOf(units); - } - }, - - min: deprecate( - 'moment().min is deprecated, use moment.min instead. https://github.com/moment/moment/issues/1548', - function (other) { - other = moment.apply(null, arguments); - return other < this ? this : other; - } - ), - - max: deprecate( - 'moment().max is deprecated, use moment.max instead. https://github.com/moment/moment/issues/1548', - function (other) { - other = moment.apply(null, arguments); - return other > this ? this : other; - } - ), - - // keepLocalTime = true means only change the timezone, without - // affecting the local hour. So 5:31:26 +0300 --[zone(2, true)]--> - // 5:31:26 +0200 It is possible that 5:31:26 doesn't exist int zone - // +0200, so we adjust the time as needed, to be valid. - // - // Keeping the time actually adds/subtracts (one hour) - // from the actual represented time. That is why we call updateOffset - // a second time. In case it wants us to change the offset again - // _changeInProgress == true case, then we have to adjust, because - // there is no such time in the given timezone. - zone : function (input, keepLocalTime) { - var offset = this._offset || 0, - localAdjust; - if (input != null) { - if (typeof input === 'string') { - input = timezoneMinutesFromString(input); - } - if (Math.abs(input) < 16) { - input = input * 60; - } - if (!this._isUTC && keepLocalTime) { - localAdjust = this._dateTzOffset(); - } - this._offset = input; - this._isUTC = true; - if (localAdjust != null) { - this.subtract(localAdjust, 'm'); - } - if (offset !== input) { - if (!keepLocalTime || this._changeInProgress) { - addOrSubtractDurationFromMoment(this, - moment.duration(offset - input, 'm'), 1, false); - } else if (!this._changeInProgress) { - this._changeInProgress = true; - moment.updateOffset(this, true); - this._changeInProgress = null; - } - } - } else { - return this._isUTC ? offset : this._dateTzOffset(); - } - return this; - }, - - zoneAbbr : function () { - return this._isUTC ? 'UTC' : ''; - }, - - zoneName : function () { - return this._isUTC ? 'Coordinated Universal Time' : ''; - }, - - parseZone : function () { - if (this._tzm) { - this.zone(this._tzm); - } else if (typeof this._i === 'string') { - this.zone(this._i); - } - return this; - }, - - hasAlignedHourOffset : function (input) { - if (!input) { - input = 0; - } - else { - input = moment(input).zone(); - } - - return (this.zone() - input) % 60 === 0; - }, - - daysInMonth : function () { - return daysInMonth(this.year(), this.month()); - }, - - dayOfYear : function (input) { - var dayOfYear = round((moment(this).startOf('day') - moment(this).startOf('year')) / 864e5) + 1; - return input == null ? dayOfYear : this.add((input - dayOfYear), 'd'); - }, - - quarter : function (input) { - return input == null ? Math.ceil((this.month() + 1) / 3) : this.month((input - 1) * 3 + this.month() % 3); - }, - - weekYear : function (input) { - var year = weekOfYear(this, this.localeData()._week.dow, this.localeData()._week.doy).year; - return input == null ? year : this.add((input - year), 'y'); - }, - - isoWeekYear : function (input) { - var year = weekOfYear(this, 1, 4).year; - return input == null ? year : this.add((input - year), 'y'); - }, - - week : function (input) { - var week = this.localeData().week(this); - return input == null ? week : this.add((input - week) * 7, 'd'); - }, - - isoWeek : function (input) { - var week = weekOfYear(this, 1, 4).week; - return input == null ? week : this.add((input - week) * 7, 'd'); - }, - - weekday : function (input) { - var weekday = (this.day() + 7 - this.localeData()._week.dow) % 7; - return input == null ? weekday : this.add(input - weekday, 'd'); - }, - - isoWeekday : function (input) { - // behaves the same as moment#day except - // as a getter, returns 7 instead of 0 (1-7 range instead of 0-6) - // as a setter, sunday should belong to the previous week. - return input == null ? this.day() || 7 : this.day(this.day() % 7 ? input : input - 7); - }, - - isoWeeksInYear : function () { - return weeksInYear(this.year(), 1, 4); - }, - - weeksInYear : function () { - var weekInfo = this.localeData()._week; - return weeksInYear(this.year(), weekInfo.dow, weekInfo.doy); - }, - - get : function (units) { - units = normalizeUnits(units); - return this[units](); - }, - - set : function (units, value) { - units = normalizeUnits(units); - if (typeof this[units] === 'function') { - this[units](value); - } - return this; - }, - - // If passed a locale key, it will set the locale for this - // instance. Otherwise, it will return the locale configuration - // variables for this instance. - locale : function (key) { - var newLocaleData; - - if (key === undefined) { - return this._locale._abbr; - } else { - newLocaleData = moment.localeData(key); - if (newLocaleData != null) { - this._locale = newLocaleData; - } - return this; - } - }, - - lang : deprecate( - 'moment().lang() is deprecated. Use moment().localeData() instead.', - function (key) { - if (key === undefined) { - return this.localeData(); - } else { - return this.locale(key); - } - } - ), - - localeData : function () { - return this._locale; - }, - - _dateTzOffset : function () { - // On Firefox.24 Date#getTimezoneOffset returns a floating point. - // https://github.com/moment/moment/pull/1871 - return Math.round(this._d.getTimezoneOffset() / 15) * 15; - } - }); - - function rawMonthSetter(mom, value) { - var dayOfMonth; - - // TODO: Move this out of here! - if (typeof value === 'string') { - value = mom.localeData().monthsParse(value); - // TODO: Another silent failure? - if (typeof value !== 'number') { - return mom; - } - } - - dayOfMonth = Math.min(mom.date(), - daysInMonth(mom.year(), value)); - mom._d['set' + (mom._isUTC ? 'UTC' : '') + 'Month'](value, dayOfMonth); - return mom; - } - - function rawGetter(mom, unit) { - return mom._d['get' + (mom._isUTC ? 'UTC' : '') + unit](); - } - - function rawSetter(mom, unit, value) { - if (unit === 'Month') { - return rawMonthSetter(mom, value); - } else { - return mom._d['set' + (mom._isUTC ? 'UTC' : '') + unit](value); - } - } - - function makeAccessor(unit, keepTime) { - return function (value) { - if (value != null) { - rawSetter(this, unit, value); - moment.updateOffset(this, keepTime); - return this; - } else { - return rawGetter(this, unit); - } - }; - } - - moment.fn.millisecond = moment.fn.milliseconds = makeAccessor('Milliseconds', false); - moment.fn.second = moment.fn.seconds = makeAccessor('Seconds', false); - moment.fn.minute = moment.fn.minutes = makeAccessor('Minutes', false); - // Setting the hour should keep the time, because the user explicitly - // specified which hour he wants. So trying to maintain the same hour (in - // a new timezone) makes sense. Adding/subtracting hours does not follow - // this rule. - moment.fn.hour = moment.fn.hours = makeAccessor('Hours', true); - // moment.fn.month is defined separately - moment.fn.date = makeAccessor('Date', true); - moment.fn.dates = deprecate('dates accessor is deprecated. Use date instead.', makeAccessor('Date', true)); - moment.fn.year = makeAccessor('FullYear', true); - moment.fn.years = deprecate('years accessor is deprecated. Use year instead.', makeAccessor('FullYear', true)); - - // add plural methods - moment.fn.days = moment.fn.day; - moment.fn.months = moment.fn.month; - moment.fn.weeks = moment.fn.week; - moment.fn.isoWeeks = moment.fn.isoWeek; - moment.fn.quarters = moment.fn.quarter; - - // add aliased format methods - moment.fn.toJSON = moment.fn.toISOString; - - /************************************ - Duration Prototype - ************************************/ - - - function daysToYears (days) { - // 400 years have 146097 days (taking into account leap year rules) - return days * 400 / 146097; - } - - function yearsToDays (years) { - // years * 365 + absRound(years / 4) - - // absRound(years / 100) + absRound(years / 400); - return years * 146097 / 400; - } - - extend(moment.duration.fn = Duration.prototype, { - - _bubble : function () { - var milliseconds = this._milliseconds, - days = this._days, - months = this._months, - data = this._data, - seconds, minutes, hours, years = 0; - - // The following code bubbles up values, see the tests for - // examples of what that means. - data.milliseconds = milliseconds % 1000; - - seconds = absRound(milliseconds / 1000); - data.seconds = seconds % 60; - - minutes = absRound(seconds / 60); - data.minutes = minutes % 60; - - hours = absRound(minutes / 60); - data.hours = hours % 24; - - days += absRound(hours / 24); - - // Accurately convert days to years, assume start from year 0. - years = absRound(daysToYears(days)); - days -= absRound(yearsToDays(years)); - - // 30 days to a month - // TODO (iskren): Use anchor date (like 1st Jan) to compute this. - months += absRound(days / 30); - days %= 30; - - // 12 months -> 1 year - years += absRound(months / 12); - months %= 12; - - data.days = days; - data.months = months; - data.years = years; - }, - - abs : function () { - this._milliseconds = Math.abs(this._milliseconds); - this._days = Math.abs(this._days); - this._months = Math.abs(this._months); - - this._data.milliseconds = Math.abs(this._data.milliseconds); - this._data.seconds = Math.abs(this._data.seconds); - this._data.minutes = Math.abs(this._data.minutes); - this._data.hours = Math.abs(this._data.hours); - this._data.months = Math.abs(this._data.months); - this._data.years = Math.abs(this._data.years); - - return this; - }, - - weeks : function () { - return absRound(this.days() / 7); - }, - - valueOf : function () { - return this._milliseconds + - this._days * 864e5 + - (this._months % 12) * 2592e6 + - toInt(this._months / 12) * 31536e6; - }, - - humanize : function (withSuffix) { - var output = relativeTime(this, !withSuffix, this.localeData()); - - if (withSuffix) { - output = this.localeData().pastFuture(+this, output); - } - - return this.localeData().postformat(output); - }, - - add : function (input, val) { - // supports only 2.0-style add(1, 's') or add(moment) - var dur = moment.duration(input, val); - - this._milliseconds += dur._milliseconds; - this._days += dur._days; - this._months += dur._months; - - this._bubble(); - - return this; - }, - - subtract : function (input, val) { - var dur = moment.duration(input, val); - - this._milliseconds -= dur._milliseconds; - this._days -= dur._days; - this._months -= dur._months; - - this._bubble(); - - return this; - }, - - get : function (units) { - units = normalizeUnits(units); - return this[units.toLowerCase() + 's'](); - }, - - as : function (units) { - var days, months; - units = normalizeUnits(units); - - if (units === 'month' || units === 'year') { - days = this._days + this._milliseconds / 864e5; - months = this._months + daysToYears(days) * 12; - return units === 'month' ? months : months / 12; - } else { - // handle milliseconds separately because of floating point math errors (issue #1867) - days = this._days + yearsToDays(this._months / 12); - switch (units) { - case 'week': return days / 7 + this._milliseconds / 6048e5; - case 'day': return days + this._milliseconds / 864e5; - case 'hour': return days * 24 + this._milliseconds / 36e5; - case 'minute': return days * 24 * 60 + this._milliseconds / 6e4; - case 'second': return days * 24 * 60 * 60 + this._milliseconds / 1000; - // Math.floor prevents floating point math errors here - case 'millisecond': return Math.floor(days * 24 * 60 * 60 * 1000) + this._milliseconds; - default: throw new Error('Unknown unit ' + units); - } - } - }, - - lang : moment.fn.lang, - locale : moment.fn.locale, - - toIsoString : deprecate( - 'toIsoString() is deprecated. Please use toISOString() instead ' + - '(notice the capitals)', - function () { - return this.toISOString(); - } - ), - - toISOString : function () { - // inspired by https://github.com/dordille/moment-isoduration/blob/master/moment.isoduration.js - var years = Math.abs(this.years()), - months = Math.abs(this.months()), - days = Math.abs(this.days()), - hours = Math.abs(this.hours()), - minutes = Math.abs(this.minutes()), - seconds = Math.abs(this.seconds() + this.milliseconds() / 1000); - - if (!this.asSeconds()) { - // this is the same as C#'s (Noda) and python (isodate)... - // but not other JS (goog.date) - return 'P0D'; - } - - return (this.asSeconds() < 0 ? '-' : '') + - 'P' + - (years ? years + 'Y' : '') + - (months ? months + 'M' : '') + - (days ? days + 'D' : '') + - ((hours || minutes || seconds) ? 'T' : '') + - (hours ? hours + 'H' : '') + - (minutes ? minutes + 'M' : '') + - (seconds ? seconds + 'S' : ''); - }, - - localeData : function () { - return this._locale; - } - }); - - moment.duration.fn.toString = moment.duration.fn.toISOString; - - function makeDurationGetter(name) { - moment.duration.fn[name] = function () { - return this._data[name]; - }; - } - - for (i in unitMillisecondFactors) { - if (hasOwnProp(unitMillisecondFactors, i)) { - makeDurationGetter(i.toLowerCase()); - } - } - - moment.duration.fn.asMilliseconds = function () { - return this.as('ms'); - }; - moment.duration.fn.asSeconds = function () { - return this.as('s'); - }; - moment.duration.fn.asMinutes = function () { - return this.as('m'); - }; - moment.duration.fn.asHours = function () { - return this.as('h'); - }; - moment.duration.fn.asDays = function () { - return this.as('d'); - }; - moment.duration.fn.asWeeks = function () { - return this.as('weeks'); - }; - moment.duration.fn.asMonths = function () { - return this.as('M'); - }; - moment.duration.fn.asYears = function () { - return this.as('y'); - }; - - /************************************ - Default Locale - ************************************/ - - - // Set default locale, other locale will inherit from English. - moment.locale('en', { - ordinal : function (number) { - var b = number % 10, - output = (toInt(number % 100 / 10) === 1) ? 'th' : - (b === 1) ? 'st' : - (b === 2) ? 'nd' : - (b === 3) ? 'rd' : 'th'; - return number + output; - } - }); - - // moment.js locale configuration -// locale : afrikaans (af) -// author : Werner Mollentze : https://github.com/wernerm - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('af', { - months : 'Januarie_Februarie_Maart_April_Mei_Junie_Julie_Augustus_September_Oktober_November_Desember'.split('_'), - monthsShort : 'Jan_Feb_Mar_Apr_Mei_Jun_Jul_Aug_Sep_Okt_Nov_Des'.split('_'), - weekdays : 'Sondag_Maandag_Dinsdag_Woensdag_Donderdag_Vrydag_Saterdag'.split('_'), - weekdaysShort : 'Son_Maa_Din_Woe_Don_Vry_Sat'.split('_'), - weekdaysMin : 'So_Ma_Di_Wo_Do_Vr_Sa'.split('_'), - meridiem : function (hours, minutes, isLower) { - if (hours < 12) { - return isLower ? 'vm' : 'VM'; - } else { - return isLower ? 'nm' : 'NM'; - } - }, - longDateFormat : { - LT : 'HH:mm', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd, D MMMM YYYY LT' - }, - calendar : { - sameDay : '[Vandag om] LT', - nextDay : '[Môre om] LT', - nextWeek : 'dddd [om] LT', - lastDay : '[Gister om] LT', - lastWeek : '[Laas] dddd [om] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'oor %s', - past : '%s gelede', - s : '\'n paar sekondes', - m : '\'n minuut', - mm : '%d minute', - h : '\'n uur', - hh : '%d ure', - d : '\'n dag', - dd : '%d dae', - M : '\'n maand', - MM : '%d maande', - y : '\'n jaar', - yy : '%d jaar' - }, - ordinal : function (number) { - return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de'); // Thanks to Joris Röling : https://github.com/jjupiter - }, - week : { - dow : 1, // Maandag is die eerste dag van die week. - doy : 4 // Die week wat die 4de Januarie bevat is die eerste week van die jaar. - } - }); -})); -// moment.js locale configuration -// locale : Moroccan Arabic (ar-ma) -// author : ElFadili Yassine : https://github.com/ElFadiliY -// author : Abdel Said : https://github.com/abdelsaid - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('ar-ma', { - months : 'يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر'.split('_'), - monthsShort : 'يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر'.split('_'), - weekdays : 'الأحد_الإتنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'), - weekdaysShort : 'احد_اتنين_ثلاثاء_اربعاء_خميس_جمعة_سبت'.split('_'), - weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd D MMMM YYYY LT' - }, - calendar : { - sameDay: '[اليوم على الساعة] LT', - nextDay: '[غدا على الساعة] LT', - nextWeek: 'dddd [على الساعة] LT', - lastDay: '[أمس على الساعة] LT', - lastWeek: 'dddd [على الساعة] LT', - sameElse: 'L' - }, - relativeTime : { - future : 'في %s', - past : 'منذ %s', - s : 'ثوان', - m : 'دقيقة', - mm : '%d دقائق', - h : 'ساعة', - hh : '%d ساعات', - d : 'يوم', - dd : '%d أيام', - M : 'شهر', - MM : '%d أشهر', - y : 'سنة', - yy : '%d سنوات' - }, - week : { - dow : 6, // Saturday is the first day of the week. - doy : 12 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : Arabic Saudi Arabia (ar-sa) -// author : Suhail Alkowaileet : https://github.com/xsoh - -(function (factory) { - factory(moment); -}(function (moment) { - var symbolMap = { - '1': '١', - '2': '٢', - '3': '٣', - '4': '٤', - '5': '٥', - '6': '٦', - '7': '٧', - '8': '٨', - '9': '٩', - '0': '٠' - }, numberMap = { - '١': '1', - '٢': '2', - '٣': '3', - '٤': '4', - '٥': '5', - '٦': '6', - '٧': '7', - '٨': '8', - '٩': '9', - '٠': '0' - }; - - return moment.defineLocale('ar-sa', { - months : 'يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'), - monthsShort : 'يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر'.split('_'), - weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'), - weekdaysShort : 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'), - weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd D MMMM YYYY LT' - }, - meridiem : function (hour, minute, isLower) { - if (hour < 12) { - return 'ص'; - } else { - return 'م'; - } - }, - calendar : { - sameDay: '[اليوم على الساعة] LT', - nextDay: '[غدا على الساعة] LT', - nextWeek: 'dddd [على الساعة] LT', - lastDay: '[أمس على الساعة] LT', - lastWeek: 'dddd [على الساعة] LT', - sameElse: 'L' - }, - relativeTime : { - future : 'في %s', - past : 'منذ %s', - s : 'ثوان', - m : 'دقيقة', - mm : '%d دقائق', - h : 'ساعة', - hh : '%d ساعات', - d : 'يوم', - dd : '%d أيام', - M : 'شهر', - MM : '%d أشهر', - y : 'سنة', - yy : '%d سنوات' - }, - preparse: function (string) { - return string.replace(/[۰-۹]/g, function (match) { - return numberMap[match]; - }).replace(/،/g, ','); - }, - postformat: function (string) { - return string.replace(/\d/g, function (match) { - return symbolMap[match]; - }).replace(/,/g, '،'); - }, - week : { - dow : 6, // Saturday is the first day of the week. - doy : 12 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// Locale: Arabic (ar) -// Author: Abdel Said: https://github.com/abdelsaid -// Changes in months, weekdays: Ahmed Elkhatib -// Native plural forms: forabi https://github.com/forabi - -(function (factory) { - factory(moment); -}(function (moment) { - var symbolMap = { - '1': '١', - '2': '٢', - '3': '٣', - '4': '٤', - '5': '٥', - '6': '٦', - '7': '٧', - '8': '٨', - '9': '٩', - '0': '٠' - }, numberMap = { - '١': '1', - '٢': '2', - '٣': '3', - '٤': '4', - '٥': '5', - '٦': '6', - '٧': '7', - '٨': '8', - '٩': '9', - '٠': '0' - }, pluralForm = function (n) { - return n === 0 ? 0 : n === 1 ? 1 : n === 2 ? 2 : n % 100 >= 3 && n % 100 <= 10 ? 3 : n % 100 >= 11 ? 4 : 5; - }, plurals = { - s : ['أقل من ثانية', 'ثانية واحدة', ['ثانيتان', 'ثانيتين'], '%d ثوان', '%d ثانية', '%d ثانية'], - m : ['أقل من دقيقة', 'دقيقة واحدة', ['دقيقتان', 'دقيقتين'], '%d دقائق', '%d دقيقة', '%d دقيقة'], - h : ['أقل من ساعة', 'ساعة واحدة', ['ساعتان', 'ساعتين'], '%d ساعات', '%d ساعة', '%d ساعة'], - d : ['أقل من يوم', 'يوم واحد', ['يومان', 'يومين'], '%d أيام', '%d يومًا', '%d يوم'], - M : ['أقل من شهر', 'شهر واحد', ['شهران', 'شهرين'], '%d أشهر', '%d شهرا', '%d شهر'], - y : ['أقل من عام', 'عام واحد', ['عامان', 'عامين'], '%d أعوام', '%d عامًا', '%d عام'] - }, pluralize = function (u) { - return function (number, withoutSuffix, string, isFuture) { - var f = pluralForm(number), - str = plurals[u][pluralForm(number)]; - if (f === 2) { - str = str[withoutSuffix ? 0 : 1]; - } - return str.replace(/%d/i, number); - }; - }, months = [ - 'كانون الثاني يناير', - 'شباط فبراير', - 'آذار مارس', - 'نيسان أبريل', - 'أيار مايو', - 'حزيران يونيو', - 'تموز يوليو', - 'آب أغسطس', - 'أيلول سبتمبر', - 'تشرين الأول أكتوبر', - 'تشرين الثاني نوفمبر', - 'كانون الأول ديسمبر' - ]; - - return moment.defineLocale('ar', { - months : months, - monthsShort : months, - weekdays : 'الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت'.split('_'), - weekdaysShort : 'أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت'.split('_'), - weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd D MMMM YYYY LT' - }, - meridiem : function (hour, minute, isLower) { - if (hour < 12) { - return 'ص'; - } else { - return 'م'; - } - }, - calendar : { - sameDay: '[اليوم عند الساعة] LT', - nextDay: '[غدًا عند الساعة] LT', - nextWeek: 'dddd [عند الساعة] LT', - lastDay: '[أمس عند الساعة] LT', - lastWeek: 'dddd [عند الساعة] LT', - sameElse: 'L' - }, - relativeTime : { - future : 'بعد %s', - past : 'منذ %s', - s : pluralize('s'), - m : pluralize('m'), - mm : pluralize('m'), - h : pluralize('h'), - hh : pluralize('h'), - d : pluralize('d'), - dd : pluralize('d'), - M : pluralize('M'), - MM : pluralize('M'), - y : pluralize('y'), - yy : pluralize('y') - }, - preparse: function (string) { - return string.replace(/[۰-۹]/g, function (match) { - return numberMap[match]; - }).replace(/،/g, ','); - }, - postformat: function (string) { - return string.replace(/\d/g, function (match) { - return symbolMap[match]; - }).replace(/,/g, '،'); - }, - week : { - dow : 6, // Saturday is the first day of the week. - doy : 12 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : azerbaijani (az) -// author : topchiyev : https://github.com/topchiyev - -(function (factory) { - factory(moment); -}(function (moment) { - var suffixes = { - 1: '-inci', - 5: '-inci', - 8: '-inci', - 70: '-inci', - 80: '-inci', - - 2: '-nci', - 7: '-nci', - 20: '-nci', - 50: '-nci', - - 3: '-üncü', - 4: '-üncü', - 100: '-üncü', - - 6: '-ncı', - - 9: '-uncu', - 10: '-uncu', - 30: '-uncu', - - 60: '-ıncı', - 90: '-ıncı' - }; - return moment.defineLocale('az', { - months : 'yanvar_fevral_mart_aprel_may_iyun_iyul_avqust_sentyabr_oktyabr_noyabr_dekabr'.split('_'), - monthsShort : 'yan_fev_mar_apr_may_iyn_iyl_avq_sen_okt_noy_dek'.split('_'), - weekdays : 'Bazar_Bazar ertəsi_Çərşənbə axşamı_Çərşənbə_Cümə axşamı_Cümə_Şənbə'.split('_'), - weekdaysShort : 'Baz_BzE_ÇAx_Çər_CAx_Cüm_Şən'.split('_'), - weekdaysMin : 'Bz_BE_ÇA_Çə_CA_Cü_Şə'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'DD.MM.YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd, D MMMM YYYY LT' - }, - calendar : { - sameDay : '[bugün saat] LT', - nextDay : '[sabah saat] LT', - nextWeek : '[gələn həftə] dddd [saat] LT', - lastDay : '[dünən] LT', - lastWeek : '[keçən həftə] dddd [saat] LT', - sameElse : 'L' - }, - relativeTime : { - future : '%s sonra', - past : '%s əvvəl', - s : 'birneçə saniyyə', - m : 'bir dəqiqə', - mm : '%d dəqiqə', - h : 'bir saat', - hh : '%d saat', - d : 'bir gün', - dd : '%d gün', - M : 'bir ay', - MM : '%d ay', - y : 'bir il', - yy : '%d il' - }, - meridiem : function (hour, minute, isLower) { - if (hour < 4) { - return 'gecə'; - } else if (hour < 12) { - return 'səhər'; - } else if (hour < 17) { - return 'gündüz'; - } else { - return 'axşam'; - } - }, - ordinal : function (number) { - if (number === 0) { // special case for zero - return number + '-ıncı'; - } - var a = number % 10, - b = number % 100 - a, - c = number >= 100 ? 100 : null; - - return number + (suffixes[a] || suffixes[b] || suffixes[c]); - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : belarusian (be) -// author : Dmitry Demidov : https://github.com/demidov91 -// author: Praleska: http://praleska.pro/ -// Author : Menelion Elensúle : https://github.com/Oire - -(function (factory) { - factory(moment); -}(function (moment) { - function plural(word, num) { - var forms = word.split('_'); - return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]); - } - - function relativeTimeWithPlural(number, withoutSuffix, key) { - var format = { - 'mm': withoutSuffix ? 'хвіліна_хвіліны_хвілін' : 'хвіліну_хвіліны_хвілін', - 'hh': withoutSuffix ? 'гадзіна_гадзіны_гадзін' : 'гадзіну_гадзіны_гадзін', - 'dd': 'дзень_дні_дзён', - 'MM': 'месяц_месяцы_месяцаў', - 'yy': 'год_гады_гадоў' - }; - if (key === 'm') { - return withoutSuffix ? 'хвіліна' : 'хвіліну'; - } - else if (key === 'h') { - return withoutSuffix ? 'гадзіна' : 'гадзіну'; - } - else { - return number + ' ' + plural(format[key], +number); - } - } - - function monthsCaseReplace(m, format) { - var months = { - 'nominative': 'студзень_люты_сакавік_красавік_травень_чэрвень_ліпень_жнівень_верасень_кастрычнік_лістапад_снежань'.split('_'), - 'accusative': 'студзеня_лютага_сакавіка_красавіка_траўня_чэрвеня_ліпеня_жніўня_верасня_кастрычніка_лістапада_снежня'.split('_') - }, - - nounCase = (/D[oD]?(\[[^\[\]]*\]|\s+)+MMMM?/).test(format) ? - 'accusative' : - 'nominative'; - - return months[nounCase][m.month()]; - } - - function weekdaysCaseReplace(m, format) { - var weekdays = { - 'nominative': 'нядзеля_панядзелак_аўторак_серада_чацвер_пятніца_субота'.split('_'), - 'accusative': 'нядзелю_панядзелак_аўторак_сераду_чацвер_пятніцу_суботу'.split('_') - }, - - nounCase = (/\[ ?[Вв] ?(?:мінулую|наступную)? ?\] ?dddd/).test(format) ? - 'accusative' : - 'nominative'; - - return weekdays[nounCase][m.day()]; - } - - return moment.defineLocale('be', { - months : monthsCaseReplace, - monthsShort : 'студ_лют_сак_крас_трав_чэрв_ліп_жнів_вер_каст_ліст_снеж'.split('_'), - weekdays : weekdaysCaseReplace, - weekdaysShort : 'нд_пн_ат_ср_чц_пт_сб'.split('_'), - weekdaysMin : 'нд_пн_ат_ср_чц_пт_сб'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'DD.MM.YYYY', - LL : 'D MMMM YYYY г.', - LLL : 'D MMMM YYYY г., LT', - LLLL : 'dddd, D MMMM YYYY г., LT' - }, - calendar : { - sameDay: '[Сёння ў] LT', - nextDay: '[Заўтра ў] LT', - lastDay: '[Учора ў] LT', - nextWeek: function () { - return '[У] dddd [ў] LT'; - }, - lastWeek: function () { - switch (this.day()) { - case 0: - case 3: - case 5: - case 6: - return '[У мінулую] dddd [ў] LT'; - case 1: - case 2: - case 4: - return '[У мінулы] dddd [ў] LT'; - } - }, - sameElse: 'L' - }, - relativeTime : { - future : 'праз %s', - past : '%s таму', - s : 'некалькі секунд', - m : relativeTimeWithPlural, - mm : relativeTimeWithPlural, - h : relativeTimeWithPlural, - hh : relativeTimeWithPlural, - d : 'дзень', - dd : relativeTimeWithPlural, - M : 'месяц', - MM : relativeTimeWithPlural, - y : 'год', - yy : relativeTimeWithPlural - }, - - - meridiem : function (hour, minute, isLower) { - if (hour < 4) { - return 'ночы'; - } else if (hour < 12) { - return 'раніцы'; - } else if (hour < 17) { - return 'дня'; - } else { - return 'вечара'; - } - }, - - ordinal: function (number, period) { - switch (period) { - case 'M': - case 'd': - case 'DDD': - case 'w': - case 'W': - return (number % 10 === 2 || number % 10 === 3) && (number % 100 !== 12 && number % 100 !== 13) ? number + '-і' : number + '-ы'; - case 'D': - return number + '-га'; - default: - return number; - } - }, - - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : bulgarian (bg) -// author : Krasen Borisov : https://github.com/kraz - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('bg', { - months : 'януари_февруари_март_април_май_юни_юли_август_септември_октомври_ноември_декември'.split('_'), - monthsShort : 'янр_фев_мар_апр_май_юни_юли_авг_сеп_окт_ное_дек'.split('_'), - weekdays : 'неделя_понеделник_вторник_сряда_четвъртък_петък_събота'.split('_'), - weekdaysShort : 'нед_пон_вто_сря_чет_пет_съб'.split('_'), - weekdaysMin : 'нд_пн_вт_ср_чт_пт_сб'.split('_'), - longDateFormat : { - LT : 'H:mm', - L : 'D.MM.YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd, D MMMM YYYY LT' - }, - calendar : { - sameDay : '[Днес в] LT', - nextDay : '[Утре в] LT', - nextWeek : 'dddd [в] LT', - lastDay : '[Вчера в] LT', - lastWeek : function () { - switch (this.day()) { - case 0: - case 3: - case 6: - return '[В изминалата] dddd [в] LT'; - case 1: - case 2: - case 4: - case 5: - return '[В изминалия] dddd [в] LT'; - } - }, - sameElse : 'L' - }, - relativeTime : { - future : 'след %s', - past : 'преди %s', - s : 'няколко секунди', - m : 'минута', - mm : '%d минути', - h : 'час', - hh : '%d часа', - d : 'ден', - dd : '%d дни', - M : 'месец', - MM : '%d месеца', - y : 'година', - yy : '%d години' - }, - ordinal : function (number) { - var lastDigit = number % 10, - last2Digits = number % 100; - if (number === 0) { - return number + '-ев'; - } else if (last2Digits === 0) { - return number + '-ен'; - } else if (last2Digits > 10 && last2Digits < 20) { - return number + '-ти'; - } else if (lastDigit === 1) { - return number + '-ви'; - } else if (lastDigit === 2) { - return number + '-ри'; - } else if (lastDigit === 7 || lastDigit === 8) { - return number + '-ми'; - } else { - return number + '-ти'; - } - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : Bengali (bn) -// author : Kaushik Gandhi : https://github.com/kaushikgandhi - -(function (factory) { - factory(moment); -}(function (moment) { - var symbolMap = { - '1': '১', - '2': '২', - '3': '৩', - '4': '৪', - '5': '৫', - '6': '৬', - '7': '৭', - '8': '৮', - '9': '৯', - '0': '০' - }, - numberMap = { - '১': '1', - '২': '2', - '৩': '3', - '৪': '4', - '৫': '5', - '৬': '6', - '৭': '7', - '৮': '8', - '৯': '9', - '০': '0' - }; - - return moment.defineLocale('bn', { - months : 'জানুয়ারী_ফেবুয়ারী_মার্চ_এপ্রিল_মে_জুন_জুলাই_অগাস্ট_সেপ্টেম্বর_অক্টোবর_নভেম্বর_ডিসেম্বর'.split('_'), - monthsShort : 'জানু_ফেব_মার্চ_এপর_মে_জুন_জুল_অগ_সেপ্ট_অক্টো_নভ_ডিসেম্'.split('_'), - weekdays : 'রবিবার_সোমবার_মঙ্গলবার_বুধবার_বৃহস্পত্তিবার_শুক্রুবার_শনিবার'.split('_'), - weekdaysShort : 'রবি_সোম_মঙ্গল_বুধ_বৃহস্পত্তি_শুক্রু_শনি'.split('_'), - weekdaysMin : 'রব_সম_মঙ্গ_বু_ব্রিহ_শু_শনি'.split('_'), - longDateFormat : { - LT : 'A h:mm সময়', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY, LT', - LLLL : 'dddd, D MMMM YYYY, LT' - }, - calendar : { - sameDay : '[আজ] LT', - nextDay : '[আগামীকাল] LT', - nextWeek : 'dddd, LT', - lastDay : '[গতকাল] LT', - lastWeek : '[গত] dddd, LT', - sameElse : 'L' - }, - relativeTime : { - future : '%s পরে', - past : '%s আগে', - s : 'কএক সেকেন্ড', - m : 'এক মিনিট', - mm : '%d মিনিট', - h : 'এক ঘন্টা', - hh : '%d ঘন্টা', - d : 'এক দিন', - dd : '%d দিন', - M : 'এক মাস', - MM : '%d মাস', - y : 'এক বছর', - yy : '%d বছর' - }, - preparse: function (string) { - return string.replace(/[১২৩৪৫৬৭৮৯০]/g, function (match) { - return numberMap[match]; - }); - }, - postformat: function (string) { - return string.replace(/\d/g, function (match) { - return symbolMap[match]; - }); - }, - //Bengali is a vast language its spoken - //in different forms in various parts of the world. - //I have just generalized with most common one used - meridiem : function (hour, minute, isLower) { - if (hour < 4) { - return 'রাত'; - } else if (hour < 10) { - return 'শকাল'; - } else if (hour < 17) { - return 'দুপুর'; - } else if (hour < 20) { - return 'বিকেল'; - } else { - return 'রাত'; - } - }, - week : { - dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : tibetan (bo) -// author : Thupten N. Chakrishar : https://github.com/vajradog - -(function (factory) { - factory(moment); -}(function (moment) { - var symbolMap = { - '1': '༡', - '2': '༢', - '3': '༣', - '4': '༤', - '5': '༥', - '6': '༦', - '7': '༧', - '8': '༨', - '9': '༩', - '0': '༠' - }, - numberMap = { - '༡': '1', - '༢': '2', - '༣': '3', - '༤': '4', - '༥': '5', - '༦': '6', - '༧': '7', - '༨': '8', - '༩': '9', - '༠': '0' - }; - - return moment.defineLocale('bo', { - months : 'ཟླ་བ་དང་པོ_ཟླ་བ་གཉིས་པ_ཟླ་བ་གསུམ་པ_ཟླ་བ་བཞི་པ_ཟླ་བ་ལྔ་པ_ཟླ་བ་དྲུག་པ_ཟླ་བ་བདུན་པ_ཟླ་བ་བརྒྱད་པ_ཟླ་བ་དགུ་པ_ཟླ་བ་བཅུ་པ_ཟླ་བ་བཅུ་གཅིག་པ_ཟླ་བ་བཅུ་གཉིས་པ'.split('_'), - monthsShort : 'ཟླ་བ་དང་པོ_ཟླ་བ་གཉིས་པ_ཟླ་བ་གསུམ་པ_ཟླ་བ་བཞི་པ_ཟླ་བ་ལྔ་པ_ཟླ་བ་དྲུག་པ_ཟླ་བ་བདུན་པ_ཟླ་བ་བརྒྱད་པ_ཟླ་བ་དགུ་པ_ཟླ་བ་བཅུ་པ_ཟླ་བ་བཅུ་གཅིག་པ_ཟླ་བ་བཅུ་གཉིས་པ'.split('_'), - weekdays : 'གཟའ་ཉི་མ་_གཟའ་ཟླ་བ་_གཟའ་མིག་དམར་_གཟའ་ལྷག་པ་_གཟའ་ཕུར་བུ_གཟའ་པ་སངས་_གཟའ་སྤེན་པ་'.split('_'), - weekdaysShort : 'ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་'.split('_'), - weekdaysMin : 'ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་'.split('_'), - longDateFormat : { - LT : 'A h:mm', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY, LT', - LLLL : 'dddd, D MMMM YYYY, LT' - }, - calendar : { - sameDay : '[དི་རིང] LT', - nextDay : '[སང་ཉིན] LT', - nextWeek : '[བདུན་ཕྲག་རྗེས་མ], LT', - lastDay : '[ཁ་སང] LT', - lastWeek : '[བདུན་ཕྲག་མཐའ་མ] dddd, LT', - sameElse : 'L' - }, - relativeTime : { - future : '%s ལ་', - past : '%s སྔན་ལ', - s : 'ལམ་སང', - m : 'སྐར་མ་གཅིག', - mm : '%d སྐར་མ', - h : 'ཆུ་ཚོད་གཅིག', - hh : '%d ཆུ་ཚོད', - d : 'ཉིན་གཅིག', - dd : '%d ཉིན་', - M : 'ཟླ་བ་གཅིག', - MM : '%d ཟླ་བ', - y : 'ལོ་གཅིག', - yy : '%d ལོ' - }, - preparse: function (string) { - return string.replace(/[༡༢༣༤༥༦༧༨༩༠]/g, function (match) { - return numberMap[match]; - }); - }, - postformat: function (string) { - return string.replace(/\d/g, function (match) { - return symbolMap[match]; - }); - }, - meridiem : function (hour, minute, isLower) { - if (hour < 4) { - return 'མཚན་མོ'; - } else if (hour < 10) { - return 'ཞོགས་ཀས'; - } else if (hour < 17) { - return 'ཉིན་གུང'; - } else if (hour < 20) { - return 'དགོང་དག'; - } else { - return 'མཚན་མོ'; - } - }, - week : { - dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : breton (br) -// author : Jean-Baptiste Le Duigou : https://github.com/jbleduigou - -(function (factory) { - factory(moment); -}(function (moment) { - function relativeTimeWithMutation(number, withoutSuffix, key) { - var format = { - 'mm': 'munutenn', - 'MM': 'miz', - 'dd': 'devezh' - }; - return number + ' ' + mutation(format[key], number); - } - - function specialMutationForYears(number) { - switch (lastNumber(number)) { - case 1: - case 3: - case 4: - case 5: - case 9: - return number + ' bloaz'; - default: - return number + ' vloaz'; - } - } - - function lastNumber(number) { - if (number > 9) { - return lastNumber(number % 10); - } - return number; - } - - function mutation(text, number) { - if (number === 2) { - return softMutation(text); - } - return text; - } - - function softMutation(text) { - var mutationTable = { - 'm': 'v', - 'b': 'v', - 'd': 'z' - }; - if (mutationTable[text.charAt(0)] === undefined) { - return text; - } - return mutationTable[text.charAt(0)] + text.substring(1); - } - - return moment.defineLocale('br', { - months : 'Genver_C\'hwevrer_Meurzh_Ebrel_Mae_Mezheven_Gouere_Eost_Gwengolo_Here_Du_Kerzu'.split('_'), - monthsShort : 'Gen_C\'hwe_Meu_Ebr_Mae_Eve_Gou_Eos_Gwe_Her_Du_Ker'.split('_'), - weekdays : 'Sul_Lun_Meurzh_Merc\'her_Yaou_Gwener_Sadorn'.split('_'), - weekdaysShort : 'Sul_Lun_Meu_Mer_Yao_Gwe_Sad'.split('_'), - weekdaysMin : 'Su_Lu_Me_Mer_Ya_Gw_Sa'.split('_'), - longDateFormat : { - LT : 'h[e]mm A', - L : 'DD/MM/YYYY', - LL : 'D [a viz] MMMM YYYY', - LLL : 'D [a viz] MMMM YYYY LT', - LLLL : 'dddd, D [a viz] MMMM YYYY LT' - }, - calendar : { - sameDay : '[Hiziv da] LT', - nextDay : '[Warc\'hoazh da] LT', - nextWeek : 'dddd [da] LT', - lastDay : '[Dec\'h da] LT', - lastWeek : 'dddd [paset da] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'a-benn %s', - past : '%s \'zo', - s : 'un nebeud segondennoù', - m : 'ur vunutenn', - mm : relativeTimeWithMutation, - h : 'un eur', - hh : '%d eur', - d : 'un devezh', - dd : relativeTimeWithMutation, - M : 'ur miz', - MM : relativeTimeWithMutation, - y : 'ur bloaz', - yy : specialMutationForYears - }, - ordinal : function (number) { - var output = (number === 1) ? 'añ' : 'vet'; - return number + output; - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : bosnian (bs) -// author : Nedim Cholich : https://github.com/frontyard -// based on (hr) translation by Bojan Marković - -(function (factory) { - factory(moment); -}(function (moment) { - function translate(number, withoutSuffix, key) { - var result = number + ' '; - switch (key) { - case 'm': - return withoutSuffix ? 'jedna minuta' : 'jedne minute'; - case 'mm': - if (number === 1) { - result += 'minuta'; - } else if (number === 2 || number === 3 || number === 4) { - result += 'minute'; - } else { - result += 'minuta'; - } - return result; - case 'h': - return withoutSuffix ? 'jedan sat' : 'jednog sata'; - case 'hh': - if (number === 1) { - result += 'sat'; - } else if (number === 2 || number === 3 || number === 4) { - result += 'sata'; - } else { - result += 'sati'; - } - return result; - case 'dd': - if (number === 1) { - result += 'dan'; - } else { - result += 'dana'; - } - return result; - case 'MM': - if (number === 1) { - result += 'mjesec'; - } else if (number === 2 || number === 3 || number === 4) { - result += 'mjeseca'; - } else { - result += 'mjeseci'; - } - return result; - case 'yy': - if (number === 1) { - result += 'godina'; - } else if (number === 2 || number === 3 || number === 4) { - result += 'godine'; - } else { - result += 'godina'; - } - return result; - } - } - - return moment.defineLocale('bs', { - months : 'januar_februar_mart_april_maj_juni_juli_avgust_septembar_oktobar_novembar_decembar'.split('_'), - monthsShort : 'jan._feb._mar._apr._maj._jun._jul._avg._sep._okt._nov._dec.'.split('_'), - weekdays : 'nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota'.split('_'), - weekdaysShort : 'ned._pon._uto._sri._čet._pet._sub.'.split('_'), - weekdaysMin : 'ne_po_ut_sr_če_pe_su'.split('_'), - longDateFormat : { - LT : 'H:mm', - L : 'DD. MM. YYYY', - LL : 'D. MMMM YYYY', - LLL : 'D. MMMM YYYY LT', - LLLL : 'dddd, D. MMMM YYYY LT' - }, - calendar : { - sameDay : '[danas u] LT', - nextDay : '[sutra u] LT', - - nextWeek : function () { - switch (this.day()) { - case 0: - return '[u] [nedjelju] [u] LT'; - case 3: - return '[u] [srijedu] [u] LT'; - case 6: - return '[u] [subotu] [u] LT'; - case 1: - case 2: - case 4: - case 5: - return '[u] dddd [u] LT'; - } - }, - lastDay : '[jučer u] LT', - lastWeek : function () { - switch (this.day()) { - case 0: - case 3: - return '[prošlu] dddd [u] LT'; - case 6: - return '[prošle] [subote] [u] LT'; - case 1: - case 2: - case 4: - case 5: - return '[prošli] dddd [u] LT'; - } - }, - sameElse : 'L' - }, - relativeTime : { - future : 'za %s', - past : 'prije %s', - s : 'par sekundi', - m : translate, - mm : translate, - h : translate, - hh : translate, - d : 'dan', - dd : translate, - M : 'mjesec', - MM : translate, - y : 'godinu', - yy : translate - }, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : catalan (ca) -// author : Juan G. Hurtado : https://github.com/juanghurtado - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('ca', { - months : 'gener_febrer_març_abril_maig_juny_juliol_agost_setembre_octubre_novembre_desembre'.split('_'), - monthsShort : 'gen._febr._mar._abr._mai._jun._jul._ag._set._oct._nov._des.'.split('_'), - weekdays : 'diumenge_dilluns_dimarts_dimecres_dijous_divendres_dissabte'.split('_'), - weekdaysShort : 'dg._dl._dt._dc._dj._dv._ds.'.split('_'), - weekdaysMin : 'Dg_Dl_Dt_Dc_Dj_Dv_Ds'.split('_'), - longDateFormat : { - LT : 'H:mm', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd D MMMM YYYY LT' - }, - calendar : { - sameDay : function () { - return '[avui a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT'; - }, - nextDay : function () { - return '[demà a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT'; - }, - nextWeek : function () { - return 'dddd [a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT'; - }, - lastDay : function () { - return '[ahir a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT'; - }, - lastWeek : function () { - return '[el] dddd [passat a ' + ((this.hours() !== 1) ? 'les' : 'la') + '] LT'; - }, - sameElse : 'L' - }, - relativeTime : { - future : 'en %s', - past : 'fa %s', - s : 'uns segons', - m : 'un minut', - mm : '%d minuts', - h : 'una hora', - hh : '%d hores', - d : 'un dia', - dd : '%d dies', - M : 'un mes', - MM : '%d mesos', - y : 'un any', - yy : '%d anys' - }, - ordinal : '%dº', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : czech (cs) -// author : petrbela : https://github.com/petrbela - -(function (factory) { - factory(moment); -}(function (moment) { - var months = 'leden_únor_březen_duben_květen_červen_červenec_srpen_září_říjen_listopad_prosinec'.split('_'), - monthsShort = 'led_úno_bře_dub_kvě_čvn_čvc_srp_zář_říj_lis_pro'.split('_'); - - function plural(n) { - return (n > 1) && (n < 5) && (~~(n / 10) !== 1); - } - - function translate(number, withoutSuffix, key, isFuture) { - var result = number + ' '; - switch (key) { - case 's': // a few seconds / in a few seconds / a few seconds ago - return (withoutSuffix || isFuture) ? 'pár sekund' : 'pár sekundami'; - case 'm': // a minute / in a minute / a minute ago - return withoutSuffix ? 'minuta' : (isFuture ? 'minutu' : 'minutou'); - case 'mm': // 9 minutes / in 9 minutes / 9 minutes ago - if (withoutSuffix || isFuture) { - return result + (plural(number) ? 'minuty' : 'minut'); - } else { - return result + 'minutami'; - } - break; - case 'h': // an hour / in an hour / an hour ago - return withoutSuffix ? 'hodina' : (isFuture ? 'hodinu' : 'hodinou'); - case 'hh': // 9 hours / in 9 hours / 9 hours ago - if (withoutSuffix || isFuture) { - return result + (plural(number) ? 'hodiny' : 'hodin'); - } else { - return result + 'hodinami'; - } - break; - case 'd': // a day / in a day / a day ago - return (withoutSuffix || isFuture) ? 'den' : 'dnem'; - case 'dd': // 9 days / in 9 days / 9 days ago - if (withoutSuffix || isFuture) { - return result + (plural(number) ? 'dny' : 'dní'); - } else { - return result + 'dny'; - } - break; - case 'M': // a month / in a month / a month ago - return (withoutSuffix || isFuture) ? 'měsíc' : 'měsícem'; - case 'MM': // 9 months / in 9 months / 9 months ago - if (withoutSuffix || isFuture) { - return result + (plural(number) ? 'měsíce' : 'měsíců'); - } else { - return result + 'měsíci'; - } - break; - case 'y': // a year / in a year / a year ago - return (withoutSuffix || isFuture) ? 'rok' : 'rokem'; - case 'yy': // 9 years / in 9 years / 9 years ago - if (withoutSuffix || isFuture) { - return result + (plural(number) ? 'roky' : 'let'); - } else { - return result + 'lety'; - } - break; - } - } - - return moment.defineLocale('cs', { - months : months, - monthsShort : monthsShort, - monthsParse : (function (months, monthsShort) { - var i, _monthsParse = []; - for (i = 0; i < 12; i++) { - // use custom parser to solve problem with July (červenec) - _monthsParse[i] = new RegExp('^' + months[i] + '$|^' + monthsShort[i] + '$', 'i'); - } - return _monthsParse; - }(months, monthsShort)), - weekdays : 'neděle_pondělí_úterý_středa_čtvrtek_pátek_sobota'.split('_'), - weekdaysShort : 'ne_po_út_st_čt_pá_so'.split('_'), - weekdaysMin : 'ne_po_út_st_čt_pá_so'.split('_'), - longDateFormat : { - LT: 'H:mm', - L : 'DD. MM. YYYY', - LL : 'D. MMMM YYYY', - LLL : 'D. MMMM YYYY LT', - LLLL : 'dddd D. MMMM YYYY LT' - }, - calendar : { - sameDay: '[dnes v] LT', - nextDay: '[zítra v] LT', - nextWeek: function () { - switch (this.day()) { - case 0: - return '[v neděli v] LT'; - case 1: - case 2: - return '[v] dddd [v] LT'; - case 3: - return '[ve středu v] LT'; - case 4: - return '[ve čtvrtek v] LT'; - case 5: - return '[v pátek v] LT'; - case 6: - return '[v sobotu v] LT'; - } - }, - lastDay: '[včera v] LT', - lastWeek: function () { - switch (this.day()) { - case 0: - return '[minulou neděli v] LT'; - case 1: - case 2: - return '[minulé] dddd [v] LT'; - case 3: - return '[minulou středu v] LT'; - case 4: - case 5: - return '[minulý] dddd [v] LT'; - case 6: - return '[minulou sobotu v] LT'; - } - }, - sameElse: 'L' - }, - relativeTime : { - future : 'za %s', - past : 'před %s', - s : translate, - m : translate, - mm : translate, - h : translate, - hh : translate, - d : translate, - dd : translate, - M : translate, - MM : translate, - y : translate, - yy : translate - }, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : chuvash (cv) -// author : Anatoly Mironov : https://github.com/mirontoli - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('cv', { - months : 'кăрлач_нарăс_пуш_ака_май_çĕртме_утă_çурла_авăн_юпа_чӳк_раштав'.split('_'), - monthsShort : 'кăр_нар_пуш_ака_май_çĕр_утă_çур_ав_юпа_чӳк_раш'.split('_'), - weekdays : 'вырсарникун_тунтикун_ытларикун_юнкун_кĕçнерникун_эрнекун_шăматкун'.split('_'), - weekdaysShort : 'выр_тун_ытл_юн_кĕç_эрн_шăм'.split('_'), - weekdaysMin : 'вр_тн_ыт_юн_кç_эр_шм'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'DD-MM-YYYY', - LL : 'YYYY [çулхи] MMMM [уйăхĕн] D[-мĕшĕ]', - LLL : 'YYYY [çулхи] MMMM [уйăхĕн] D[-мĕшĕ], LT', - LLLL : 'dddd, YYYY [çулхи] MMMM [уйăхĕн] D[-мĕшĕ], LT' - }, - calendar : { - sameDay: '[Паян] LT [сехетре]', - nextDay: '[Ыран] LT [сехетре]', - lastDay: '[Ĕнер] LT [сехетре]', - nextWeek: '[Çитес] dddd LT [сехетре]', - lastWeek: '[Иртнĕ] dddd LT [сехетре]', - sameElse: 'L' - }, - relativeTime : { - future : function (output) { - var affix = /сехет$/i.exec(output) ? 'рен' : /çул$/i.exec(output) ? 'тан' : 'ран'; - return output + affix; - }, - past : '%s каялла', - s : 'пĕр-ик çеккунт', - m : 'пĕр минут', - mm : '%d минут', - h : 'пĕр сехет', - hh : '%d сехет', - d : 'пĕр кун', - dd : '%d кун', - M : 'пĕр уйăх', - MM : '%d уйăх', - y : 'пĕр çул', - yy : '%d çул' - }, - ordinal : '%d-мĕш', - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : Welsh (cy) -// author : Robert Allen - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('cy', { - months: 'Ionawr_Chwefror_Mawrth_Ebrill_Mai_Mehefin_Gorffennaf_Awst_Medi_Hydref_Tachwedd_Rhagfyr'.split('_'), - monthsShort: 'Ion_Chwe_Maw_Ebr_Mai_Meh_Gor_Aws_Med_Hyd_Tach_Rhag'.split('_'), - weekdays: 'Dydd Sul_Dydd Llun_Dydd Mawrth_Dydd Mercher_Dydd Iau_Dydd Gwener_Dydd Sadwrn'.split('_'), - weekdaysShort: 'Sul_Llun_Maw_Mer_Iau_Gwe_Sad'.split('_'), - weekdaysMin: 'Su_Ll_Ma_Me_Ia_Gw_Sa'.split('_'), - // time formats are the same as en-gb - longDateFormat: { - LT: 'HH:mm', - L: 'DD/MM/YYYY', - LL: 'D MMMM YYYY', - LLL: 'D MMMM YYYY LT', - LLLL: 'dddd, D MMMM YYYY LT' - }, - calendar: { - sameDay: '[Heddiw am] LT', - nextDay: '[Yfory am] LT', - nextWeek: 'dddd [am] LT', - lastDay: '[Ddoe am] LT', - lastWeek: 'dddd [diwethaf am] LT', - sameElse: 'L' - }, - relativeTime: { - future: 'mewn %s', - past: '%s yn ôl', - s: 'ychydig eiliadau', - m: 'munud', - mm: '%d munud', - h: 'awr', - hh: '%d awr', - d: 'diwrnod', - dd: '%d diwrnod', - M: 'mis', - MM: '%d mis', - y: 'blwyddyn', - yy: '%d flynedd' - }, - // traditional ordinal numbers above 31 are not commonly used in colloquial Welsh - ordinal: function (number) { - var b = number, - output = '', - lookup = [ - '', 'af', 'il', 'ydd', 'ydd', 'ed', 'ed', 'ed', 'fed', 'fed', 'fed', // 1af to 10fed - 'eg', 'fed', 'eg', 'eg', 'fed', 'eg', 'eg', 'fed', 'eg', 'fed' // 11eg to 20fed - ]; - - if (b > 20) { - if (b === 40 || b === 50 || b === 60 || b === 80 || b === 100) { - output = 'fed'; // not 30ain, 70ain or 90ain - } else { - output = 'ain'; - } - } else if (b > 0) { - output = lookup[b]; - } - - return number + output; - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : danish (da) -// author : Ulrik Nielsen : https://github.com/mrbase - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('da', { - months : 'januar_februar_marts_april_maj_juni_juli_august_september_oktober_november_december'.split('_'), - monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec'.split('_'), - weekdays : 'søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag'.split('_'), - weekdaysShort : 'søn_man_tir_ons_tor_fre_lør'.split('_'), - weekdaysMin : 'sø_ma_ti_on_to_fr_lø'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'DD/MM/YYYY', - LL : 'D. MMMM YYYY', - LLL : 'D. MMMM YYYY LT', - LLLL : 'dddd [d.] D. MMMM YYYY LT' - }, - calendar : { - sameDay : '[I dag kl.] LT', - nextDay : '[I morgen kl.] LT', - nextWeek : 'dddd [kl.] LT', - lastDay : '[I går kl.] LT', - lastWeek : '[sidste] dddd [kl] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'om %s', - past : '%s siden', - s : 'få sekunder', - m : 'et minut', - mm : '%d minutter', - h : 'en time', - hh : '%d timer', - d : 'en dag', - dd : '%d dage', - M : 'en måned', - MM : '%d måneder', - y : 'et år', - yy : '%d år' - }, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : austrian german (de-at) -// author : lluchs : https://github.com/lluchs -// author: Menelion Elensúle: https://github.com/Oire -// author : Martin Groller : https://github.com/MadMG - -(function (factory) { - factory(moment); -}(function (moment) { - function processRelativeTime(number, withoutSuffix, key, isFuture) { - var format = { - 'm': ['eine Minute', 'einer Minute'], - 'h': ['eine Stunde', 'einer Stunde'], - 'd': ['ein Tag', 'einem Tag'], - 'dd': [number + ' Tage', number + ' Tagen'], - 'M': ['ein Monat', 'einem Monat'], - 'MM': [number + ' Monate', number + ' Monaten'], - 'y': ['ein Jahr', 'einem Jahr'], - 'yy': [number + ' Jahre', number + ' Jahren'] - }; - return withoutSuffix ? format[key][0] : format[key][1]; - } - - return moment.defineLocale('de-at', { - months : 'Jänner_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'), - monthsShort : 'Jän._Febr._Mrz._Apr._Mai_Jun._Jul._Aug._Sept._Okt._Nov._Dez.'.split('_'), - weekdays : 'Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag'.split('_'), - weekdaysShort : 'So._Mo._Di._Mi._Do._Fr._Sa.'.split('_'), - weekdaysMin : 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'), - longDateFormat : { - LT: 'HH:mm [Uhr]', - L : 'DD.MM.YYYY', - LL : 'D. MMMM YYYY', - LLL : 'D. MMMM YYYY LT', - LLLL : 'dddd, D. MMMM YYYY LT' - }, - calendar : { - sameDay: '[Heute um] LT', - sameElse: 'L', - nextDay: '[Morgen um] LT', - nextWeek: 'dddd [um] LT', - lastDay: '[Gestern um] LT', - lastWeek: '[letzten] dddd [um] LT' - }, - relativeTime : { - future : 'in %s', - past : 'vor %s', - s : 'ein paar Sekunden', - m : processRelativeTime, - mm : '%d Minuten', - h : processRelativeTime, - hh : '%d Stunden', - d : processRelativeTime, - dd : processRelativeTime, - M : processRelativeTime, - MM : processRelativeTime, - y : processRelativeTime, - yy : processRelativeTime - }, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : german (de) -// author : lluchs : https://github.com/lluchs -// author: Menelion Elensúle: https://github.com/Oire - -(function (factory) { - factory(moment); -}(function (moment) { - function processRelativeTime(number, withoutSuffix, key, isFuture) { - var format = { - 'm': ['eine Minute', 'einer Minute'], - 'h': ['eine Stunde', 'einer Stunde'], - 'd': ['ein Tag', 'einem Tag'], - 'dd': [number + ' Tage', number + ' Tagen'], - 'M': ['ein Monat', 'einem Monat'], - 'MM': [number + ' Monate', number + ' Monaten'], - 'y': ['ein Jahr', 'einem Jahr'], - 'yy': [number + ' Jahre', number + ' Jahren'] - }; - return withoutSuffix ? format[key][0] : format[key][1]; - } - - return moment.defineLocale('de', { - months : 'Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'), - monthsShort : 'Jan._Febr._Mrz._Apr._Mai_Jun._Jul._Aug._Sept._Okt._Nov._Dez.'.split('_'), - weekdays : 'Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag'.split('_'), - weekdaysShort : 'So._Mo._Di._Mi._Do._Fr._Sa.'.split('_'), - weekdaysMin : 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'), - longDateFormat : { - LT: 'HH:mm [Uhr]', - L : 'DD.MM.YYYY', - LL : 'D. MMMM YYYY', - LLL : 'D. MMMM YYYY LT', - LLLL : 'dddd, D. MMMM YYYY LT' - }, - calendar : { - sameDay: '[Heute um] LT', - sameElse: 'L', - nextDay: '[Morgen um] LT', - nextWeek: 'dddd [um] LT', - lastDay: '[Gestern um] LT', - lastWeek: '[letzten] dddd [um] LT' - }, - relativeTime : { - future : 'in %s', - past : 'vor %s', - s : 'ein paar Sekunden', - m : processRelativeTime, - mm : '%d Minuten', - h : processRelativeTime, - hh : '%d Stunden', - d : processRelativeTime, - dd : processRelativeTime, - M : processRelativeTime, - MM : processRelativeTime, - y : processRelativeTime, - yy : processRelativeTime - }, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : modern greek (el) -// author : Aggelos Karalias : https://github.com/mehiel - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('el', { - monthsNominativeEl : 'Ιανουάριος_Φεβρουάριος_Μάρτιος_Απρίλιος_Μάιος_Ιούνιος_Ιούλιος_Αύγουστος_Σεπτέμβριος_Οκτώβριος_Νοέμβριος_Δεκέμβριος'.split('_'), - monthsGenitiveEl : 'Ιανουαρίου_Φεβρουαρίου_Μαρτίου_Απριλίου_Μαΐου_Ιουνίου_Ιουλίου_Αυγούστου_Σεπτεμβρίου_Οκτωβρίου_Νοεμβρίου_Δεκεμβρίου'.split('_'), - months : function (momentToFormat, format) { - if (/D/.test(format.substring(0, format.indexOf('MMMM')))) { // if there is a day number before 'MMMM' - return this._monthsGenitiveEl[momentToFormat.month()]; - } else { - return this._monthsNominativeEl[momentToFormat.month()]; - } - }, - monthsShort : 'Ιαν_Φεβ_Μαρ_Απρ_Μαϊ_Ιουν_Ιουλ_Αυγ_Σεπ_Οκτ_Νοε_Δεκ'.split('_'), - weekdays : 'Κυριακή_Δευτέρα_Τρίτη_Τετάρτη_Πέμπτη_Παρασκευή_Σάββατο'.split('_'), - weekdaysShort : 'Κυρ_Δευ_Τρι_Τετ_Πεμ_Παρ_Σαβ'.split('_'), - weekdaysMin : 'Κυ_Δε_Τρ_Τε_Πε_Πα_Σα'.split('_'), - meridiem : function (hours, minutes, isLower) { - if (hours > 11) { - return isLower ? 'μμ' : 'ΜΜ'; - } else { - return isLower ? 'πμ' : 'ΠΜ'; - } - }, - isPM : function (input) { - return ((input + '').toLowerCase()[0] === 'μ'); - }, - meridiemParse : /[ΠΜ]\.?Μ?\.?/i, - longDateFormat : { - LT : 'h:mm A', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd, D MMMM YYYY LT' - }, - calendarEl : { - sameDay : '[Σήμερα {}] LT', - nextDay : '[Αύριο {}] LT', - nextWeek : 'dddd [{}] LT', - lastDay : '[Χθες {}] LT', - lastWeek : function () { - switch (this.day()) { - case 6: - return '[το προηγούμενο] dddd [{}] LT'; - default: - return '[την προηγούμενη] dddd [{}] LT'; - } - }, - sameElse : 'L' - }, - calendar : function (key, mom) { - var output = this._calendarEl[key], - hours = mom && mom.hours(); - - if (typeof output === 'function') { - output = output.apply(mom); - } - - return output.replace('{}', (hours % 12 === 1 ? 'στη' : 'στις')); - }, - relativeTime : { - future : 'σε %s', - past : '%s πριν', - s : 'δευτερόλεπτα', - m : 'ένα λεπτό', - mm : '%d λεπτά', - h : 'μία ώρα', - hh : '%d ώρες', - d : 'μία μέρα', - dd : '%d μέρες', - M : 'ένας μήνας', - MM : '%d μήνες', - y : 'ένας χρόνος', - yy : '%d χρόνια' - }, - ordinal : function (number) { - return number + 'η'; - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : australian english (en-au) - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('en-au', { - months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'), - monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), - weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), - weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), - weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), - longDateFormat : { - LT : 'h:mm A', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd, D MMMM YYYY LT' - }, - calendar : { - sameDay : '[Today at] LT', - nextDay : '[Tomorrow at] LT', - nextWeek : 'dddd [at] LT', - lastDay : '[Yesterday at] LT', - lastWeek : '[Last] dddd [at] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'in %s', - past : '%s ago', - s : 'a few seconds', - m : 'a minute', - mm : '%d minutes', - h : 'an hour', - hh : '%d hours', - d : 'a day', - dd : '%d days', - M : 'a month', - MM : '%d months', - y : 'a year', - yy : '%d years' - }, - ordinal : function (number) { - var b = number % 10, - output = (~~(number % 100 / 10) === 1) ? 'th' : - (b === 1) ? 'st' : - (b === 2) ? 'nd' : - (b === 3) ? 'rd' : 'th'; - return number + output; - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : canadian english (en-ca) -// author : Jonathan Abourbih : https://github.com/jonbca - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('en-ca', { - months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'), - monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), - weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), - weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), - weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), - longDateFormat : { - LT : 'h:mm A', - L : 'YYYY-MM-DD', - LL : 'D MMMM, YYYY', - LLL : 'D MMMM, YYYY LT', - LLLL : 'dddd, D MMMM, YYYY LT' - }, - calendar : { - sameDay : '[Today at] LT', - nextDay : '[Tomorrow at] LT', - nextWeek : 'dddd [at] LT', - lastDay : '[Yesterday at] LT', - lastWeek : '[Last] dddd [at] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'in %s', - past : '%s ago', - s : 'a few seconds', - m : 'a minute', - mm : '%d minutes', - h : 'an hour', - hh : '%d hours', - d : 'a day', - dd : '%d days', - M : 'a month', - MM : '%d months', - y : 'a year', - yy : '%d years' - }, - ordinal : function (number) { - var b = number % 10, - output = (~~(number % 100 / 10) === 1) ? 'th' : - (b === 1) ? 'st' : - (b === 2) ? 'nd' : - (b === 3) ? 'rd' : 'th'; - return number + output; - } - }); -})); -// moment.js locale configuration -// locale : great britain english (en-gb) -// author : Chris Gedrim : https://github.com/chrisgedrim - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('en-gb', { - months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'), - monthsShort : 'Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec'.split('_'), - weekdays : 'Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday'.split('_'), - weekdaysShort : 'Sun_Mon_Tue_Wed_Thu_Fri_Sat'.split('_'), - weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd, D MMMM YYYY LT' - }, - calendar : { - sameDay : '[Today at] LT', - nextDay : '[Tomorrow at] LT', - nextWeek : 'dddd [at] LT', - lastDay : '[Yesterday at] LT', - lastWeek : '[Last] dddd [at] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'in %s', - past : '%s ago', - s : 'a few seconds', - m : 'a minute', - mm : '%d minutes', - h : 'an hour', - hh : '%d hours', - d : 'a day', - dd : '%d days', - M : 'a month', - MM : '%d months', - y : 'a year', - yy : '%d years' - }, - ordinal : function (number) { - var b = number % 10, - output = (~~(number % 100 / 10) === 1) ? 'th' : - (b === 1) ? 'st' : - (b === 2) ? 'nd' : - (b === 3) ? 'rd' : 'th'; - return number + output; - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : esperanto (eo) -// author : Colin Dean : https://github.com/colindean -// komento: Mi estas malcerta se mi korekte traktis akuzativojn en tiu traduko. -// Se ne, bonvolu korekti kaj avizi min por ke mi povas lerni! - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('eo', { - months : 'januaro_februaro_marto_aprilo_majo_junio_julio_aŭgusto_septembro_oktobro_novembro_decembro'.split('_'), - monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aŭg_sep_okt_nov_dec'.split('_'), - weekdays : 'Dimanĉo_Lundo_Mardo_Merkredo_Ĵaŭdo_Vendredo_Sabato'.split('_'), - weekdaysShort : 'Dim_Lun_Mard_Merk_Ĵaŭ_Ven_Sab'.split('_'), - weekdaysMin : 'Di_Lu_Ma_Me_Ĵa_Ve_Sa'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'YYYY-MM-DD', - LL : 'D[-an de] MMMM, YYYY', - LLL : 'D[-an de] MMMM, YYYY LT', - LLLL : 'dddd, [la] D[-an de] MMMM, YYYY LT' - }, - meridiem : function (hours, minutes, isLower) { - if (hours > 11) { - return isLower ? 'p.t.m.' : 'P.T.M.'; - } else { - return isLower ? 'a.t.m.' : 'A.T.M.'; - } - }, - calendar : { - sameDay : '[Hodiaŭ je] LT', - nextDay : '[Morgaŭ je] LT', - nextWeek : 'dddd [je] LT', - lastDay : '[Hieraŭ je] LT', - lastWeek : '[pasinta] dddd [je] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'je %s', - past : 'antaŭ %s', - s : 'sekundoj', - m : 'minuto', - mm : '%d minutoj', - h : 'horo', - hh : '%d horoj', - d : 'tago',//ne 'diurno', ĉar estas uzita por proksimumo - dd : '%d tagoj', - M : 'monato', - MM : '%d monatoj', - y : 'jaro', - yy : '%d jaroj' - }, - ordinal : '%da', - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : spanish (es) -// author : Julio Napurí : https://github.com/julionc - -(function (factory) { - factory(moment); -}(function (moment) { - var monthsShortDot = 'ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.'.split('_'), - monthsShort = 'ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic'.split('_'); - - return moment.defineLocale('es', { - months : 'enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre'.split('_'), - monthsShort : function (m, format) { - if (/-MMM-/.test(format)) { - return monthsShort[m.month()]; - } else { - return monthsShortDot[m.month()]; - } - }, - weekdays : 'domingo_lunes_martes_miércoles_jueves_viernes_sábado'.split('_'), - weekdaysShort : 'dom._lun._mar._mié._jue._vie._sáb.'.split('_'), - weekdaysMin : 'Do_Lu_Ma_Mi_Ju_Vi_Sá'.split('_'), - longDateFormat : { - LT : 'H:mm', - L : 'DD/MM/YYYY', - LL : 'D [de] MMMM [de] YYYY', - LLL : 'D [de] MMMM [de] YYYY LT', - LLLL : 'dddd, D [de] MMMM [de] YYYY LT' - }, - calendar : { - sameDay : function () { - return '[hoy a la' + ((this.hours() !== 1) ? 's' : '') + '] LT'; - }, - nextDay : function () { - return '[mañana a la' + ((this.hours() !== 1) ? 's' : '') + '] LT'; - }, - nextWeek : function () { - return 'dddd [a la' + ((this.hours() !== 1) ? 's' : '') + '] LT'; - }, - lastDay : function () { - return '[ayer a la' + ((this.hours() !== 1) ? 's' : '') + '] LT'; - }, - lastWeek : function () { - return '[el] dddd [pasado a la' + ((this.hours() !== 1) ? 's' : '') + '] LT'; - }, - sameElse : 'L' - }, - relativeTime : { - future : 'en %s', - past : 'hace %s', - s : 'unos segundos', - m : 'un minuto', - mm : '%d minutos', - h : 'una hora', - hh : '%d horas', - d : 'un día', - dd : '%d días', - M : 'un mes', - MM : '%d meses', - y : 'un año', - yy : '%d años' - }, - ordinal : '%dº', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : estonian (et) -// author : Henry Kehlmann : https://github.com/madhenry -// improvements : Illimar Tambek : https://github.com/ragulka - -(function (factory) { - factory(moment); -}(function (moment) { - function processRelativeTime(number, withoutSuffix, key, isFuture) { - var format = { - 's' : ['mõne sekundi', 'mõni sekund', 'paar sekundit'], - 'm' : ['ühe minuti', 'üks minut'], - 'mm': [number + ' minuti', number + ' minutit'], - 'h' : ['ühe tunni', 'tund aega', 'üks tund'], - 'hh': [number + ' tunni', number + ' tundi'], - 'd' : ['ühe päeva', 'üks päev'], - 'M' : ['kuu aja', 'kuu aega', 'üks kuu'], - 'MM': [number + ' kuu', number + ' kuud'], - 'y' : ['ühe aasta', 'aasta', 'üks aasta'], - 'yy': [number + ' aasta', number + ' aastat'] - }; - if (withoutSuffix) { - return format[key][2] ? format[key][2] : format[key][1]; - } - return isFuture ? format[key][0] : format[key][1]; - } - - return moment.defineLocale('et', { - months : 'jaanuar_veebruar_märts_aprill_mai_juuni_juuli_august_september_oktoober_november_detsember'.split('_'), - monthsShort : 'jaan_veebr_märts_apr_mai_juuni_juuli_aug_sept_okt_nov_dets'.split('_'), - weekdays : 'pühapäev_esmaspäev_teisipäev_kolmapäev_neljapäev_reede_laupäev'.split('_'), - weekdaysShort : 'P_E_T_K_N_R_L'.split('_'), - weekdaysMin : 'P_E_T_K_N_R_L'.split('_'), - longDateFormat : { - LT : 'H:mm', - L : 'DD.MM.YYYY', - LL : 'D. MMMM YYYY', - LLL : 'D. MMMM YYYY LT', - LLLL : 'dddd, D. MMMM YYYY LT' - }, - calendar : { - sameDay : '[Täna,] LT', - nextDay : '[Homme,] LT', - nextWeek : '[Järgmine] dddd LT', - lastDay : '[Eile,] LT', - lastWeek : '[Eelmine] dddd LT', - sameElse : 'L' - }, - relativeTime : { - future : '%s pärast', - past : '%s tagasi', - s : processRelativeTime, - m : processRelativeTime, - mm : processRelativeTime, - h : processRelativeTime, - hh : processRelativeTime, - d : processRelativeTime, - dd : '%d päeva', - M : processRelativeTime, - MM : processRelativeTime, - y : processRelativeTime, - yy : processRelativeTime - }, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : euskara (eu) -// author : Eneko Illarramendi : https://github.com/eillarra - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('eu', { - months : 'urtarrila_otsaila_martxoa_apirila_maiatza_ekaina_uztaila_abuztua_iraila_urria_azaroa_abendua'.split('_'), - monthsShort : 'urt._ots._mar._api._mai._eka._uzt._abu._ira._urr._aza._abe.'.split('_'), - weekdays : 'igandea_astelehena_asteartea_asteazkena_osteguna_ostirala_larunbata'.split('_'), - weekdaysShort : 'ig._al._ar._az._og._ol._lr.'.split('_'), - weekdaysMin : 'ig_al_ar_az_og_ol_lr'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'YYYY-MM-DD', - LL : 'YYYY[ko] MMMM[ren] D[a]', - LLL : 'YYYY[ko] MMMM[ren] D[a] LT', - LLLL : 'dddd, YYYY[ko] MMMM[ren] D[a] LT', - l : 'YYYY-M-D', - ll : 'YYYY[ko] MMM D[a]', - lll : 'YYYY[ko] MMM D[a] LT', - llll : 'ddd, YYYY[ko] MMM D[a] LT' - }, - calendar : { - sameDay : '[gaur] LT[etan]', - nextDay : '[bihar] LT[etan]', - nextWeek : 'dddd LT[etan]', - lastDay : '[atzo] LT[etan]', - lastWeek : '[aurreko] dddd LT[etan]', - sameElse : 'L' - }, - relativeTime : { - future : '%s barru', - past : 'duela %s', - s : 'segundo batzuk', - m : 'minutu bat', - mm : '%d minutu', - h : 'ordu bat', - hh : '%d ordu', - d : 'egun bat', - dd : '%d egun', - M : 'hilabete bat', - MM : '%d hilabete', - y : 'urte bat', - yy : '%d urte' - }, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : Persian (fa) -// author : Ebrahim Byagowi : https://github.com/ebraminio - -(function (factory) { - factory(moment); -}(function (moment) { - var symbolMap = { - '1': '۱', - '2': '۲', - '3': '۳', - '4': '۴', - '5': '۵', - '6': '۶', - '7': '۷', - '8': '۸', - '9': '۹', - '0': '۰' - }, numberMap = { - '۱': '1', - '۲': '2', - '۳': '3', - '۴': '4', - '۵': '5', - '۶': '6', - '۷': '7', - '۸': '8', - '۹': '9', - '۰': '0' - }; - - return moment.defineLocale('fa', { - months : 'ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر'.split('_'), - monthsShort : 'ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر'.split('_'), - weekdays : 'یک\u200cشنبه_دوشنبه_سه\u200cشنبه_چهارشنبه_پنج\u200cشنبه_جمعه_شنبه'.split('_'), - weekdaysShort : 'یک\u200cشنبه_دوشنبه_سه\u200cشنبه_چهارشنبه_پنج\u200cشنبه_جمعه_شنبه'.split('_'), - weekdaysMin : 'ی_د_س_چ_پ_ج_ش'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd, D MMMM YYYY LT' - }, - meridiem : function (hour, minute, isLower) { - if (hour < 12) { - return 'قبل از ظهر'; - } else { - return 'بعد از ظهر'; - } - }, - calendar : { - sameDay : '[امروز ساعت] LT', - nextDay : '[فردا ساعت] LT', - nextWeek : 'dddd [ساعت] LT', - lastDay : '[دیروز ساعت] LT', - lastWeek : 'dddd [پیش] [ساعت] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'در %s', - past : '%s پیش', - s : 'چندین ثانیه', - m : 'یک دقیقه', - mm : '%d دقیقه', - h : 'یک ساعت', - hh : '%d ساعت', - d : 'یک روز', - dd : '%d روز', - M : 'یک ماه', - MM : '%d ماه', - y : 'یک سال', - yy : '%d سال' - }, - preparse: function (string) { - return string.replace(/[۰-۹]/g, function (match) { - return numberMap[match]; - }).replace(/،/g, ','); - }, - postformat: function (string) { - return string.replace(/\d/g, function (match) { - return symbolMap[match]; - }).replace(/,/g, '،'); - }, - ordinal : '%dم', - week : { - dow : 6, // Saturday is the first day of the week. - doy : 12 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : finnish (fi) -// author : Tarmo Aidantausta : https://github.com/bleadof - -(function (factory) { - factory(moment); -}(function (moment) { - var numbersPast = 'nolla yksi kaksi kolme neljä viisi kuusi seitsemän kahdeksan yhdeksän'.split(' '), - numbersFuture = [ - 'nolla', 'yhden', 'kahden', 'kolmen', 'neljän', 'viiden', 'kuuden', - numbersPast[7], numbersPast[8], numbersPast[9] - ]; - - function translate(number, withoutSuffix, key, isFuture) { - var result = ''; - switch (key) { - case 's': - return isFuture ? 'muutaman sekunnin' : 'muutama sekunti'; - case 'm': - return isFuture ? 'minuutin' : 'minuutti'; - case 'mm': - result = isFuture ? 'minuutin' : 'minuuttia'; - break; - case 'h': - return isFuture ? 'tunnin' : 'tunti'; - case 'hh': - result = isFuture ? 'tunnin' : 'tuntia'; - break; - case 'd': - return isFuture ? 'päivän' : 'päivä'; - case 'dd': - result = isFuture ? 'päivän' : 'päivää'; - break; - case 'M': - return isFuture ? 'kuukauden' : 'kuukausi'; - case 'MM': - result = isFuture ? 'kuukauden' : 'kuukautta'; - break; - case 'y': - return isFuture ? 'vuoden' : 'vuosi'; - case 'yy': - result = isFuture ? 'vuoden' : 'vuotta'; - break; - } - result = verbalNumber(number, isFuture) + ' ' + result; - return result; - } - - function verbalNumber(number, isFuture) { - return number < 10 ? (isFuture ? numbersFuture[number] : numbersPast[number]) : number; - } - - return moment.defineLocale('fi', { - months : 'tammikuu_helmikuu_maaliskuu_huhtikuu_toukokuu_kesäkuu_heinäkuu_elokuu_syyskuu_lokakuu_marraskuu_joulukuu'.split('_'), - monthsShort : 'tammi_helmi_maalis_huhti_touko_kesä_heinä_elo_syys_loka_marras_joulu'.split('_'), - weekdays : 'sunnuntai_maanantai_tiistai_keskiviikko_torstai_perjantai_lauantai'.split('_'), - weekdaysShort : 'su_ma_ti_ke_to_pe_la'.split('_'), - weekdaysMin : 'su_ma_ti_ke_to_pe_la'.split('_'), - longDateFormat : { - LT : 'HH.mm', - L : 'DD.MM.YYYY', - LL : 'Do MMMM[ta] YYYY', - LLL : 'Do MMMM[ta] YYYY, [klo] LT', - LLLL : 'dddd, Do MMMM[ta] YYYY, [klo] LT', - l : 'D.M.YYYY', - ll : 'Do MMM YYYY', - lll : 'Do MMM YYYY, [klo] LT', - llll : 'ddd, Do MMM YYYY, [klo] LT' - }, - calendar : { - sameDay : '[tänään] [klo] LT', - nextDay : '[huomenna] [klo] LT', - nextWeek : 'dddd [klo] LT', - lastDay : '[eilen] [klo] LT', - lastWeek : '[viime] dddd[na] [klo] LT', - sameElse : 'L' - }, - relativeTime : { - future : '%s päästä', - past : '%s sitten', - s : translate, - m : translate, - mm : translate, - h : translate, - hh : translate, - d : translate, - dd : translate, - M : translate, - MM : translate, - y : translate, - yy : translate - }, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : faroese (fo) -// author : Ragnar Johannesen : https://github.com/ragnar123 - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('fo', { - months : 'januar_februar_mars_apríl_mai_juni_juli_august_september_oktober_november_desember'.split('_'), - monthsShort : 'jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_'), - weekdays : 'sunnudagur_mánadagur_týsdagur_mikudagur_hósdagur_fríggjadagur_leygardagur'.split('_'), - weekdaysShort : 'sun_mán_týs_mik_hós_frí_ley'.split('_'), - weekdaysMin : 'su_má_tý_mi_hó_fr_le'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd D. MMMM, YYYY LT' - }, - calendar : { - sameDay : '[Í dag kl.] LT', - nextDay : '[Í morgin kl.] LT', - nextWeek : 'dddd [kl.] LT', - lastDay : '[Í gjár kl.] LT', - lastWeek : '[síðstu] dddd [kl] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'um %s', - past : '%s síðani', - s : 'fá sekund', - m : 'ein minutt', - mm : '%d minuttir', - h : 'ein tími', - hh : '%d tímar', - d : 'ein dagur', - dd : '%d dagar', - M : 'ein mánaði', - MM : '%d mánaðir', - y : 'eitt ár', - yy : '%d ár' - }, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : canadian french (fr-ca) -// author : Jonathan Abourbih : https://github.com/jonbca - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('fr-ca', { - months : 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_'), - monthsShort : 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split('_'), - weekdays : 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'), - weekdaysShort : 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'), - weekdaysMin : 'Di_Lu_Ma_Me_Je_Ve_Sa'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'YYYY-MM-DD', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd D MMMM YYYY LT' - }, - calendar : { - sameDay: '[Aujourd\'hui à] LT', - nextDay: '[Demain à] LT', - nextWeek: 'dddd [à] LT', - lastDay: '[Hier à] LT', - lastWeek: 'dddd [dernier à] LT', - sameElse: 'L' - }, - relativeTime : { - future : 'dans %s', - past : 'il y a %s', - s : 'quelques secondes', - m : 'une minute', - mm : '%d minutes', - h : 'une heure', - hh : '%d heures', - d : 'un jour', - dd : '%d jours', - M : 'un mois', - MM : '%d mois', - y : 'un an', - yy : '%d ans' - }, - ordinal : function (number) { - return number + (number === 1 ? 'er' : ''); - } - }); -})); -// moment.js locale configuration -// locale : french (fr) -// author : John Fischer : https://github.com/jfroffice - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('fr', { - months : 'janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre'.split('_'), - monthsShort : 'janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.'.split('_'), - weekdays : 'dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi'.split('_'), - weekdaysShort : 'dim._lun._mar._mer._jeu._ven._sam.'.split('_'), - weekdaysMin : 'Di_Lu_Ma_Me_Je_Ve_Sa'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd D MMMM YYYY LT' - }, - calendar : { - sameDay: '[Aujourd\'hui à] LT', - nextDay: '[Demain à] LT', - nextWeek: 'dddd [à] LT', - lastDay: '[Hier à] LT', - lastWeek: 'dddd [dernier à] LT', - sameElse: 'L' - }, - relativeTime : { - future : 'dans %s', - past : 'il y a %s', - s : 'quelques secondes', - m : 'une minute', - mm : '%d minutes', - h : 'une heure', - hh : '%d heures', - d : 'un jour', - dd : '%d jours', - M : 'un mois', - MM : '%d mois', - y : 'un an', - yy : '%d ans' - }, - ordinal : function (number) { - return number + (number === 1 ? 'er' : ''); - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : galician (gl) -// author : Juan G. Hurtado : https://github.com/juanghurtado - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('gl', { - months : 'Xaneiro_Febreiro_Marzo_Abril_Maio_Xuño_Xullo_Agosto_Setembro_Outubro_Novembro_Decembro'.split('_'), - monthsShort : 'Xan._Feb._Mar._Abr._Mai._Xuñ._Xul._Ago._Set._Out._Nov._Dec.'.split('_'), - weekdays : 'Domingo_Luns_Martes_Mércores_Xoves_Venres_Sábado'.split('_'), - weekdaysShort : 'Dom._Lun._Mar._Mér._Xov._Ven._Sáb.'.split('_'), - weekdaysMin : 'Do_Lu_Ma_Mé_Xo_Ve_Sá'.split('_'), - longDateFormat : { - LT : 'H:mm', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd D MMMM YYYY LT' - }, - calendar : { - sameDay : function () { - return '[hoxe ' + ((this.hours() !== 1) ? 'ás' : 'á') + '] LT'; - }, - nextDay : function () { - return '[mañá ' + ((this.hours() !== 1) ? 'ás' : 'á') + '] LT'; - }, - nextWeek : function () { - return 'dddd [' + ((this.hours() !== 1) ? 'ás' : 'a') + '] LT'; - }, - lastDay : function () { - return '[onte ' + ((this.hours() !== 1) ? 'á' : 'a') + '] LT'; - }, - lastWeek : function () { - return '[o] dddd [pasado ' + ((this.hours() !== 1) ? 'ás' : 'a') + '] LT'; - }, - sameElse : 'L' - }, - relativeTime : { - future : function (str) { - if (str === 'uns segundos') { - return 'nuns segundos'; - } - return 'en ' + str; - }, - past : 'hai %s', - s : 'uns segundos', - m : 'un minuto', - mm : '%d minutos', - h : 'unha hora', - hh : '%d horas', - d : 'un día', - dd : '%d días', - M : 'un mes', - MM : '%d meses', - y : 'un ano', - yy : '%d anos' - }, - ordinal : '%dº', - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : Hebrew (he) -// author : Tomer Cohen : https://github.com/tomer -// author : Moshe Simantov : https://github.com/DevelopmentIL -// author : Tal Ater : https://github.com/TalAter - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('he', { - months : 'ינואר_פברואר_מרץ_אפריל_מאי_יוני_יולי_אוגוסט_ספטמבר_אוקטובר_נובמבר_דצמבר'.split('_'), - monthsShort : 'ינו׳_פבר׳_מרץ_אפר׳_מאי_יוני_יולי_אוג׳_ספט׳_אוק׳_נוב׳_דצמ׳'.split('_'), - weekdays : 'ראשון_שני_שלישי_רביעי_חמישי_שישי_שבת'.split('_'), - weekdaysShort : 'א׳_ב׳_ג׳_ד׳_ה׳_ו׳_ש׳'.split('_'), - weekdaysMin : 'א_ב_ג_ד_ה_ו_ש'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'DD/MM/YYYY', - LL : 'D [ב]MMMM YYYY', - LLL : 'D [ב]MMMM YYYY LT', - LLLL : 'dddd, D [ב]MMMM YYYY LT', - l : 'D/M/YYYY', - ll : 'D MMM YYYY', - lll : 'D MMM YYYY LT', - llll : 'ddd, D MMM YYYY LT' - }, - calendar : { - sameDay : '[היום ב־]LT', - nextDay : '[מחר ב־]LT', - nextWeek : 'dddd [בשעה] LT', - lastDay : '[אתמול ב־]LT', - lastWeek : '[ביום] dddd [האחרון בשעה] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'בעוד %s', - past : 'לפני %s', - s : 'מספר שניות', - m : 'דקה', - mm : '%d דקות', - h : 'שעה', - hh : function (number) { - if (number === 2) { - return 'שעתיים'; - } - return number + ' שעות'; - }, - d : 'יום', - dd : function (number) { - if (number === 2) { - return 'יומיים'; - } - return number + ' ימים'; - }, - M : 'חודש', - MM : function (number) { - if (number === 2) { - return 'חודשיים'; - } - return number + ' חודשים'; - }, - y : 'שנה', - yy : function (number) { - if (number === 2) { - return 'שנתיים'; - } - return number + ' שנים'; - } - } - }); -})); -// moment.js locale configuration -// locale : hindi (hi) -// author : Mayank Singhal : https://github.com/mayanksinghal - -(function (factory) { - factory(moment); -}(function (moment) { - var symbolMap = { - '1': '१', - '2': '२', - '3': '३', - '4': '४', - '5': '५', - '6': '६', - '7': '७', - '8': '८', - '9': '९', - '0': '०' - }, - numberMap = { - '१': '1', - '२': '2', - '३': '3', - '४': '4', - '५': '5', - '६': '6', - '७': '7', - '८': '8', - '९': '9', - '०': '0' - }; - - return moment.defineLocale('hi', { - months : 'जनवरी_फ़रवरी_मार्च_अप्रैल_मई_जून_जुलाई_अगस्त_सितम्बर_अक्टूबर_नवम्बर_दिसम्बर'.split('_'), - monthsShort : 'जन._फ़र._मार्च_अप्रै._मई_जून_जुल._अग._सित._अक्टू._नव._दिस.'.split('_'), - weekdays : 'रविवार_सोमवार_मंगलवार_बुधवार_गुरूवार_शुक्रवार_शनिवार'.split('_'), - weekdaysShort : 'रवि_सोम_मंगल_बुध_गुरू_शुक्र_शनि'.split('_'), - weekdaysMin : 'र_सो_मं_बु_गु_शु_श'.split('_'), - longDateFormat : { - LT : 'A h:mm बजे', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY, LT', - LLLL : 'dddd, D MMMM YYYY, LT' - }, - calendar : { - sameDay : '[आज] LT', - nextDay : '[कल] LT', - nextWeek : 'dddd, LT', - lastDay : '[कल] LT', - lastWeek : '[पिछले] dddd, LT', - sameElse : 'L' - }, - relativeTime : { - future : '%s में', - past : '%s पहले', - s : 'कुछ ही क्षण', - m : 'एक मिनट', - mm : '%d मिनट', - h : 'एक घंटा', - hh : '%d घंटे', - d : 'एक दिन', - dd : '%d दिन', - M : 'एक महीने', - MM : '%d महीने', - y : 'एक वर्ष', - yy : '%d वर्ष' - }, - preparse: function (string) { - return string.replace(/[१२३४५६७८९०]/g, function (match) { - return numberMap[match]; - }); - }, - postformat: function (string) { - return string.replace(/\d/g, function (match) { - return symbolMap[match]; - }); - }, - // Hindi notation for meridiems are quite fuzzy in practice. While there exists - // a rigid notion of a 'Pahar' it is not used as rigidly in modern Hindi. - meridiem : function (hour, minute, isLower) { - if (hour < 4) { - return 'रात'; - } else if (hour < 10) { - return 'सुबह'; - } else if (hour < 17) { - return 'दोपहर'; - } else if (hour < 20) { - return 'शाम'; - } else { - return 'रात'; - } - }, - week : { - dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : hrvatski (hr) -// author : Bojan Marković : https://github.com/bmarkovic - -// based on (sl) translation by Robert Sedovšek - -(function (factory) { - factory(moment); -}(function (moment) { - function translate(number, withoutSuffix, key) { - var result = number + ' '; - switch (key) { - case 'm': - return withoutSuffix ? 'jedna minuta' : 'jedne minute'; - case 'mm': - if (number === 1) { - result += 'minuta'; - } else if (number === 2 || number === 3 || number === 4) { - result += 'minute'; - } else { - result += 'minuta'; - } - return result; - case 'h': - return withoutSuffix ? 'jedan sat' : 'jednog sata'; - case 'hh': - if (number === 1) { - result += 'sat'; - } else if (number === 2 || number === 3 || number === 4) { - result += 'sata'; - } else { - result += 'sati'; - } - return result; - case 'dd': - if (number === 1) { - result += 'dan'; - } else { - result += 'dana'; - } - return result; - case 'MM': - if (number === 1) { - result += 'mjesec'; - } else if (number === 2 || number === 3 || number === 4) { - result += 'mjeseca'; - } else { - result += 'mjeseci'; - } - return result; - case 'yy': - if (number === 1) { - result += 'godina'; - } else if (number === 2 || number === 3 || number === 4) { - result += 'godine'; - } else { - result += 'godina'; - } - return result; - } - } - - return moment.defineLocale('hr', { - months : 'sječanj_veljača_ožujak_travanj_svibanj_lipanj_srpanj_kolovoz_rujan_listopad_studeni_prosinac'.split('_'), - monthsShort : 'sje._vel._ožu._tra._svi._lip._srp._kol._ruj._lis._stu._pro.'.split('_'), - weekdays : 'nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota'.split('_'), - weekdaysShort : 'ned._pon._uto._sri._čet._pet._sub.'.split('_'), - weekdaysMin : 'ne_po_ut_sr_če_pe_su'.split('_'), - longDateFormat : { - LT : 'H:mm', - L : 'DD. MM. YYYY', - LL : 'D. MMMM YYYY', - LLL : 'D. MMMM YYYY LT', - LLLL : 'dddd, D. MMMM YYYY LT' - }, - calendar : { - sameDay : '[danas u] LT', - nextDay : '[sutra u] LT', - - nextWeek : function () { - switch (this.day()) { - case 0: - return '[u] [nedjelju] [u] LT'; - case 3: - return '[u] [srijedu] [u] LT'; - case 6: - return '[u] [subotu] [u] LT'; - case 1: - case 2: - case 4: - case 5: - return '[u] dddd [u] LT'; - } - }, - lastDay : '[jučer u] LT', - lastWeek : function () { - switch (this.day()) { - case 0: - case 3: - return '[prošlu] dddd [u] LT'; - case 6: - return '[prošle] [subote] [u] LT'; - case 1: - case 2: - case 4: - case 5: - return '[prošli] dddd [u] LT'; - } - }, - sameElse : 'L' - }, - relativeTime : { - future : 'za %s', - past : 'prije %s', - s : 'par sekundi', - m : translate, - mm : translate, - h : translate, - hh : translate, - d : 'dan', - dd : translate, - M : 'mjesec', - MM : translate, - y : 'godinu', - yy : translate - }, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : hungarian (hu) -// author : Adam Brunner : https://github.com/adambrunner - -(function (factory) { - factory(moment); -}(function (moment) { - var weekEndings = 'vasárnap hétfőn kedden szerdán csütörtökön pénteken szombaton'.split(' '); - - function translate(number, withoutSuffix, key, isFuture) { - var num = number, - suffix; - - switch (key) { - case 's': - return (isFuture || withoutSuffix) ? 'néhány másodperc' : 'néhány másodperce'; - case 'm': - return 'egy' + (isFuture || withoutSuffix ? ' perc' : ' perce'); - case 'mm': - return num + (isFuture || withoutSuffix ? ' perc' : ' perce'); - case 'h': - return 'egy' + (isFuture || withoutSuffix ? ' óra' : ' órája'); - case 'hh': - return num + (isFuture || withoutSuffix ? ' óra' : ' órája'); - case 'd': - return 'egy' + (isFuture || withoutSuffix ? ' nap' : ' napja'); - case 'dd': - return num + (isFuture || withoutSuffix ? ' nap' : ' napja'); - case 'M': - return 'egy' + (isFuture || withoutSuffix ? ' hónap' : ' hónapja'); - case 'MM': - return num + (isFuture || withoutSuffix ? ' hónap' : ' hónapja'); - case 'y': - return 'egy' + (isFuture || withoutSuffix ? ' év' : ' éve'); - case 'yy': - return num + (isFuture || withoutSuffix ? ' év' : ' éve'); - } - - return ''; - } - - function week(isFuture) { - return (isFuture ? '' : '[múlt] ') + '[' + weekEndings[this.day()] + '] LT[-kor]'; - } - - return moment.defineLocale('hu', { - months : 'január_február_március_április_május_június_július_augusztus_szeptember_október_november_december'.split('_'), - monthsShort : 'jan_feb_márc_ápr_máj_jún_júl_aug_szept_okt_nov_dec'.split('_'), - weekdays : 'vasárnap_hétfő_kedd_szerda_csütörtök_péntek_szombat'.split('_'), - weekdaysShort : 'vas_hét_kedd_sze_csüt_pén_szo'.split('_'), - weekdaysMin : 'v_h_k_sze_cs_p_szo'.split('_'), - longDateFormat : { - LT : 'H:mm', - L : 'YYYY.MM.DD.', - LL : 'YYYY. MMMM D.', - LLL : 'YYYY. MMMM D., LT', - LLLL : 'YYYY. MMMM D., dddd LT' - }, - meridiem : function (hours, minutes, isLower) { - if (hours < 12) { - return isLower === true ? 'de' : 'DE'; - } else { - return isLower === true ? 'du' : 'DU'; - } - }, - calendar : { - sameDay : '[ma] LT[-kor]', - nextDay : '[holnap] LT[-kor]', - nextWeek : function () { - return week.call(this, true); - }, - lastDay : '[tegnap] LT[-kor]', - lastWeek : function () { - return week.call(this, false); - }, - sameElse : 'L' - }, - relativeTime : { - future : '%s múlva', - past : '%s', - s : translate, - m : translate, - mm : translate, - h : translate, - hh : translate, - d : translate, - dd : translate, - M : translate, - MM : translate, - y : translate, - yy : translate - }, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : Armenian (hy-am) -// author : Armendarabyan : https://github.com/armendarabyan - -(function (factory) { - factory(moment); -}(function (moment) { - function monthsCaseReplace(m, format) { - var months = { - 'nominative': 'հունվար_փետրվար_մարտ_ապրիլ_մայիս_հունիս_հուլիս_օգոստոս_սեպտեմբեր_հոկտեմբեր_նոյեմբեր_դեկտեմբեր'.split('_'), - 'accusative': 'հունվարի_փետրվարի_մարտի_ապրիլի_մայիսի_հունիսի_հուլիսի_օգոստոսի_սեպտեմբերի_հոկտեմբերի_նոյեմբերի_դեկտեմբերի'.split('_') - }, - - nounCase = (/D[oD]?(\[[^\[\]]*\]|\s+)+MMMM?/).test(format) ? - 'accusative' : - 'nominative'; - - return months[nounCase][m.month()]; - } - - function monthsShortCaseReplace(m, format) { - var monthsShort = 'հնվ_փտր_մրտ_ապր_մյս_հնս_հլս_օգս_սպտ_հկտ_նմբ_դկտ'.split('_'); - - return monthsShort[m.month()]; - } - - function weekdaysCaseReplace(m, format) { - var weekdays = 'կիրակի_երկուշաբթի_երեքշաբթի_չորեքշաբթի_հինգշաբթի_ուրբաթ_շաբաթ'.split('_'); - - return weekdays[m.day()]; - } - - return moment.defineLocale('hy-am', { - months : monthsCaseReplace, - monthsShort : monthsShortCaseReplace, - weekdays : weekdaysCaseReplace, - weekdaysShort : 'կրկ_երկ_երք_չրք_հնգ_ուրբ_շբթ'.split('_'), - weekdaysMin : 'կրկ_երկ_երք_չրք_հնգ_ուրբ_շբթ'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'DD.MM.YYYY', - LL : 'D MMMM YYYY թ.', - LLL : 'D MMMM YYYY թ., LT', - LLLL : 'dddd, D MMMM YYYY թ., LT' - }, - calendar : { - sameDay: '[այսօր] LT', - nextDay: '[վաղը] LT', - lastDay: '[երեկ] LT', - nextWeek: function () { - return 'dddd [օրը ժամը] LT'; - }, - lastWeek: function () { - return '[անցած] dddd [օրը ժամը] LT'; - }, - sameElse: 'L' - }, - relativeTime : { - future : '%s հետո', - past : '%s առաջ', - s : 'մի քանի վայրկյան', - m : 'րոպե', - mm : '%d րոպե', - h : 'ժամ', - hh : '%d ժամ', - d : 'օր', - dd : '%d օր', - M : 'ամիս', - MM : '%d ամիս', - y : 'տարի', - yy : '%d տարի' - }, - - meridiem : function (hour) { - if (hour < 4) { - return 'գիշերվա'; - } else if (hour < 12) { - return 'առավոտվա'; - } else if (hour < 17) { - return 'ցերեկվա'; - } else { - return 'երեկոյան'; - } - }, - - ordinal: function (number, period) { - switch (period) { - case 'DDD': - case 'w': - case 'W': - case 'DDDo': - if (number === 1) { - return number + '-ին'; - } - return number + '-րդ'; - default: - return number; - } - }, - - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : Bahasa Indonesia (id) -// author : Mohammad Satrio Utomo : https://github.com/tyok -// reference: http://id.wikisource.org/wiki/Pedoman_Umum_Ejaan_Bahasa_Indonesia_yang_Disempurnakan - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('id', { - months : 'Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_November_Desember'.split('_'), - monthsShort : 'Jan_Feb_Mar_Apr_Mei_Jun_Jul_Ags_Sep_Okt_Nov_Des'.split('_'), - weekdays : 'Minggu_Senin_Selasa_Rabu_Kamis_Jumat_Sabtu'.split('_'), - weekdaysShort : 'Min_Sen_Sel_Rab_Kam_Jum_Sab'.split('_'), - weekdaysMin : 'Mg_Sn_Sl_Rb_Km_Jm_Sb'.split('_'), - longDateFormat : { - LT : 'HH.mm', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY [pukul] LT', - LLLL : 'dddd, D MMMM YYYY [pukul] LT' - }, - meridiem : function (hours, minutes, isLower) { - if (hours < 11) { - return 'pagi'; - } else if (hours < 15) { - return 'siang'; - } else if (hours < 19) { - return 'sore'; - } else { - return 'malam'; - } - }, - calendar : { - sameDay : '[Hari ini pukul] LT', - nextDay : '[Besok pukul] LT', - nextWeek : 'dddd [pukul] LT', - lastDay : '[Kemarin pukul] LT', - lastWeek : 'dddd [lalu pukul] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'dalam %s', - past : '%s yang lalu', - s : 'beberapa detik', - m : 'semenit', - mm : '%d menit', - h : 'sejam', - hh : '%d jam', - d : 'sehari', - dd : '%d hari', - M : 'sebulan', - MM : '%d bulan', - y : 'setahun', - yy : '%d tahun' - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : icelandic (is) -// author : Hinrik Örn Sigurðsson : https://github.com/hinrik - -(function (factory) { - factory(moment); -}(function (moment) { - function plural(n) { - if (n % 100 === 11) { - return true; - } else if (n % 10 === 1) { - return false; - } - return true; - } - - function translate(number, withoutSuffix, key, isFuture) { - var result = number + ' '; - switch (key) { - case 's': - return withoutSuffix || isFuture ? 'nokkrar sekúndur' : 'nokkrum sekúndum'; - case 'm': - return withoutSuffix ? 'mínúta' : 'mínútu'; - case 'mm': - if (plural(number)) { - return result + (withoutSuffix || isFuture ? 'mínútur' : 'mínútum'); - } else if (withoutSuffix) { - return result + 'mínúta'; - } - return result + 'mínútu'; - case 'hh': - if (plural(number)) { - return result + (withoutSuffix || isFuture ? 'klukkustundir' : 'klukkustundum'); - } - return result + 'klukkustund'; - case 'd': - if (withoutSuffix) { - return 'dagur'; - } - return isFuture ? 'dag' : 'degi'; - case 'dd': - if (plural(number)) { - if (withoutSuffix) { - return result + 'dagar'; - } - return result + (isFuture ? 'daga' : 'dögum'); - } else if (withoutSuffix) { - return result + 'dagur'; - } - return result + (isFuture ? 'dag' : 'degi'); - case 'M': - if (withoutSuffix) { - return 'mánuður'; - } - return isFuture ? 'mánuð' : 'mánuði'; - case 'MM': - if (plural(number)) { - if (withoutSuffix) { - return result + 'mánuðir'; - } - return result + (isFuture ? 'mánuði' : 'mánuðum'); - } else if (withoutSuffix) { - return result + 'mánuður'; - } - return result + (isFuture ? 'mánuð' : 'mánuði'); - case 'y': - return withoutSuffix || isFuture ? 'ár' : 'ári'; - case 'yy': - if (plural(number)) { - return result + (withoutSuffix || isFuture ? 'ár' : 'árum'); - } - return result + (withoutSuffix || isFuture ? 'ár' : 'ári'); - } - } - - return moment.defineLocale('is', { - months : 'janúar_febrúar_mars_apríl_maí_júní_júlí_ágúst_september_október_nóvember_desember'.split('_'), - monthsShort : 'jan_feb_mar_apr_maí_jún_júl_ágú_sep_okt_nóv_des'.split('_'), - weekdays : 'sunnudagur_mánudagur_þriðjudagur_miðvikudagur_fimmtudagur_föstudagur_laugardagur'.split('_'), - weekdaysShort : 'sun_mán_þri_mið_fim_fös_lau'.split('_'), - weekdaysMin : 'Su_Má_Þr_Mi_Fi_Fö_La'.split('_'), - longDateFormat : { - LT : 'H:mm', - L : 'DD/MM/YYYY', - LL : 'D. MMMM YYYY', - LLL : 'D. MMMM YYYY [kl.] LT', - LLLL : 'dddd, D. MMMM YYYY [kl.] LT' - }, - calendar : { - sameDay : '[í dag kl.] LT', - nextDay : '[á morgun kl.] LT', - nextWeek : 'dddd [kl.] LT', - lastDay : '[í gær kl.] LT', - lastWeek : '[síðasta] dddd [kl.] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'eftir %s', - past : 'fyrir %s síðan', - s : translate, - m : translate, - mm : translate, - h : 'klukkustund', - hh : translate, - d : translate, - dd : translate, - M : translate, - MM : translate, - y : translate, - yy : translate - }, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : italian (it) -// author : Lorenzo : https://github.com/aliem -// author: Mattia Larentis: https://github.com/nostalgiaz - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('it', { - months : 'gennaio_febbraio_marzo_aprile_maggio_giugno_luglio_agosto_settembre_ottobre_novembre_dicembre'.split('_'), - monthsShort : 'gen_feb_mar_apr_mag_giu_lug_ago_set_ott_nov_dic'.split('_'), - weekdays : 'Domenica_Lunedì_Martedì_Mercoledì_Giovedì_Venerdì_Sabato'.split('_'), - weekdaysShort : 'Dom_Lun_Mar_Mer_Gio_Ven_Sab'.split('_'), - weekdaysMin : 'D_L_Ma_Me_G_V_S'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd, D MMMM YYYY LT' - }, - calendar : { - sameDay: '[Oggi alle] LT', - nextDay: '[Domani alle] LT', - nextWeek: 'dddd [alle] LT', - lastDay: '[Ieri alle] LT', - lastWeek: '[lo scorso] dddd [alle] LT', - sameElse: 'L' - }, - relativeTime : { - future : function (s) { - return ((/^[0-9].+$/).test(s) ? 'tra' : 'in') + ' ' + s; - }, - past : '%s fa', - s : 'alcuni secondi', - m : 'un minuto', - mm : '%d minuti', - h : 'un\'ora', - hh : '%d ore', - d : 'un giorno', - dd : '%d giorni', - M : 'un mese', - MM : '%d mesi', - y : 'un anno', - yy : '%d anni' - }, - ordinal: '%dº', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : japanese (ja) -// author : LI Long : https://github.com/baryon - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('ja', { - months : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'), - monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'), - weekdays : '日曜日_月曜日_火曜日_水曜日_木曜日_金曜日_土曜日'.split('_'), - weekdaysShort : '日_月_火_水_木_金_土'.split('_'), - weekdaysMin : '日_月_火_水_木_金_土'.split('_'), - longDateFormat : { - LT : 'Ah時m分', - L : 'YYYY/MM/DD', - LL : 'YYYY年M月D日', - LLL : 'YYYY年M月D日LT', - LLLL : 'YYYY年M月D日LT dddd' - }, - meridiem : function (hour, minute, isLower) { - if (hour < 12) { - return '午前'; - } else { - return '午後'; - } - }, - calendar : { - sameDay : '[今日] LT', - nextDay : '[明日] LT', - nextWeek : '[来週]dddd LT', - lastDay : '[昨日] LT', - lastWeek : '[前週]dddd LT', - sameElse : 'L' - }, - relativeTime : { - future : '%s後', - past : '%s前', - s : '数秒', - m : '1分', - mm : '%d分', - h : '1時間', - hh : '%d時間', - d : '1日', - dd : '%d日', - M : '1ヶ月', - MM : '%dヶ月', - y : '1年', - yy : '%d年' - } - }); -})); -// moment.js locale configuration -// locale : Georgian (ka) -// author : Irakli Janiashvili : https://github.com/irakli-janiashvili - -(function (factory) { - factory(moment); -}(function (moment) { - function monthsCaseReplace(m, format) { - var months = { - 'nominative': 'იანვარი_თებერვალი_მარტი_აპრილი_მაისი_ივნისი_ივლისი_აგვისტო_სექტემბერი_ოქტომბერი_ნოემბერი_დეკემბერი'.split('_'), - 'accusative': 'იანვარს_თებერვალს_მარტს_აპრილის_მაისს_ივნისს_ივლისს_აგვისტს_სექტემბერს_ოქტომბერს_ნოემბერს_დეკემბერს'.split('_') - }, - - nounCase = (/D[oD] *MMMM?/).test(format) ? - 'accusative' : - 'nominative'; - - return months[nounCase][m.month()]; - } - - function weekdaysCaseReplace(m, format) { - var weekdays = { - 'nominative': 'კვირა_ორშაბათი_სამშაბათი_ოთხშაბათი_ხუთშაბათი_პარასკევი_შაბათი'.split('_'), - 'accusative': 'კვირას_ორშაბათს_სამშაბათს_ოთხშაბათს_ხუთშაბათს_პარასკევს_შაბათს'.split('_') - }, - - nounCase = (/(წინა|შემდეგ)/).test(format) ? - 'accusative' : - 'nominative'; - - return weekdays[nounCase][m.day()]; - } - - return moment.defineLocale('ka', { - months : monthsCaseReplace, - monthsShort : 'იან_თებ_მარ_აპრ_მაი_ივნ_ივლ_აგვ_სექ_ოქტ_ნოე_დეკ'.split('_'), - weekdays : weekdaysCaseReplace, - weekdaysShort : 'კვი_ორშ_სამ_ოთხ_ხუთ_პარ_შაბ'.split('_'), - weekdaysMin : 'კვ_ორ_სა_ოთ_ხუ_პა_შა'.split('_'), - longDateFormat : { - LT : 'h:mm A', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd, D MMMM YYYY LT' - }, - calendar : { - sameDay : '[დღეს] LT[-ზე]', - nextDay : '[ხვალ] LT[-ზე]', - lastDay : '[გუშინ] LT[-ზე]', - nextWeek : '[შემდეგ] dddd LT[-ზე]', - lastWeek : '[წინა] dddd LT-ზე', - sameElse : 'L' - }, - relativeTime : { - future : function (s) { - return (/(წამი|წუთი|საათი|წელი)/).test(s) ? - s.replace(/ი$/, 'ში') : - s + 'ში'; - }, - past : function (s) { - if ((/(წამი|წუთი|საათი|დღე|თვე)/).test(s)) { - return s.replace(/(ი|ე)$/, 'ის წინ'); - } - if ((/წელი/).test(s)) { - return s.replace(/წელი$/, 'წლის წინ'); - } - }, - s : 'რამდენიმე წამი', - m : 'წუთი', - mm : '%d წუთი', - h : 'საათი', - hh : '%d საათი', - d : 'დღე', - dd : '%d დღე', - M : 'თვე', - MM : '%d თვე', - y : 'წელი', - yy : '%d წელი' - }, - ordinal : function (number) { - if (number === 0) { - return number; - } - - if (number === 1) { - return number + '-ლი'; - } - - if ((number < 20) || (number <= 100 && (number % 20 === 0)) || (number % 100 === 0)) { - return 'მე-' + number; - } - - return number + '-ე'; - }, - week : { - dow : 1, - doy : 7 - } - }); -})); -// moment.js locale configuration -// locale : khmer (km) -// author : Kruy Vanna : https://github.com/kruyvanna - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('km', { - months: 'មករា_កុម្ភៈ_មិនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ'.split('_'), - monthsShort: 'មករា_កុម្ភៈ_មិនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ'.split('_'), - weekdays: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'), - weekdaysShort: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'), - weekdaysMin: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'), - longDateFormat: { - LT: 'HH:mm', - L: 'DD/MM/YYYY', - LL: 'D MMMM YYYY', - LLL: 'D MMMM YYYY LT', - LLLL: 'dddd, D MMMM YYYY LT' - }, - calendar: { - sameDay: '[ថ្ងៃនៈ ម៉ោង] LT', - nextDay: '[ស្អែក ម៉ោង] LT', - nextWeek: 'dddd [ម៉ោង] LT', - lastDay: '[ម្សិលមិញ ម៉ោង] LT', - lastWeek: 'dddd [សប្តាហ៍មុន] [ម៉ោង] LT', - sameElse: 'L' - }, - relativeTime: { - future: '%sទៀត', - past: '%sមុន', - s: 'ប៉ុន្មានវិនាទី', - m: 'មួយនាទី', - mm: '%d នាទី', - h: 'មួយម៉ោង', - hh: '%d ម៉ោង', - d: 'មួយថ្ងៃ', - dd: '%d ថ្ងៃ', - M: 'មួយខែ', - MM: '%d ខែ', - y: 'មួយឆ្នាំ', - yy: '%d ឆ្នាំ' - }, - week: { - dow: 1, // Monday is the first day of the week. - doy: 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : korean (ko) -// -// authors -// -// - Kyungwook, Park : https://github.com/kyungw00k -// - Jeeeyul Lee -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('ko', { - months : '1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월'.split('_'), - monthsShort : '1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월'.split('_'), - weekdays : '일요일_월요일_화요일_수요일_목요일_금요일_토요일'.split('_'), - weekdaysShort : '일_월_화_수_목_금_토'.split('_'), - weekdaysMin : '일_월_화_수_목_금_토'.split('_'), - longDateFormat : { - LT : 'A h시 m분', - L : 'YYYY.MM.DD', - LL : 'YYYY년 MMMM D일', - LLL : 'YYYY년 MMMM D일 LT', - LLLL : 'YYYY년 MMMM D일 dddd LT' - }, - meridiem : function (hour, minute, isUpper) { - return hour < 12 ? '오전' : '오후'; - }, - calendar : { - sameDay : '오늘 LT', - nextDay : '내일 LT', - nextWeek : 'dddd LT', - lastDay : '어제 LT', - lastWeek : '지난주 dddd LT', - sameElse : 'L' - }, - relativeTime : { - future : '%s 후', - past : '%s 전', - s : '몇초', - ss : '%d초', - m : '일분', - mm : '%d분', - h : '한시간', - hh : '%d시간', - d : '하루', - dd : '%d일', - M : '한달', - MM : '%d달', - y : '일년', - yy : '%d년' - }, - ordinal : '%d일', - meridiemParse : /(오전|오후)/, - isPM : function (token) { - return token === '오후'; - } - }); -})); -// moment.js locale configuration -// locale : Luxembourgish (lb) -// author : mweimerskirch : https://github.com/mweimerskirch, David Raison : https://github.com/kwisatz - -// Note: Luxembourgish has a very particular phonological rule ('Eifeler Regel') that causes the -// deletion of the final 'n' in certain contexts. That's what the 'eifelerRegelAppliesToWeekday' -// and 'eifelerRegelAppliesToNumber' methods are meant for - -(function (factory) { - factory(moment); -}(function (moment) { - function processRelativeTime(number, withoutSuffix, key, isFuture) { - var format = { - 'm': ['eng Minutt', 'enger Minutt'], - 'h': ['eng Stonn', 'enger Stonn'], - 'd': ['een Dag', 'engem Dag'], - 'M': ['ee Mount', 'engem Mount'], - 'y': ['ee Joer', 'engem Joer'] - }; - return withoutSuffix ? format[key][0] : format[key][1]; - } - - function processFutureTime(string) { - var number = string.substr(0, string.indexOf(' ')); - if (eifelerRegelAppliesToNumber(number)) { - return 'a ' + string; - } - return 'an ' + string; - } - - function processPastTime(string) { - var number = string.substr(0, string.indexOf(' ')); - if (eifelerRegelAppliesToNumber(number)) { - return 'viru ' + string; - } - return 'virun ' + string; - } - - /** - * Returns true if the word before the given number loses the '-n' ending. - * e.g. 'an 10 Deeg' but 'a 5 Deeg' - * - * @param number {integer} - * @returns {boolean} - */ - function eifelerRegelAppliesToNumber(number) { - number = parseInt(number, 10); - if (isNaN(number)) { - return false; - } - if (number < 0) { - // Negative Number --> always true - return true; - } else if (number < 10) { - // Only 1 digit - if (4 <= number && number <= 7) { - return true; - } - return false; - } else if (number < 100) { - // 2 digits - var lastDigit = number % 10, firstDigit = number / 10; - if (lastDigit === 0) { - return eifelerRegelAppliesToNumber(firstDigit); - } - return eifelerRegelAppliesToNumber(lastDigit); - } else if (number < 10000) { - // 3 or 4 digits --> recursively check first digit - while (number >= 10) { - number = number / 10; - } - return eifelerRegelAppliesToNumber(number); - } else { - // Anything larger than 4 digits: recursively check first n-3 digits - number = number / 1000; - return eifelerRegelAppliesToNumber(number); - } - } - - return moment.defineLocale('lb', { - months: 'Januar_Februar_Mäerz_Abrëll_Mee_Juni_Juli_August_September_Oktober_November_Dezember'.split('_'), - monthsShort: 'Jan._Febr._Mrz._Abr._Mee_Jun._Jul._Aug._Sept._Okt._Nov._Dez.'.split('_'), - weekdays: 'Sonndeg_Méindeg_Dënschdeg_Mëttwoch_Donneschdeg_Freideg_Samschdeg'.split('_'), - weekdaysShort: 'So._Mé._Dë._Më._Do._Fr._Sa.'.split('_'), - weekdaysMin: 'So_Mé_Dë_Më_Do_Fr_Sa'.split('_'), - longDateFormat: { - LT: 'H:mm [Auer]', - L: 'DD.MM.YYYY', - LL: 'D. MMMM YYYY', - LLL: 'D. MMMM YYYY LT', - LLLL: 'dddd, D. MMMM YYYY LT' - }, - calendar: { - sameDay: '[Haut um] LT', - sameElse: 'L', - nextDay: '[Muer um] LT', - nextWeek: 'dddd [um] LT', - lastDay: '[Gëschter um] LT', - lastWeek: function () { - // Different date string for 'Dënschdeg' (Tuesday) and 'Donneschdeg' (Thursday) due to phonological rule - switch (this.day()) { - case 2: - case 4: - return '[Leschten] dddd [um] LT'; - default: - return '[Leschte] dddd [um] LT'; - } - } - }, - relativeTime : { - future : processFutureTime, - past : processPastTime, - s : 'e puer Sekonnen', - m : processRelativeTime, - mm : '%d Minutten', - h : processRelativeTime, - hh : '%d Stonnen', - d : processRelativeTime, - dd : '%d Deeg', - M : processRelativeTime, - MM : '%d Méint', - y : processRelativeTime, - yy : '%d Joer' - }, - ordinal: '%d.', - week: { - dow: 1, // Monday is the first day of the week. - doy: 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : Lithuanian (lt) -// author : Mindaugas Mozūras : https://github.com/mmozuras - -(function (factory) { - factory(moment); -}(function (moment) { - var units = { - 'm' : 'minutė_minutės_minutę', - 'mm': 'minutės_minučių_minutes', - 'h' : 'valanda_valandos_valandą', - 'hh': 'valandos_valandų_valandas', - 'd' : 'diena_dienos_dieną', - 'dd': 'dienos_dienų_dienas', - 'M' : 'mėnuo_mėnesio_mėnesį', - 'MM': 'mėnesiai_mėnesių_mėnesius', - 'y' : 'metai_metų_metus', - 'yy': 'metai_metų_metus' - }, - weekDays = 'sekmadienis_pirmadienis_antradienis_trečiadienis_ketvirtadienis_penktadienis_šeštadienis'.split('_'); - - function translateSeconds(number, withoutSuffix, key, isFuture) { - if (withoutSuffix) { - return 'kelios sekundės'; - } else { - return isFuture ? 'kelių sekundžių' : 'kelias sekundes'; - } - } - - function translateSingular(number, withoutSuffix, key, isFuture) { - return withoutSuffix ? forms(key)[0] : (isFuture ? forms(key)[1] : forms(key)[2]); - } - - function special(number) { - return number % 10 === 0 || (number > 10 && number < 20); - } - - function forms(key) { - return units[key].split('_'); - } - - function translate(number, withoutSuffix, key, isFuture) { - var result = number + ' '; - if (number === 1) { - return result + translateSingular(number, withoutSuffix, key[0], isFuture); - } else if (withoutSuffix) { - return result + (special(number) ? forms(key)[1] : forms(key)[0]); - } else { - if (isFuture) { - return result + forms(key)[1]; - } else { - return result + (special(number) ? forms(key)[1] : forms(key)[2]); - } - } - } - - function relativeWeekDay(moment, format) { - var nominative = format.indexOf('dddd HH:mm') === -1, - weekDay = weekDays[moment.day()]; - - return nominative ? weekDay : weekDay.substring(0, weekDay.length - 2) + 'į'; - } - - return moment.defineLocale('lt', { - months : 'sausio_vasario_kovo_balandžio_gegužės_birželio_liepos_rugpjūčio_rugsėjo_spalio_lapkričio_gruodžio'.split('_'), - monthsShort : 'sau_vas_kov_bal_geg_bir_lie_rgp_rgs_spa_lap_grd'.split('_'), - weekdays : relativeWeekDay, - weekdaysShort : 'Sek_Pir_Ant_Tre_Ket_Pen_Šeš'.split('_'), - weekdaysMin : 'S_P_A_T_K_Pn_Š'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'YYYY-MM-DD', - LL : 'YYYY [m.] MMMM D [d.]', - LLL : 'YYYY [m.] MMMM D [d.], LT [val.]', - LLLL : 'YYYY [m.] MMMM D [d.], dddd, LT [val.]', - l : 'YYYY-MM-DD', - ll : 'YYYY [m.] MMMM D [d.]', - lll : 'YYYY [m.] MMMM D [d.], LT [val.]', - llll : 'YYYY [m.] MMMM D [d.], ddd, LT [val.]' - }, - calendar : { - sameDay : '[Šiandien] LT', - nextDay : '[Rytoj] LT', - nextWeek : 'dddd LT', - lastDay : '[Vakar] LT', - lastWeek : '[Praėjusį] dddd LT', - sameElse : 'L' - }, - relativeTime : { - future : 'po %s', - past : 'prieš %s', - s : translateSeconds, - m : translateSingular, - mm : translate, - h : translateSingular, - hh : translate, - d : translateSingular, - dd : translate, - M : translateSingular, - MM : translate, - y : translateSingular, - yy : translate - }, - ordinal : function (number) { - return number + '-oji'; - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : latvian (lv) -// author : Kristaps Karlsons : https://github.com/skakri - -(function (factory) { - factory(moment); -}(function (moment) { - var units = { - 'mm': 'minūti_minūtes_minūte_minūtes', - 'hh': 'stundu_stundas_stunda_stundas', - 'dd': 'dienu_dienas_diena_dienas', - 'MM': 'mēnesi_mēnešus_mēnesis_mēneši', - 'yy': 'gadu_gadus_gads_gadi' - }; - - function format(word, number, withoutSuffix) { - var forms = word.split('_'); - if (withoutSuffix) { - return number % 10 === 1 && number !== 11 ? forms[2] : forms[3]; - } else { - return number % 10 === 1 && number !== 11 ? forms[0] : forms[1]; - } - } - - function relativeTimeWithPlural(number, withoutSuffix, key) { - return number + ' ' + format(units[key], number, withoutSuffix); - } - - return moment.defineLocale('lv', { - months : 'janvāris_februāris_marts_aprīlis_maijs_jūnijs_jūlijs_augusts_septembris_oktobris_novembris_decembris'.split('_'), - monthsShort : 'jan_feb_mar_apr_mai_jūn_jūl_aug_sep_okt_nov_dec'.split('_'), - weekdays : 'svētdiena_pirmdiena_otrdiena_trešdiena_ceturtdiena_piektdiena_sestdiena'.split('_'), - weekdaysShort : 'Sv_P_O_T_C_Pk_S'.split('_'), - weekdaysMin : 'Sv_P_O_T_C_Pk_S'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'DD.MM.YYYY', - LL : 'YYYY. [gada] D. MMMM', - LLL : 'YYYY. [gada] D. MMMM, LT', - LLLL : 'YYYY. [gada] D. MMMM, dddd, LT' - }, - calendar : { - sameDay : '[Šodien pulksten] LT', - nextDay : '[Rīt pulksten] LT', - nextWeek : 'dddd [pulksten] LT', - lastDay : '[Vakar pulksten] LT', - lastWeek : '[Pagājušā] dddd [pulksten] LT', - sameElse : 'L' - }, - relativeTime : { - future : '%s vēlāk', - past : '%s agrāk', - s : 'dažas sekundes', - m : 'minūti', - mm : relativeTimeWithPlural, - h : 'stundu', - hh : relativeTimeWithPlural, - d : 'dienu', - dd : relativeTimeWithPlural, - M : 'mēnesi', - MM : relativeTimeWithPlural, - y : 'gadu', - yy : relativeTimeWithPlural - }, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : macedonian (mk) -// author : Borislav Mickov : https://github.com/B0k0 - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('mk', { - months : 'јануари_февруари_март_април_мај_јуни_јули_август_септември_октомври_ноември_декември'.split('_'), - monthsShort : 'јан_фев_мар_апр_мај_јун_јул_авг_сеп_окт_ное_дек'.split('_'), - weekdays : 'недела_понеделник_вторник_среда_четврток_петок_сабота'.split('_'), - weekdaysShort : 'нед_пон_вто_сре_чет_пет_саб'.split('_'), - weekdaysMin : 'нe_пo_вт_ср_че_пе_сa'.split('_'), - longDateFormat : { - LT : 'H:mm', - L : 'D.MM.YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd, D MMMM YYYY LT' - }, - calendar : { - sameDay : '[Денес во] LT', - nextDay : '[Утре во] LT', - nextWeek : 'dddd [во] LT', - lastDay : '[Вчера во] LT', - lastWeek : function () { - switch (this.day()) { - case 0: - case 3: - case 6: - return '[Во изминатата] dddd [во] LT'; - case 1: - case 2: - case 4: - case 5: - return '[Во изминатиот] dddd [во] LT'; - } - }, - sameElse : 'L' - }, - relativeTime : { - future : 'после %s', - past : 'пред %s', - s : 'неколку секунди', - m : 'минута', - mm : '%d минути', - h : 'час', - hh : '%d часа', - d : 'ден', - dd : '%d дена', - M : 'месец', - MM : '%d месеци', - y : 'година', - yy : '%d години' - }, - ordinal : function (number) { - var lastDigit = number % 10, - last2Digits = number % 100; - if (number === 0) { - return number + '-ев'; - } else if (last2Digits === 0) { - return number + '-ен'; - } else if (last2Digits > 10 && last2Digits < 20) { - return number + '-ти'; - } else if (lastDigit === 1) { - return number + '-ви'; - } else if (lastDigit === 2) { - return number + '-ри'; - } else if (lastDigit === 7 || lastDigit === 8) { - return number + '-ми'; - } else { - return number + '-ти'; - } - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : malayalam (ml) -// author : Floyd Pink : https://github.com/floydpink - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('ml', { - months : 'ജനുവരി_ഫെബ്രുവരി_മാർച്ച്_ഏപ്രിൽ_മേയ്_ജൂൺ_ജൂലൈ_ഓഗസ്റ്റ്_സെപ്റ്റംബർ_ഒക്ടോബർ_നവംബർ_ഡിസംബർ'.split('_'), - monthsShort : 'ജനു._ഫെബ്രു._മാർ._ഏപ്രി._മേയ്_ജൂൺ_ജൂലൈ._ഓഗ._സെപ്റ്റ._ഒക്ടോ._നവം._ഡിസം.'.split('_'), - weekdays : 'ഞായറാഴ്ച_തിങ്കളാഴ്ച_ചൊവ്വാഴ്ച_ബുധനാഴ്ച_വ്യാഴാഴ്ച_വെള്ളിയാഴ്ച_ശനിയാഴ്ച'.split('_'), - weekdaysShort : 'ഞായർ_തിങ്കൾ_ചൊവ്വ_ബുധൻ_വ്യാഴം_വെള്ളി_ശനി'.split('_'), - weekdaysMin : 'ഞാ_തി_ചൊ_ബു_വ്യാ_വെ_ശ'.split('_'), - longDateFormat : { - LT : 'A h:mm -നു', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY, LT', - LLLL : 'dddd, D MMMM YYYY, LT' - }, - calendar : { - sameDay : '[ഇന്ന്] LT', - nextDay : '[നാളെ] LT', - nextWeek : 'dddd, LT', - lastDay : '[ഇന്നലെ] LT', - lastWeek : '[കഴിഞ്ഞ] dddd, LT', - sameElse : 'L' - }, - relativeTime : { - future : '%s കഴിഞ്ഞ്', - past : '%s മുൻപ്', - s : 'അൽപ നിമിഷങ്ങൾ', - m : 'ഒരു മിനിറ്റ്', - mm : '%d മിനിറ്റ്', - h : 'ഒരു മണിക്കൂർ', - hh : '%d മണിക്കൂർ', - d : 'ഒരു ദിവസം', - dd : '%d ദിവസം', - M : 'ഒരു മാസം', - MM : '%d മാസം', - y : 'ഒരു വർഷം', - yy : '%d വർഷം' - }, - meridiem : function (hour, minute, isLower) { - if (hour < 4) { - return 'രാത്രി'; - } else if (hour < 12) { - return 'രാവിലെ'; - } else if (hour < 17) { - return 'ഉച്ച കഴിഞ്ഞ്'; - } else if (hour < 20) { - return 'വൈകുന്നേരം'; - } else { - return 'രാത്രി'; - } - } - }); -})); -// moment.js locale configuration -// locale : Marathi (mr) -// author : Harshad Kale : https://github.com/kalehv - -(function (factory) { - factory(moment); -}(function (moment) { - var symbolMap = { - '1': '१', - '2': '२', - '3': '३', - '4': '४', - '5': '५', - '6': '६', - '7': '७', - '8': '८', - '9': '९', - '0': '०' - }, - numberMap = { - '१': '1', - '२': '2', - '३': '3', - '४': '4', - '५': '5', - '६': '6', - '७': '7', - '८': '8', - '९': '9', - '०': '0' - }; - - return moment.defineLocale('mr', { - months : 'जानेवारी_फेब्रुवारी_मार्च_एप्रिल_मे_जून_जुलै_ऑगस्ट_सप्टेंबर_ऑक्टोबर_नोव्हेंबर_डिसेंबर'.split('_'), - monthsShort: 'जाने._फेब्रु._मार्च._एप्रि._मे._जून._जुलै._ऑग._सप्टें._ऑक्टो._नोव्हें._डिसें.'.split('_'), - weekdays : 'रविवार_सोमवार_मंगळवार_बुधवार_गुरूवार_शुक्रवार_शनिवार'.split('_'), - weekdaysShort : 'रवि_सोम_मंगळ_बुध_गुरू_शुक्र_शनि'.split('_'), - weekdaysMin : 'र_सो_मं_बु_गु_शु_श'.split('_'), - longDateFormat : { - LT : 'A h:mm वाजता', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY, LT', - LLLL : 'dddd, D MMMM YYYY, LT' - }, - calendar : { - sameDay : '[आज] LT', - nextDay : '[उद्या] LT', - nextWeek : 'dddd, LT', - lastDay : '[काल] LT', - lastWeek: '[मागील] dddd, LT', - sameElse : 'L' - }, - relativeTime : { - future : '%s नंतर', - past : '%s पूर्वी', - s : 'सेकंद', - m: 'एक मिनिट', - mm: '%d मिनिटे', - h : 'एक तास', - hh : '%d तास', - d : 'एक दिवस', - dd : '%d दिवस', - M : 'एक महिना', - MM : '%d महिने', - y : 'एक वर्ष', - yy : '%d वर्षे' - }, - preparse: function (string) { - return string.replace(/[१२३४५६७८९०]/g, function (match) { - return numberMap[match]; - }); - }, - postformat: function (string) { - return string.replace(/\d/g, function (match) { - return symbolMap[match]; - }); - }, - meridiem: function (hour, minute, isLower) - { - if (hour < 4) { - return 'रात्री'; - } else if (hour < 10) { - return 'सकाळी'; - } else if (hour < 17) { - return 'दुपारी'; - } else if (hour < 20) { - return 'सायंकाळी'; - } else { - return 'रात्री'; - } - }, - week : { - dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : Bahasa Malaysia (ms-MY) -// author : Weldan Jamili : https://github.com/weldan - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('ms-my', { - months : 'Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember'.split('_'), - monthsShort : 'Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis'.split('_'), - weekdays : 'Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu'.split('_'), - weekdaysShort : 'Ahd_Isn_Sel_Rab_Kha_Jum_Sab'.split('_'), - weekdaysMin : 'Ah_Is_Sl_Rb_Km_Jm_Sb'.split('_'), - longDateFormat : { - LT : 'HH.mm', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY [pukul] LT', - LLLL : 'dddd, D MMMM YYYY [pukul] LT' - }, - meridiem : function (hours, minutes, isLower) { - if (hours < 11) { - return 'pagi'; - } else if (hours < 15) { - return 'tengahari'; - } else if (hours < 19) { - return 'petang'; - } else { - return 'malam'; - } - }, - calendar : { - sameDay : '[Hari ini pukul] LT', - nextDay : '[Esok pukul] LT', - nextWeek : 'dddd [pukul] LT', - lastDay : '[Kelmarin pukul] LT', - lastWeek : 'dddd [lepas pukul] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'dalam %s', - past : '%s yang lepas', - s : 'beberapa saat', - m : 'seminit', - mm : '%d minit', - h : 'sejam', - hh : '%d jam', - d : 'sehari', - dd : '%d hari', - M : 'sebulan', - MM : '%d bulan', - y : 'setahun', - yy : '%d tahun' - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : Burmese (my) -// author : Squar team, mysquar.com - -(function (factory) { - factory(moment); -}(function (moment) { - var symbolMap = { - '1': '၁', - '2': '၂', - '3': '၃', - '4': '၄', - '5': '၅', - '6': '၆', - '7': '၇', - '8': '၈', - '9': '၉', - '0': '၀' - }, numberMap = { - '၁': '1', - '၂': '2', - '၃': '3', - '၄': '4', - '၅': '5', - '၆': '6', - '၇': '7', - '၈': '8', - '၉': '9', - '၀': '0' - }; - return moment.defineLocale('my', { - months: 'ဇန်နဝါရီ_ဖေဖော်ဝါရီ_မတ်_ဧပြီ_မေ_ဇွန်_ဇူလိုင်_သြဂုတ်_စက်တင်ဘာ_အောက်တိုဘာ_နိုဝင်ဘာ_ဒီဇင်ဘာ'.split('_'), - monthsShort: 'ဇန်_ဖေ_မတ်_ပြီ_မေ_ဇွန်_လိုင်_သြ_စက်_အောက်_နို_ဒီ'.split('_'), - weekdays: 'တနင်္ဂနွေ_တနင်္လာ_အင်္ဂါ_ဗုဒ္ဓဟူး_ကြာသပတေး_သောကြာ_စနေ'.split('_'), - weekdaysShort: 'နွေ_လာ_င်္ဂါ_ဟူး_ကြာ_သော_နေ'.split('_'), - weekdaysMin: 'နွေ_လာ_င်္ဂါ_ဟူး_ကြာ_သော_နေ'.split('_'), - longDateFormat: { - LT: 'HH:mm', - L: 'DD/MM/YYYY', - LL: 'D MMMM YYYY', - LLL: 'D MMMM YYYY LT', - LLLL: 'dddd D MMMM YYYY LT' - }, - calendar: { - sameDay: '[ယနေ.] LT [မှာ]', - nextDay: '[မနက်ဖြန်] LT [မှာ]', - nextWeek: 'dddd LT [မှာ]', - lastDay: '[မနေ.က] LT [မှာ]', - lastWeek: '[ပြီးခဲ့သော] dddd LT [မှာ]', - sameElse: 'L' - }, - relativeTime: { - future: 'လာမည့် %s မှာ', - past: 'လွန်ခဲ့သော %s က', - s: 'စက္ကန်.အနည်းငယ်', - m: 'တစ်မိနစ်', - mm: '%d မိနစ်', - h: 'တစ်နာရီ', - hh: '%d နာရီ', - d: 'တစ်ရက်', - dd: '%d ရက်', - M: 'တစ်လ', - MM: '%d လ', - y: 'တစ်နှစ်', - yy: '%d နှစ်' - }, - preparse: function (string) { - return string.replace(/[၁၂၃၄၅၆၇၈၉၀]/g, function (match) { - return numberMap[match]; - }); - }, - postformat: function (string) { - return string.replace(/\d/g, function (match) { - return symbolMap[match]; - }); - }, - week: { - dow: 1, // Monday is the first day of the week. - doy: 4 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : norwegian bokmål (nb) -// authors : Espen Hovlandsdal : https://github.com/rexxars -// Sigurd Gartmann : https://github.com/sigurdga - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('nb', { - months : 'januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember'.split('_'), - monthsShort : 'jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_'), - weekdays : 'søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag'.split('_'), - weekdaysShort : 'søn_man_tirs_ons_tors_fre_lør'.split('_'), - weekdaysMin : 'sø_ma_ti_on_to_fr_lø'.split('_'), - longDateFormat : { - LT : 'H.mm', - L : 'DD.MM.YYYY', - LL : 'D. MMMM YYYY', - LLL : 'D. MMMM YYYY [kl.] LT', - LLLL : 'dddd D. MMMM YYYY [kl.] LT' - }, - calendar : { - sameDay: '[i dag kl.] LT', - nextDay: '[i morgen kl.] LT', - nextWeek: 'dddd [kl.] LT', - lastDay: '[i går kl.] LT', - lastWeek: '[forrige] dddd [kl.] LT', - sameElse: 'L' - }, - relativeTime : { - future : 'om %s', - past : 'for %s siden', - s : 'noen sekunder', - m : 'ett minutt', - mm : '%d minutter', - h : 'en time', - hh : '%d timer', - d : 'en dag', - dd : '%d dager', - M : 'en måned', - MM : '%d måneder', - y : 'ett år', - yy : '%d år' - }, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : nepali/nepalese -// author : suvash : https://github.com/suvash - -(function (factory) { - factory(moment); -}(function (moment) { - var symbolMap = { - '1': '१', - '2': '२', - '3': '३', - '4': '४', - '5': '५', - '6': '६', - '7': '७', - '8': '८', - '9': '९', - '0': '०' - }, - numberMap = { - '१': '1', - '२': '2', - '३': '3', - '४': '4', - '५': '5', - '६': '6', - '७': '7', - '८': '8', - '९': '9', - '०': '0' - }; - - return moment.defineLocale('ne', { - months : 'जनवरी_फेब्रुवरी_मार्च_अप्रिल_मई_जुन_जुलाई_अगष्ट_सेप्टेम्बर_अक्टोबर_नोभेम्बर_डिसेम्बर'.split('_'), - monthsShort : 'जन._फेब्रु._मार्च_अप्रि._मई_जुन_जुलाई._अग._सेप्ट._अक्टो._नोभे._डिसे.'.split('_'), - weekdays : 'आइतबार_सोमबार_मङ्गलबार_बुधबार_बिहिबार_शुक्रबार_शनिबार'.split('_'), - weekdaysShort : 'आइत._सोम._मङ्गल._बुध._बिहि._शुक्र._शनि.'.split('_'), - weekdaysMin : 'आइ._सो._मङ्_बु._बि._शु._श.'.split('_'), - longDateFormat : { - LT : 'Aको h:mm बजे', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY, LT', - LLLL : 'dddd, D MMMM YYYY, LT' - }, - preparse: function (string) { - return string.replace(/[१२३४५६७८९०]/g, function (match) { - return numberMap[match]; - }); - }, - postformat: function (string) { - return string.replace(/\d/g, function (match) { - return symbolMap[match]; - }); - }, - meridiem : function (hour, minute, isLower) { - if (hour < 3) { - return 'राती'; - } else if (hour < 10) { - return 'बिहान'; - } else if (hour < 15) { - return 'दिउँसो'; - } else if (hour < 18) { - return 'बेलुका'; - } else if (hour < 20) { - return 'साँझ'; - } else { - return 'राती'; - } - }, - calendar : { - sameDay : '[आज] LT', - nextDay : '[भोली] LT', - nextWeek : '[आउँदो] dddd[,] LT', - lastDay : '[हिजो] LT', - lastWeek : '[गएको] dddd[,] LT', - sameElse : 'L' - }, - relativeTime : { - future : '%sमा', - past : '%s अगाडी', - s : 'केही समय', - m : 'एक मिनेट', - mm : '%d मिनेट', - h : 'एक घण्टा', - hh : '%d घण्टा', - d : 'एक दिन', - dd : '%d दिन', - M : 'एक महिना', - MM : '%d महिना', - y : 'एक बर्ष', - yy : '%d बर्ष' - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : dutch (nl) -// author : Joris Röling : https://github.com/jjupiter - -(function (factory) { - factory(moment); -}(function (moment) { - var monthsShortWithDots = 'jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.'.split('_'), - monthsShortWithoutDots = 'jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec'.split('_'); - - return moment.defineLocale('nl', { - months : 'januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december'.split('_'), - monthsShort : function (m, format) { - if (/-MMM-/.test(format)) { - return monthsShortWithoutDots[m.month()]; - } else { - return monthsShortWithDots[m.month()]; - } - }, - weekdays : 'zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag'.split('_'), - weekdaysShort : 'zo._ma._di._wo._do._vr._za.'.split('_'), - weekdaysMin : 'Zo_Ma_Di_Wo_Do_Vr_Za'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'DD-MM-YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd D MMMM YYYY LT' - }, - calendar : { - sameDay: '[vandaag om] LT', - nextDay: '[morgen om] LT', - nextWeek: 'dddd [om] LT', - lastDay: '[gisteren om] LT', - lastWeek: '[afgelopen] dddd [om] LT', - sameElse: 'L' - }, - relativeTime : { - future : 'over %s', - past : '%s geleden', - s : 'een paar seconden', - m : 'één minuut', - mm : '%d minuten', - h : 'één uur', - hh : '%d uur', - d : 'één dag', - dd : '%d dagen', - M : 'één maand', - MM : '%d maanden', - y : 'één jaar', - yy : '%d jaar' - }, - ordinal : function (number) { - return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de'); - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : norwegian nynorsk (nn) -// author : https://github.com/mechuwind - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('nn', { - months : 'januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember'.split('_'), - monthsShort : 'jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des'.split('_'), - weekdays : 'sundag_måndag_tysdag_onsdag_torsdag_fredag_laurdag'.split('_'), - weekdaysShort : 'sun_mån_tys_ons_tor_fre_lau'.split('_'), - weekdaysMin : 'su_må_ty_on_to_fr_lø'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'DD.MM.YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd D MMMM YYYY LT' - }, - calendar : { - sameDay: '[I dag klokka] LT', - nextDay: '[I morgon klokka] LT', - nextWeek: 'dddd [klokka] LT', - lastDay: '[I går klokka] LT', - lastWeek: '[Føregåande] dddd [klokka] LT', - sameElse: 'L' - }, - relativeTime : { - future : 'om %s', - past : 'for %s sidan', - s : 'nokre sekund', - m : 'eit minutt', - mm : '%d minutt', - h : 'ein time', - hh : '%d timar', - d : 'ein dag', - dd : '%d dagar', - M : 'ein månad', - MM : '%d månader', - y : 'eit år', - yy : '%d år' - }, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : polish (pl) -// author : Rafal Hirsz : https://github.com/evoL - -(function (factory) { - factory(moment); -}(function (moment) { - var monthsNominative = 'styczeń_luty_marzec_kwiecień_maj_czerwiec_lipiec_sierpień_wrzesień_październik_listopad_grudzień'.split('_'), - monthsSubjective = 'stycznia_lutego_marca_kwietnia_maja_czerwca_lipca_sierpnia_września_października_listopada_grudnia'.split('_'); - - function plural(n) { - return (n % 10 < 5) && (n % 10 > 1) && ((~~(n / 10) % 10) !== 1); - } - - function translate(number, withoutSuffix, key) { - var result = number + ' '; - switch (key) { - case 'm': - return withoutSuffix ? 'minuta' : 'minutę'; - case 'mm': - return result + (plural(number) ? 'minuty' : 'minut'); - case 'h': - return withoutSuffix ? 'godzina' : 'godzinę'; - case 'hh': - return result + (plural(number) ? 'godziny' : 'godzin'); - case 'MM': - return result + (plural(number) ? 'miesiące' : 'miesięcy'); - case 'yy': - return result + (plural(number) ? 'lata' : 'lat'); - } - } - - return moment.defineLocale('pl', { - months : function (momentToFormat, format) { - if (/D MMMM/.test(format)) { - return monthsSubjective[momentToFormat.month()]; - } else { - return monthsNominative[momentToFormat.month()]; - } - }, - monthsShort : 'sty_lut_mar_kwi_maj_cze_lip_sie_wrz_paź_lis_gru'.split('_'), - weekdays : 'niedziela_poniedziałek_wtorek_środa_czwartek_piątek_sobota'.split('_'), - weekdaysShort : 'nie_pon_wt_śr_czw_pt_sb'.split('_'), - weekdaysMin : 'N_Pn_Wt_Śr_Cz_Pt_So'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'DD.MM.YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd, D MMMM YYYY LT' - }, - calendar : { - sameDay: '[Dziś o] LT', - nextDay: '[Jutro o] LT', - nextWeek: '[W] dddd [o] LT', - lastDay: '[Wczoraj o] LT', - lastWeek: function () { - switch (this.day()) { - case 0: - return '[W zeszłą niedzielę o] LT'; - case 3: - return '[W zeszłą środę o] LT'; - case 6: - return '[W zeszłą sobotę o] LT'; - default: - return '[W zeszły] dddd [o] LT'; - } - }, - sameElse: 'L' - }, - relativeTime : { - future : 'za %s', - past : '%s temu', - s : 'kilka sekund', - m : translate, - mm : translate, - h : translate, - hh : translate, - d : '1 dzień', - dd : '%d dni', - M : 'miesiąc', - MM : translate, - y : 'rok', - yy : translate - }, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : brazilian portuguese (pt-br) -// author : Caio Ribeiro Pereira : https://github.com/caio-ribeiro-pereira - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('pt-br', { - months : 'janeiro_fevereiro_março_abril_maio_junho_julho_agosto_setembro_outubro_novembro_dezembro'.split('_'), - monthsShort : 'jan_fev_mar_abr_mai_jun_jul_ago_set_out_nov_dez'.split('_'), - weekdays : 'domingo_segunda-feira_terça-feira_quarta-feira_quinta-feira_sexta-feira_sábado'.split('_'), - weekdaysShort : 'dom_seg_ter_qua_qui_sex_sáb'.split('_'), - weekdaysMin : 'dom_2ª_3ª_4ª_5ª_6ª_sáb'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'DD/MM/YYYY', - LL : 'D [de] MMMM [de] YYYY', - LLL : 'D [de] MMMM [de] YYYY [às] LT', - LLLL : 'dddd, D [de] MMMM [de] YYYY [às] LT' - }, - calendar : { - sameDay: '[Hoje às] LT', - nextDay: '[Amanhã às] LT', - nextWeek: 'dddd [às] LT', - lastDay: '[Ontem às] LT', - lastWeek: function () { - return (this.day() === 0 || this.day() === 6) ? - '[Último] dddd [às] LT' : // Saturday + Sunday - '[Última] dddd [às] LT'; // Monday - Friday - }, - sameElse: 'L' - }, - relativeTime : { - future : 'em %s', - past : '%s atrás', - s : 'segundos', - m : 'um minuto', - mm : '%d minutos', - h : 'uma hora', - hh : '%d horas', - d : 'um dia', - dd : '%d dias', - M : 'um mês', - MM : '%d meses', - y : 'um ano', - yy : '%d anos' - }, - ordinal : '%dº' - }); -})); -// moment.js locale configuration -// locale : portuguese (pt) -// author : Jefferson : https://github.com/jalex79 - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('pt', { - months : 'janeiro_fevereiro_março_abril_maio_junho_julho_agosto_setembro_outubro_novembro_dezembro'.split('_'), - monthsShort : 'jan_fev_mar_abr_mai_jun_jul_ago_set_out_nov_dez'.split('_'), - weekdays : 'domingo_segunda-feira_terça-feira_quarta-feira_quinta-feira_sexta-feira_sábado'.split('_'), - weekdaysShort : 'dom_seg_ter_qua_qui_sex_sáb'.split('_'), - weekdaysMin : 'dom_2ª_3ª_4ª_5ª_6ª_sáb'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'DD/MM/YYYY', - LL : 'D [de] MMMM [de] YYYY', - LLL : 'D [de] MMMM [de] YYYY LT', - LLLL : 'dddd, D [de] MMMM [de] YYYY LT' - }, - calendar : { - sameDay: '[Hoje às] LT', - nextDay: '[Amanhã às] LT', - nextWeek: 'dddd [às] LT', - lastDay: '[Ontem às] LT', - lastWeek: function () { - return (this.day() === 0 || this.day() === 6) ? - '[Último] dddd [às] LT' : // Saturday + Sunday - '[Última] dddd [às] LT'; // Monday - Friday - }, - sameElse: 'L' - }, - relativeTime : { - future : 'em %s', - past : 'há %s', - s : 'segundos', - m : 'um minuto', - mm : '%d minutos', - h : 'uma hora', - hh : '%d horas', - d : 'um dia', - dd : '%d dias', - M : 'um mês', - MM : '%d meses', - y : 'um ano', - yy : '%d anos' - }, - ordinal : '%dº', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : romanian (ro) -// author : Vlad Gurdiga : https://github.com/gurdiga -// author : Valentin Agachi : https://github.com/avaly - -(function (factory) { - factory(moment); -}(function (moment) { - function relativeTimeWithPlural(number, withoutSuffix, key) { - var format = { - 'mm': 'minute', - 'hh': 'ore', - 'dd': 'zile', - 'MM': 'luni', - 'yy': 'ani' - }, - separator = ' '; - if (number % 100 >= 20 || (number >= 100 && number % 100 === 0)) { - separator = ' de '; - } - - return number + separator + format[key]; - } - - return moment.defineLocale('ro', { - months : 'ianuarie_februarie_martie_aprilie_mai_iunie_iulie_august_septembrie_octombrie_noiembrie_decembrie'.split('_'), - monthsShort : 'ian._febr._mart._apr._mai_iun._iul._aug._sept._oct._nov._dec.'.split('_'), - weekdays : 'duminică_luni_marți_miercuri_joi_vineri_sâmbătă'.split('_'), - weekdaysShort : 'Dum_Lun_Mar_Mie_Joi_Vin_Sâm'.split('_'), - weekdaysMin : 'Du_Lu_Ma_Mi_Jo_Vi_Sâ'.split('_'), - longDateFormat : { - LT : 'H:mm', - L : 'DD.MM.YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY H:mm', - LLLL : 'dddd, D MMMM YYYY H:mm' - }, - calendar : { - sameDay: '[azi la] LT', - nextDay: '[mâine la] LT', - nextWeek: 'dddd [la] LT', - lastDay: '[ieri la] LT', - lastWeek: '[fosta] dddd [la] LT', - sameElse: 'L' - }, - relativeTime : { - future : 'peste %s', - past : '%s în urmă', - s : 'câteva secunde', - m : 'un minut', - mm : relativeTimeWithPlural, - h : 'o oră', - hh : relativeTimeWithPlural, - d : 'o zi', - dd : relativeTimeWithPlural, - M : 'o lună', - MM : relativeTimeWithPlural, - y : 'un an', - yy : relativeTimeWithPlural - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : russian (ru) -// author : Viktorminator : https://github.com/Viktorminator -// Author : Menelion Elensúle : https://github.com/Oire - -(function (factory) { - factory(moment); -}(function (moment) { - function plural(word, num) { - var forms = word.split('_'); - return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]); - } - - function relativeTimeWithPlural(number, withoutSuffix, key) { - var format = { - 'mm': withoutSuffix ? 'минута_минуты_минут' : 'минуту_минуты_минут', - 'hh': 'час_часа_часов', - 'dd': 'день_дня_дней', - 'MM': 'месяц_месяца_месяцев', - 'yy': 'год_года_лет' - }; - if (key === 'm') { - return withoutSuffix ? 'минута' : 'минуту'; - } - else { - return number + ' ' + plural(format[key], +number); - } - } - - function monthsCaseReplace(m, format) { - var months = { - 'nominative': 'январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь'.split('_'), - 'accusative': 'января_февраля_марта_апреля_мая_июня_июля_августа_сентября_октября_ноября_декабря'.split('_') - }, - - nounCase = (/D[oD]?(\[[^\[\]]*\]|\s+)+MMMM?/).test(format) ? - 'accusative' : - 'nominative'; - - return months[nounCase][m.month()]; - } - - function monthsShortCaseReplace(m, format) { - var monthsShort = { - 'nominative': 'янв_фев_мар_апр_май_июнь_июль_авг_сен_окт_ноя_дек'.split('_'), - 'accusative': 'янв_фев_мар_апр_мая_июня_июля_авг_сен_окт_ноя_дек'.split('_') - }, - - nounCase = (/D[oD]?(\[[^\[\]]*\]|\s+)+MMMM?/).test(format) ? - 'accusative' : - 'nominative'; - - return monthsShort[nounCase][m.month()]; - } - - function weekdaysCaseReplace(m, format) { - var weekdays = { - 'nominative': 'воскресенье_понедельник_вторник_среда_четверг_пятница_суббота'.split('_'), - 'accusative': 'воскресенье_понедельник_вторник_среду_четверг_пятницу_субботу'.split('_') - }, - - nounCase = (/\[ ?[Вв] ?(?:прошлую|следующую)? ?\] ?dddd/).test(format) ? - 'accusative' : - 'nominative'; - - return weekdays[nounCase][m.day()]; - } - - return moment.defineLocale('ru', { - months : monthsCaseReplace, - monthsShort : monthsShortCaseReplace, - weekdays : weekdaysCaseReplace, - weekdaysShort : 'вс_пн_вт_ср_чт_пт_сб'.split('_'), - weekdaysMin : 'вс_пн_вт_ср_чт_пт_сб'.split('_'), - monthsParse : [/^янв/i, /^фев/i, /^мар/i, /^апр/i, /^ма[й|я]/i, /^июн/i, /^июл/i, /^авг/i, /^сен/i, /^окт/i, /^ноя/i, /^дек/i], - longDateFormat : { - LT : 'HH:mm', - L : 'DD.MM.YYYY', - LL : 'D MMMM YYYY г.', - LLL : 'D MMMM YYYY г., LT', - LLLL : 'dddd, D MMMM YYYY г., LT' - }, - calendar : { - sameDay: '[Сегодня в] LT', - nextDay: '[Завтра в] LT', - lastDay: '[Вчера в] LT', - nextWeek: function () { - return this.day() === 2 ? '[Во] dddd [в] LT' : '[В] dddd [в] LT'; - }, - lastWeek: function () { - switch (this.day()) { - case 0: - return '[В прошлое] dddd [в] LT'; - case 1: - case 2: - case 4: - return '[В прошлый] dddd [в] LT'; - case 3: - case 5: - case 6: - return '[В прошлую] dddd [в] LT'; - } - }, - sameElse: 'L' - }, - relativeTime : { - future : 'через %s', - past : '%s назад', - s : 'несколько секунд', - m : relativeTimeWithPlural, - mm : relativeTimeWithPlural, - h : 'час', - hh : relativeTimeWithPlural, - d : 'день', - dd : relativeTimeWithPlural, - M : 'месяц', - MM : relativeTimeWithPlural, - y : 'год', - yy : relativeTimeWithPlural - }, - - meridiemParse: /ночи|утра|дня|вечера/i, - isPM : function (input) { - return /^(дня|вечера)$/.test(input); - }, - - meridiem : function (hour, minute, isLower) { - if (hour < 4) { - return 'ночи'; - } else if (hour < 12) { - return 'утра'; - } else if (hour < 17) { - return 'дня'; - } else { - return 'вечера'; - } - }, - - ordinal: function (number, period) { - switch (period) { - case 'M': - case 'd': - case 'DDD': - return number + '-й'; - case 'D': - return number + '-го'; - case 'w': - case 'W': - return number + '-я'; - default: - return number; - } - }, - - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : slovak (sk) -// author : Martin Minka : https://github.com/k2s -// based on work of petrbela : https://github.com/petrbela - -(function (factory) { - factory(moment); -}(function (moment) { - var months = 'január_február_marec_apríl_máj_jún_júl_august_september_október_november_december'.split('_'), - monthsShort = 'jan_feb_mar_apr_máj_jún_júl_aug_sep_okt_nov_dec'.split('_'); - - function plural(n) { - return (n > 1) && (n < 5); - } - - function translate(number, withoutSuffix, key, isFuture) { - var result = number + ' '; - switch (key) { - case 's': // a few seconds / in a few seconds / a few seconds ago - return (withoutSuffix || isFuture) ? 'pár sekúnd' : 'pár sekundami'; - case 'm': // a minute / in a minute / a minute ago - return withoutSuffix ? 'minúta' : (isFuture ? 'minútu' : 'minútou'); - case 'mm': // 9 minutes / in 9 minutes / 9 minutes ago - if (withoutSuffix || isFuture) { - return result + (plural(number) ? 'minúty' : 'minút'); - } else { - return result + 'minútami'; - } - break; - case 'h': // an hour / in an hour / an hour ago - return withoutSuffix ? 'hodina' : (isFuture ? 'hodinu' : 'hodinou'); - case 'hh': // 9 hours / in 9 hours / 9 hours ago - if (withoutSuffix || isFuture) { - return result + (plural(number) ? 'hodiny' : 'hodín'); - } else { - return result + 'hodinami'; - } - break; - case 'd': // a day / in a day / a day ago - return (withoutSuffix || isFuture) ? 'deň' : 'dňom'; - case 'dd': // 9 days / in 9 days / 9 days ago - if (withoutSuffix || isFuture) { - return result + (plural(number) ? 'dni' : 'dní'); - } else { - return result + 'dňami'; - } - break; - case 'M': // a month / in a month / a month ago - return (withoutSuffix || isFuture) ? 'mesiac' : 'mesiacom'; - case 'MM': // 9 months / in 9 months / 9 months ago - if (withoutSuffix || isFuture) { - return result + (plural(number) ? 'mesiace' : 'mesiacov'); - } else { - return result + 'mesiacmi'; - } - break; - case 'y': // a year / in a year / a year ago - return (withoutSuffix || isFuture) ? 'rok' : 'rokom'; - case 'yy': // 9 years / in 9 years / 9 years ago - if (withoutSuffix || isFuture) { - return result + (plural(number) ? 'roky' : 'rokov'); - } else { - return result + 'rokmi'; - } - break; - } - } - - return moment.defineLocale('sk', { - months : months, - monthsShort : monthsShort, - monthsParse : (function (months, monthsShort) { - var i, _monthsParse = []; - for (i = 0; i < 12; i++) { - // use custom parser to solve problem with July (červenec) - _monthsParse[i] = new RegExp('^' + months[i] + '$|^' + monthsShort[i] + '$', 'i'); - } - return _monthsParse; - }(months, monthsShort)), - weekdays : 'nedeľa_pondelok_utorok_streda_štvrtok_piatok_sobota'.split('_'), - weekdaysShort : 'ne_po_ut_st_št_pi_so'.split('_'), - weekdaysMin : 'ne_po_ut_st_št_pi_so'.split('_'), - longDateFormat : { - LT: 'H:mm', - L : 'DD.MM.YYYY', - LL : 'D. MMMM YYYY', - LLL : 'D. MMMM YYYY LT', - LLLL : 'dddd D. MMMM YYYY LT' - }, - calendar : { - sameDay: '[dnes o] LT', - nextDay: '[zajtra o] LT', - nextWeek: function () { - switch (this.day()) { - case 0: - return '[v nedeľu o] LT'; - case 1: - case 2: - return '[v] dddd [o] LT'; - case 3: - return '[v stredu o] LT'; - case 4: - return '[vo štvrtok o] LT'; - case 5: - return '[v piatok o] LT'; - case 6: - return '[v sobotu o] LT'; - } - }, - lastDay: '[včera o] LT', - lastWeek: function () { - switch (this.day()) { - case 0: - return '[minulú nedeľu o] LT'; - case 1: - case 2: - return '[minulý] dddd [o] LT'; - case 3: - return '[minulú stredu o] LT'; - case 4: - case 5: - return '[minulý] dddd [o] LT'; - case 6: - return '[minulú sobotu o] LT'; - } - }, - sameElse: 'L' - }, - relativeTime : { - future : 'za %s', - past : 'pred %s', - s : translate, - m : translate, - mm : translate, - h : translate, - hh : translate, - d : translate, - dd : translate, - M : translate, - MM : translate, - y : translate, - yy : translate - }, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : slovenian (sl) -// author : Robert Sedovšek : https://github.com/sedovsek - -(function (factory) { - factory(moment); -}(function (moment) { - function translate(number, withoutSuffix, key) { - var result = number + ' '; - switch (key) { - case 'm': - return withoutSuffix ? 'ena minuta' : 'eno minuto'; - case 'mm': - if (number === 1) { - result += 'minuta'; - } else if (number === 2) { - result += 'minuti'; - } else if (number === 3 || number === 4) { - result += 'minute'; - } else { - result += 'minut'; - } - return result; - case 'h': - return withoutSuffix ? 'ena ura' : 'eno uro'; - case 'hh': - if (number === 1) { - result += 'ura'; - } else if (number === 2) { - result += 'uri'; - } else if (number === 3 || number === 4) { - result += 'ure'; - } else { - result += 'ur'; - } - return result; - case 'dd': - if (number === 1) { - result += 'dan'; - } else { - result += 'dni'; - } - return result; - case 'MM': - if (number === 1) { - result += 'mesec'; - } else if (number === 2) { - result += 'meseca'; - } else if (number === 3 || number === 4) { - result += 'mesece'; - } else { - result += 'mesecev'; - } - return result; - case 'yy': - if (number === 1) { - result += 'leto'; - } else if (number === 2) { - result += 'leti'; - } else if (number === 3 || number === 4) { - result += 'leta'; - } else { - result += 'let'; - } - return result; - } - } - - return moment.defineLocale('sl', { - months : 'januar_februar_marec_april_maj_junij_julij_avgust_september_oktober_november_december'.split('_'), - monthsShort : 'jan._feb._mar._apr._maj._jun._jul._avg._sep._okt._nov._dec.'.split('_'), - weekdays : 'nedelja_ponedeljek_torek_sreda_četrtek_petek_sobota'.split('_'), - weekdaysShort : 'ned._pon._tor._sre._čet._pet._sob.'.split('_'), - weekdaysMin : 'ne_po_to_sr_če_pe_so'.split('_'), - longDateFormat : { - LT : 'H:mm', - L : 'DD. MM. YYYY', - LL : 'D. MMMM YYYY', - LLL : 'D. MMMM YYYY LT', - LLLL : 'dddd, D. MMMM YYYY LT' - }, - calendar : { - sameDay : '[danes ob] LT', - nextDay : '[jutri ob] LT', - - nextWeek : function () { - switch (this.day()) { - case 0: - return '[v] [nedeljo] [ob] LT'; - case 3: - return '[v] [sredo] [ob] LT'; - case 6: - return '[v] [soboto] [ob] LT'; - case 1: - case 2: - case 4: - case 5: - return '[v] dddd [ob] LT'; - } - }, - lastDay : '[včeraj ob] LT', - lastWeek : function () { - switch (this.day()) { - case 0: - case 3: - case 6: - return '[prejšnja] dddd [ob] LT'; - case 1: - case 2: - case 4: - case 5: - return '[prejšnji] dddd [ob] LT'; - } - }, - sameElse : 'L' - }, - relativeTime : { - future : 'čez %s', - past : '%s nazaj', - s : 'nekaj sekund', - m : translate, - mm : translate, - h : translate, - hh : translate, - d : 'en dan', - dd : translate, - M : 'en mesec', - MM : translate, - y : 'eno leto', - yy : translate - }, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : Albanian (sq) -// author : Flakërim Ismani : https://github.com/flakerimi -// author: Menelion Elensúle: https://github.com/Oire (tests) -// author : Oerd Cukalla : https://github.com/oerd (fixes) - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('sq', { - months : 'Janar_Shkurt_Mars_Prill_Maj_Qershor_Korrik_Gusht_Shtator_Tetor_Nëntor_Dhjetor'.split('_'), - monthsShort : 'Jan_Shk_Mar_Pri_Maj_Qer_Kor_Gus_Sht_Tet_Nën_Dhj'.split('_'), - weekdays : 'E Diel_E Hënë_E Martë_E Mërkurë_E Enjte_E Premte_E Shtunë'.split('_'), - weekdaysShort : 'Die_Hën_Mar_Mër_Enj_Pre_Sht'.split('_'), - weekdaysMin : 'D_H_Ma_Më_E_P_Sh'.split('_'), - meridiem : function (hours, minutes, isLower) { - return hours < 12 ? 'PD' : 'MD'; - }, - longDateFormat : { - LT : 'HH:mm', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd, D MMMM YYYY LT' - }, - calendar : { - sameDay : '[Sot në] LT', - nextDay : '[Nesër në] LT', - nextWeek : 'dddd [në] LT', - lastDay : '[Dje në] LT', - lastWeek : 'dddd [e kaluar në] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'në %s', - past : '%s më parë', - s : 'disa sekonda', - m : 'një minutë', - mm : '%d minuta', - h : 'një orë', - hh : '%d orë', - d : 'një ditë', - dd : '%d ditë', - M : 'një muaj', - MM : '%d muaj', - y : 'një vit', - yy : '%d vite' - }, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : Serbian-cyrillic (sr-cyrl) -// author : Milan Janačković : https://github.com/milan-j - -(function (factory) { - factory(moment); -}(function (moment) { - var translator = { - words: { //Different grammatical cases - m: ['један минут', 'једне минуте'], - mm: ['минут', 'минуте', 'минута'], - h: ['један сат', 'једног сата'], - hh: ['сат', 'сата', 'сати'], - dd: ['дан', 'дана', 'дана'], - MM: ['месец', 'месеца', 'месеци'], - yy: ['година', 'године', 'година'] - }, - correctGrammaticalCase: function (number, wordKey) { - return number === 1 ? wordKey[0] : (number >= 2 && number <= 4 ? wordKey[1] : wordKey[2]); - }, - translate: function (number, withoutSuffix, key) { - var wordKey = translator.words[key]; - if (key.length === 1) { - return withoutSuffix ? wordKey[0] : wordKey[1]; - } else { - return number + ' ' + translator.correctGrammaticalCase(number, wordKey); - } - } - }; - - return moment.defineLocale('sr-cyrl', { - months: ['јануар', 'фебруар', 'март', 'април', 'мај', 'јун', 'јул', 'август', 'септембар', 'октобар', 'новембар', 'децембар'], - monthsShort: ['јан.', 'феб.', 'мар.', 'апр.', 'мај', 'јун', 'јул', 'авг.', 'сеп.', 'окт.', 'нов.', 'дец.'], - weekdays: ['недеља', 'понедељак', 'уторак', 'среда', 'четвртак', 'петак', 'субота'], - weekdaysShort: ['нед.', 'пон.', 'уто.', 'сре.', 'чет.', 'пет.', 'суб.'], - weekdaysMin: ['не', 'по', 'ут', 'ср', 'че', 'пе', 'су'], - longDateFormat: { - LT: 'H:mm', - L: 'DD. MM. YYYY', - LL: 'D. MMMM YYYY', - LLL: 'D. MMMM YYYY LT', - LLLL: 'dddd, D. MMMM YYYY LT' - }, - calendar: { - sameDay: '[данас у] LT', - nextDay: '[сутра у] LT', - - nextWeek: function () { - switch (this.day()) { - case 0: - return '[у] [недељу] [у] LT'; - case 3: - return '[у] [среду] [у] LT'; - case 6: - return '[у] [суботу] [у] LT'; - case 1: - case 2: - case 4: - case 5: - return '[у] dddd [у] LT'; - } - }, - lastDay : '[јуче у] LT', - lastWeek : function () { - var lastWeekDays = [ - '[прошле] [недеље] [у] LT', - '[прошлог] [понедељка] [у] LT', - '[прошлог] [уторка] [у] LT', - '[прошле] [среде] [у] LT', - '[прошлог] [четвртка] [у] LT', - '[прошлог] [петка] [у] LT', - '[прошле] [суботе] [у] LT' - ]; - return lastWeekDays[this.day()]; - }, - sameElse : 'L' - }, - relativeTime : { - future : 'за %s', - past : 'пре %s', - s : 'неколико секунди', - m : translator.translate, - mm : translator.translate, - h : translator.translate, - hh : translator.translate, - d : 'дан', - dd : translator.translate, - M : 'месец', - MM : translator.translate, - y : 'годину', - yy : translator.translate - }, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : Serbian-latin (sr) -// author : Milan Janačković : https://github.com/milan-j - -(function (factory) { - factory(moment); -}(function (moment) { - var translator = { - words: { //Different grammatical cases - m: ['jedan minut', 'jedne minute'], - mm: ['minut', 'minute', 'minuta'], - h: ['jedan sat', 'jednog sata'], - hh: ['sat', 'sata', 'sati'], - dd: ['dan', 'dana', 'dana'], - MM: ['mesec', 'meseca', 'meseci'], - yy: ['godina', 'godine', 'godina'] - }, - correctGrammaticalCase: function (number, wordKey) { - return number === 1 ? wordKey[0] : (number >= 2 && number <= 4 ? wordKey[1] : wordKey[2]); - }, - translate: function (number, withoutSuffix, key) { - var wordKey = translator.words[key]; - if (key.length === 1) { - return withoutSuffix ? wordKey[0] : wordKey[1]; - } else { - return number + ' ' + translator.correctGrammaticalCase(number, wordKey); - } - } - }; - - return moment.defineLocale('sr', { - months: ['januar', 'februar', 'mart', 'april', 'maj', 'jun', 'jul', 'avgust', 'septembar', 'oktobar', 'novembar', 'decembar'], - monthsShort: ['jan.', 'feb.', 'mar.', 'apr.', 'maj', 'jun', 'jul', 'avg.', 'sep.', 'okt.', 'nov.', 'dec.'], - weekdays: ['nedelja', 'ponedeljak', 'utorak', 'sreda', 'četvrtak', 'petak', 'subota'], - weekdaysShort: ['ned.', 'pon.', 'uto.', 'sre.', 'čet.', 'pet.', 'sub.'], - weekdaysMin: ['ne', 'po', 'ut', 'sr', 'če', 'pe', 'su'], - longDateFormat: { - LT: 'H:mm', - L: 'DD. MM. YYYY', - LL: 'D. MMMM YYYY', - LLL: 'D. MMMM YYYY LT', - LLLL: 'dddd, D. MMMM YYYY LT' - }, - calendar: { - sameDay: '[danas u] LT', - nextDay: '[sutra u] LT', - - nextWeek: function () { - switch (this.day()) { - case 0: - return '[u] [nedelju] [u] LT'; - case 3: - return '[u] [sredu] [u] LT'; - case 6: - return '[u] [subotu] [u] LT'; - case 1: - case 2: - case 4: - case 5: - return '[u] dddd [u] LT'; - } - }, - lastDay : '[juče u] LT', - lastWeek : function () { - var lastWeekDays = [ - '[prošle] [nedelje] [u] LT', - '[prošlog] [ponedeljka] [u] LT', - '[prošlog] [utorka] [u] LT', - '[prošle] [srede] [u] LT', - '[prošlog] [četvrtka] [u] LT', - '[prošlog] [petka] [u] LT', - '[prošle] [subote] [u] LT' - ]; - return lastWeekDays[this.day()]; - }, - sameElse : 'L' - }, - relativeTime : { - future : 'za %s', - past : 'pre %s', - s : 'nekoliko sekundi', - m : translator.translate, - mm : translator.translate, - h : translator.translate, - hh : translator.translate, - d : 'dan', - dd : translator.translate, - M : 'mesec', - MM : translator.translate, - y : 'godinu', - yy : translator.translate - }, - ordinal : '%d.', - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : swedish (sv) -// author : Jens Alm : https://github.com/ulmus - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('sv', { - months : 'januari_februari_mars_april_maj_juni_juli_augusti_september_oktober_november_december'.split('_'), - monthsShort : 'jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec'.split('_'), - weekdays : 'söndag_måndag_tisdag_onsdag_torsdag_fredag_lördag'.split('_'), - weekdaysShort : 'sön_mån_tis_ons_tor_fre_lör'.split('_'), - weekdaysMin : 'sö_må_ti_on_to_fr_lö'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'YYYY-MM-DD', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd D MMMM YYYY LT' - }, - calendar : { - sameDay: '[Idag] LT', - nextDay: '[Imorgon] LT', - lastDay: '[Igår] LT', - nextWeek: 'dddd LT', - lastWeek: '[Förra] dddd[en] LT', - sameElse: 'L' - }, - relativeTime : { - future : 'om %s', - past : 'för %s sedan', - s : 'några sekunder', - m : 'en minut', - mm : '%d minuter', - h : 'en timme', - hh : '%d timmar', - d : 'en dag', - dd : '%d dagar', - M : 'en månad', - MM : '%d månader', - y : 'ett år', - yy : '%d år' - }, - ordinal : function (number) { - var b = number % 10, - output = (~~(number % 100 / 10) === 1) ? 'e' : - (b === 1) ? 'a' : - (b === 2) ? 'a' : - (b === 3) ? 'e' : 'e'; - return number + output; - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : tamil (ta) -// author : Arjunkumar Krishnamoorthy : https://github.com/tk120404 - -(function (factory) { - factory(moment); -}(function (moment) { - /*var symbolMap = { - '1': '௧', - '2': '௨', - '3': '௩', - '4': '௪', - '5': '௫', - '6': '௬', - '7': '௭', - '8': '௮', - '9': '௯', - '0': '௦' - }, - numberMap = { - '௧': '1', - '௨': '2', - '௩': '3', - '௪': '4', - '௫': '5', - '௬': '6', - '௭': '7', - '௮': '8', - '௯': '9', - '௦': '0' - }; */ - - return moment.defineLocale('ta', { - months : 'ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்'.split('_'), - monthsShort : 'ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்'.split('_'), - weekdays : 'ஞாயிற்றுக்கிழமை_திங்கட்கிழமை_செவ்வாய்கிழமை_புதன்கிழமை_வியாழக்கிழமை_வெள்ளிக்கிழமை_சனிக்கிழமை'.split('_'), - weekdaysShort : 'ஞாயிறு_திங்கள்_செவ்வாய்_புதன்_வியாழன்_வெள்ளி_சனி'.split('_'), - weekdaysMin : 'ஞா_தி_செ_பு_வி_வெ_ச'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY, LT', - LLLL : 'dddd, D MMMM YYYY, LT' - }, - calendar : { - sameDay : '[இன்று] LT', - nextDay : '[நாளை] LT', - nextWeek : 'dddd, LT', - lastDay : '[நேற்று] LT', - lastWeek : '[கடந்த வாரம்] dddd, LT', - sameElse : 'L' - }, - relativeTime : { - future : '%s இல்', - past : '%s முன்', - s : 'ஒரு சில விநாடிகள்', - m : 'ஒரு நிமிடம்', - mm : '%d நிமிடங்கள்', - h : 'ஒரு மணி நேரம்', - hh : '%d மணி நேரம்', - d : 'ஒரு நாள்', - dd : '%d நாட்கள்', - M : 'ஒரு மாதம்', - MM : '%d மாதங்கள்', - y : 'ஒரு வருடம்', - yy : '%d ஆண்டுகள்' - }, -/* preparse: function (string) { - return string.replace(/[௧௨௩௪௫௬௭௮௯௦]/g, function (match) { - return numberMap[match]; - }); - }, - postformat: function (string) { - return string.replace(/\d/g, function (match) { - return symbolMap[match]; - }); - },*/ - ordinal : function (number) { - return number + 'வது'; - }, - - - // refer http://ta.wikipedia.org/s/1er1 - - meridiem : function (hour, minute, isLower) { - if (hour >= 6 && hour <= 10) { - return ' காலை'; - } else if (hour >= 10 && hour <= 14) { - return ' நண்பகல்'; - } else if (hour >= 14 && hour <= 18) { - return ' எற்பாடு'; - } else if (hour >= 18 && hour <= 20) { - return ' மாலை'; - } else if (hour >= 20 && hour <= 24) { - return ' இரவு'; - } else if (hour >= 0 && hour <= 6) { - return ' வைகறை'; - } - }, - week : { - dow : 0, // Sunday is the first day of the week. - doy : 6 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : thai (th) -// author : Kridsada Thanabulpong : https://github.com/sirn - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('th', { - months : 'มกราคม_กุมภาพันธ์_มีนาคม_เมษายน_พฤษภาคม_มิถุนายน_กรกฎาคม_สิงหาคม_กันยายน_ตุลาคม_พฤศจิกายน_ธันวาคม'.split('_'), - monthsShort : 'มกรา_กุมภา_มีนา_เมษา_พฤษภา_มิถุนา_กรกฎา_สิงหา_กันยา_ตุลา_พฤศจิกา_ธันวา'.split('_'), - weekdays : 'อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัสบดี_ศุกร์_เสาร์'.split('_'), - weekdaysShort : 'อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัส_ศุกร์_เสาร์'.split('_'), // yes, three characters difference - weekdaysMin : 'อา._จ._อ._พ._พฤ._ศ._ส.'.split('_'), - longDateFormat : { - LT : 'H นาฬิกา m นาที', - L : 'YYYY/MM/DD', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY เวลา LT', - LLLL : 'วันddddที่ D MMMM YYYY เวลา LT' - }, - meridiem : function (hour, minute, isLower) { - if (hour < 12) { - return 'ก่อนเที่ยง'; - } else { - return 'หลังเที่ยง'; - } - }, - calendar : { - sameDay : '[วันนี้ เวลา] LT', - nextDay : '[พรุ่งนี้ เวลา] LT', - nextWeek : 'dddd[หน้า เวลา] LT', - lastDay : '[เมื่อวานนี้ เวลา] LT', - lastWeek : '[วัน]dddd[ที่แล้ว เวลา] LT', - sameElse : 'L' - }, - relativeTime : { - future : 'อีก %s', - past : '%sที่แล้ว', - s : 'ไม่กี่วินาที', - m : '1 นาที', - mm : '%d นาที', - h : '1 ชั่วโมง', - hh : '%d ชั่วโมง', - d : '1 วัน', - dd : '%d วัน', - M : '1 เดือน', - MM : '%d เดือน', - y : '1 ปี', - yy : '%d ปี' - } - }); -})); -// moment.js locale configuration -// locale : Tagalog/Filipino (tl-ph) -// author : Dan Hagman - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('tl-ph', { - months : 'Enero_Pebrero_Marso_Abril_Mayo_Hunyo_Hulyo_Agosto_Setyembre_Oktubre_Nobyembre_Disyembre'.split('_'), - monthsShort : 'Ene_Peb_Mar_Abr_May_Hun_Hul_Ago_Set_Okt_Nob_Dis'.split('_'), - weekdays : 'Linggo_Lunes_Martes_Miyerkules_Huwebes_Biyernes_Sabado'.split('_'), - weekdaysShort : 'Lin_Lun_Mar_Miy_Huw_Biy_Sab'.split('_'), - weekdaysMin : 'Li_Lu_Ma_Mi_Hu_Bi_Sab'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'MM/D/YYYY', - LL : 'MMMM D, YYYY', - LLL : 'MMMM D, YYYY LT', - LLLL : 'dddd, MMMM DD, YYYY LT' - }, - calendar : { - sameDay: '[Ngayon sa] LT', - nextDay: '[Bukas sa] LT', - nextWeek: 'dddd [sa] LT', - lastDay: '[Kahapon sa] LT', - lastWeek: 'dddd [huling linggo] LT', - sameElse: 'L' - }, - relativeTime : { - future : 'sa loob ng %s', - past : '%s ang nakalipas', - s : 'ilang segundo', - m : 'isang minuto', - mm : '%d minuto', - h : 'isang oras', - hh : '%d oras', - d : 'isang araw', - dd : '%d araw', - M : 'isang buwan', - MM : '%d buwan', - y : 'isang taon', - yy : '%d taon' - }, - ordinal : function (number) { - return number; - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : turkish (tr) -// authors : Erhan Gundogan : https://github.com/erhangundogan, -// Burak Yiğit Kaya: https://github.com/BYK - -(function (factory) { - factory(moment); -}(function (moment) { - var suffixes = { - 1: '\'inci', - 5: '\'inci', - 8: '\'inci', - 70: '\'inci', - 80: '\'inci', - - 2: '\'nci', - 7: '\'nci', - 20: '\'nci', - 50: '\'nci', - - 3: '\'üncü', - 4: '\'üncü', - 100: '\'üncü', - - 6: '\'ncı', - - 9: '\'uncu', - 10: '\'uncu', - 30: '\'uncu', - - 60: '\'ıncı', - 90: '\'ıncı' - }; - - return moment.defineLocale('tr', { - months : 'Ocak_Şubat_Mart_Nisan_Mayıs_Haziran_Temmuz_Ağustos_Eylül_Ekim_Kasım_Aralık'.split('_'), - monthsShort : 'Oca_Şub_Mar_Nis_May_Haz_Tem_Ağu_Eyl_Eki_Kas_Ara'.split('_'), - weekdays : 'Pazar_Pazartesi_Salı_Çarşamba_Perşembe_Cuma_Cumartesi'.split('_'), - weekdaysShort : 'Paz_Pts_Sal_Çar_Per_Cum_Cts'.split('_'), - weekdaysMin : 'Pz_Pt_Sa_Ça_Pe_Cu_Ct'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'DD.MM.YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd, D MMMM YYYY LT' - }, - calendar : { - sameDay : '[bugün saat] LT', - nextDay : '[yarın saat] LT', - nextWeek : '[haftaya] dddd [saat] LT', - lastDay : '[dün] LT', - lastWeek : '[geçen hafta] dddd [saat] LT', - sameElse : 'L' - }, - relativeTime : { - future : '%s sonra', - past : '%s önce', - s : 'birkaç saniye', - m : 'bir dakika', - mm : '%d dakika', - h : 'bir saat', - hh : '%d saat', - d : 'bir gün', - dd : '%d gün', - M : 'bir ay', - MM : '%d ay', - y : 'bir yıl', - yy : '%d yıl' - }, - ordinal : function (number) { - if (number === 0) { // special case for zero - return number + '\'ıncı'; - } - var a = number % 10, - b = number % 100 - a, - c = number >= 100 ? 100 : null; - - return number + (suffixes[a] || suffixes[b] || suffixes[c]); - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : Morocco Central Atlas Tamaziɣt in Latin (tzm-latn) -// author : Abdel Said : https://github.com/abdelsaid - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('tzm-latn', { - months : 'innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir'.split('_'), - monthsShort : 'innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir'.split('_'), - weekdays : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'), - weekdaysShort : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'), - weekdaysMin : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd D MMMM YYYY LT' - }, - calendar : { - sameDay: '[asdkh g] LT', - nextDay: '[aska g] LT', - nextWeek: 'dddd [g] LT', - lastDay: '[assant g] LT', - lastWeek: 'dddd [g] LT', - sameElse: 'L' - }, - relativeTime : { - future : 'dadkh s yan %s', - past : 'yan %s', - s : 'imik', - m : 'minuḍ', - mm : '%d minuḍ', - h : 'saɛa', - hh : '%d tassaɛin', - d : 'ass', - dd : '%d ossan', - M : 'ayowr', - MM : '%d iyyirn', - y : 'asgas', - yy : '%d isgasn' - }, - week : { - dow : 6, // Saturday is the first day of the week. - doy : 12 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : Morocco Central Atlas Tamaziɣt (tzm) -// author : Abdel Said : https://github.com/abdelsaid - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('tzm', { - months : 'ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ'.split('_'), - monthsShort : 'ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ'.split('_'), - weekdays : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'), - weekdaysShort : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'), - weekdaysMin : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'dddd D MMMM YYYY LT' - }, - calendar : { - sameDay: '[ⴰⵙⴷⵅ ⴴ] LT', - nextDay: '[ⴰⵙⴽⴰ ⴴ] LT', - nextWeek: 'dddd [ⴴ] LT', - lastDay: '[ⴰⵚⴰⵏⵜ ⴴ] LT', - lastWeek: 'dddd [ⴴ] LT', - sameElse: 'L' - }, - relativeTime : { - future : 'ⴷⴰⴷⵅ ⵙ ⵢⴰⵏ %s', - past : 'ⵢⴰⵏ %s', - s : 'ⵉⵎⵉⴽ', - m : 'ⵎⵉⵏⵓⴺ', - mm : '%d ⵎⵉⵏⵓⴺ', - h : 'ⵙⴰⵄⴰ', - hh : '%d ⵜⴰⵙⵙⴰⵄⵉⵏ', - d : 'ⴰⵙⵙ', - dd : '%d oⵙⵙⴰⵏ', - M : 'ⴰⵢoⵓⵔ', - MM : '%d ⵉⵢⵢⵉⵔⵏ', - y : 'ⴰⵙⴳⴰⵙ', - yy : '%d ⵉⵙⴳⴰⵙⵏ' - }, - week : { - dow : 6, // Saturday is the first day of the week. - doy : 12 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : ukrainian (uk) -// author : zemlanin : https://github.com/zemlanin -// Author : Menelion Elensúle : https://github.com/Oire - -(function (factory) { - factory(moment); -}(function (moment) { - function plural(word, num) { - var forms = word.split('_'); - return num % 10 === 1 && num % 100 !== 11 ? forms[0] : (num % 10 >= 2 && num % 10 <= 4 && (num % 100 < 10 || num % 100 >= 20) ? forms[1] : forms[2]); - } - - function relativeTimeWithPlural(number, withoutSuffix, key) { - var format = { - 'mm': 'хвилина_хвилини_хвилин', - 'hh': 'година_години_годин', - 'dd': 'день_дні_днів', - 'MM': 'місяць_місяці_місяців', - 'yy': 'рік_роки_років' - }; - if (key === 'm') { - return withoutSuffix ? 'хвилина' : 'хвилину'; - } - else if (key === 'h') { - return withoutSuffix ? 'година' : 'годину'; - } - else { - return number + ' ' + plural(format[key], +number); - } - } - - function monthsCaseReplace(m, format) { - var months = { - 'nominative': 'січень_лютий_березень_квітень_травень_червень_липень_серпень_вересень_жовтень_листопад_грудень'.split('_'), - 'accusative': 'січня_лютого_березня_квітня_травня_червня_липня_серпня_вересня_жовтня_листопада_грудня'.split('_') - }, - - nounCase = (/D[oD]? *MMMM?/).test(format) ? - 'accusative' : - 'nominative'; - - return months[nounCase][m.month()]; - } - - function weekdaysCaseReplace(m, format) { - var weekdays = { - 'nominative': 'неділя_понеділок_вівторок_середа_четвер_п’ятниця_субота'.split('_'), - 'accusative': 'неділю_понеділок_вівторок_середу_четвер_п’ятницю_суботу'.split('_'), - 'genitive': 'неділі_понеділка_вівторка_середи_четверга_п’ятниці_суботи'.split('_') - }, - - nounCase = (/(\[[ВвУу]\]) ?dddd/).test(format) ? - 'accusative' : - ((/\[?(?:минулої|наступної)? ?\] ?dddd/).test(format) ? - 'genitive' : - 'nominative'); - - return weekdays[nounCase][m.day()]; - } - - function processHoursFunction(str) { - return function () { - return str + 'о' + (this.hours() === 11 ? 'б' : '') + '] LT'; - }; - } - - return moment.defineLocale('uk', { - months : monthsCaseReplace, - monthsShort : 'січ_лют_бер_квіт_трав_черв_лип_серп_вер_жовт_лист_груд'.split('_'), - weekdays : weekdaysCaseReplace, - weekdaysShort : 'нд_пн_вт_ср_чт_пт_сб'.split('_'), - weekdaysMin : 'нд_пн_вт_ср_чт_пт_сб'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'DD.MM.YYYY', - LL : 'D MMMM YYYY р.', - LLL : 'D MMMM YYYY р., LT', - LLLL : 'dddd, D MMMM YYYY р., LT' - }, - calendar : { - sameDay: processHoursFunction('[Сьогодні '), - nextDay: processHoursFunction('[Завтра '), - lastDay: processHoursFunction('[Вчора '), - nextWeek: processHoursFunction('[У] dddd ['), - lastWeek: function () { - switch (this.day()) { - case 0: - case 3: - case 5: - case 6: - return processHoursFunction('[Минулої] dddd [').call(this); - case 1: - case 2: - case 4: - return processHoursFunction('[Минулого] dddd [').call(this); - } - }, - sameElse: 'L' - }, - relativeTime : { - future : 'за %s', - past : '%s тому', - s : 'декілька секунд', - m : relativeTimeWithPlural, - mm : relativeTimeWithPlural, - h : 'годину', - hh : relativeTimeWithPlural, - d : 'день', - dd : relativeTimeWithPlural, - M : 'місяць', - MM : relativeTimeWithPlural, - y : 'рік', - yy : relativeTimeWithPlural - }, - - // M. E.: those two are virtually unused but a user might want to implement them for his/her website for some reason - - meridiem : function (hour, minute, isLower) { - if (hour < 4) { - return 'ночі'; - } else if (hour < 12) { - return 'ранку'; - } else if (hour < 17) { - return 'дня'; - } else { - return 'вечора'; - } - }, - - ordinal: function (number, period) { - switch (period) { - case 'M': - case 'd': - case 'DDD': - case 'w': - case 'W': - return number + '-й'; - case 'D': - return number + '-го'; - default: - return number; - } - }, - - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 1st is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : uzbek (uz) -// author : Sardor Muminov : https://github.com/muminoff - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('uz', { - months : 'январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь'.split('_'), - monthsShort : 'янв_фев_мар_апр_май_июн_июл_авг_сен_окт_ноя_дек'.split('_'), - weekdays : 'Якшанба_Душанба_Сешанба_Чоршанба_Пайшанба_Жума_Шанба'.split('_'), - weekdaysShort : 'Якш_Душ_Сеш_Чор_Пай_Жум_Шан'.split('_'), - weekdaysMin : 'Як_Ду_Се_Чо_Па_Жу_Ша'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'DD/MM/YYYY', - LL : 'D MMMM YYYY', - LLL : 'D MMMM YYYY LT', - LLLL : 'D MMMM YYYY, dddd LT' - }, - calendar : { - sameDay : '[Бугун соат] LT [да]', - nextDay : '[Эртага] LT [да]', - nextWeek : 'dddd [куни соат] LT [да]', - lastDay : '[Кеча соат] LT [да]', - lastWeek : '[Утган] dddd [куни соат] LT [да]', - sameElse : 'L' - }, - relativeTime : { - future : 'Якин %s ичида', - past : 'Бир неча %s олдин', - s : 'фурсат', - m : 'бир дакика', - mm : '%d дакика', - h : 'бир соат', - hh : '%d соат', - d : 'бир кун', - dd : '%d кун', - M : 'бир ой', - MM : '%d ой', - y : 'бир йил', - yy : '%d йил' - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 7 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : vietnamese (vi) -// author : Bang Nguyen : https://github.com/bangnk - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('vi', { - months : 'tháng 1_tháng 2_tháng 3_tháng 4_tháng 5_tháng 6_tháng 7_tháng 8_tháng 9_tháng 10_tháng 11_tháng 12'.split('_'), - monthsShort : 'Th01_Th02_Th03_Th04_Th05_Th06_Th07_Th08_Th09_Th10_Th11_Th12'.split('_'), - weekdays : 'chủ nhật_thứ hai_thứ ba_thứ tư_thứ năm_thứ sáu_thứ bảy'.split('_'), - weekdaysShort : 'CN_T2_T3_T4_T5_T6_T7'.split('_'), - weekdaysMin : 'CN_T2_T3_T4_T5_T6_T7'.split('_'), - longDateFormat : { - LT : 'HH:mm', - L : 'DD/MM/YYYY', - LL : 'D MMMM [năm] YYYY', - LLL : 'D MMMM [năm] YYYY LT', - LLLL : 'dddd, D MMMM [năm] YYYY LT', - l : 'DD/M/YYYY', - ll : 'D MMM YYYY', - lll : 'D MMM YYYY LT', - llll : 'ddd, D MMM YYYY LT' - }, - calendar : { - sameDay: '[Hôm nay lúc] LT', - nextDay: '[Ngày mai lúc] LT', - nextWeek: 'dddd [tuần tới lúc] LT', - lastDay: '[Hôm qua lúc] LT', - lastWeek: 'dddd [tuần rồi lúc] LT', - sameElse: 'L' - }, - relativeTime : { - future : '%s tới', - past : '%s trước', - s : 'vài giây', - m : 'một phút', - mm : '%d phút', - h : 'một giờ', - hh : '%d giờ', - d : 'một ngày', - dd : '%d ngày', - M : 'một tháng', - MM : '%d tháng', - y : 'một năm', - yy : '%d năm' - }, - ordinal : function (number) { - return number; - }, - week : { - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : chinese (zh-cn) -// author : suupic : https://github.com/suupic -// author : Zeno Zeng : https://github.com/zenozeng - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('zh-cn', { - months : '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'), - monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'), - weekdays : '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'), - weekdaysShort : '周日_周一_周二_周三_周四_周五_周六'.split('_'), - weekdaysMin : '日_一_二_三_四_五_六'.split('_'), - longDateFormat : { - LT : 'Ah点mm', - L : 'YYYY-MM-DD', - LL : 'YYYY年MMMD日', - LLL : 'YYYY年MMMD日LT', - LLLL : 'YYYY年MMMD日ddddLT', - l : 'YYYY-MM-DD', - ll : 'YYYY年MMMD日', - lll : 'YYYY年MMMD日LT', - llll : 'YYYY年MMMD日ddddLT' - }, - meridiem : function (hour, minute, isLower) { - var hm = hour * 100 + minute; - if (hm < 600) { - return '凌晨'; - } else if (hm < 900) { - return '早上'; - } else if (hm < 1130) { - return '上午'; - } else if (hm < 1230) { - return '中午'; - } else if (hm < 1800) { - return '下午'; - } else { - return '晚上'; - } - }, - calendar : { - sameDay : function () { - return this.minutes() === 0 ? '[今天]Ah[点整]' : '[今天]LT'; - }, - nextDay : function () { - return this.minutes() === 0 ? '[明天]Ah[点整]' : '[明天]LT'; - }, - lastDay : function () { - return this.minutes() === 0 ? '[昨天]Ah[点整]' : '[昨天]LT'; - }, - nextWeek : function () { - var startOfWeek, prefix; - startOfWeek = moment().startOf('week'); - prefix = this.unix() - startOfWeek.unix() >= 7 * 24 * 3600 ? '[下]' : '[本]'; - return this.minutes() === 0 ? prefix + 'dddAh点整' : prefix + 'dddAh点mm'; - }, - lastWeek : function () { - var startOfWeek, prefix; - startOfWeek = moment().startOf('week'); - prefix = this.unix() < startOfWeek.unix() ? '[上]' : '[本]'; - return this.minutes() === 0 ? prefix + 'dddAh点整' : prefix + 'dddAh点mm'; - }, - sameElse : 'LL' - }, - ordinal : function (number, period) { - switch (period) { - case 'd': - case 'D': - case 'DDD': - return number + '日'; - case 'M': - return number + '月'; - case 'w': - case 'W': - return number + '周'; - default: - return number; - } - }, - relativeTime : { - future : '%s内', - past : '%s前', - s : '几秒', - m : '1分钟', - mm : '%d分钟', - h : '1小时', - hh : '%d小时', - d : '1天', - dd : '%d天', - M : '1个月', - MM : '%d个月', - y : '1年', - yy : '%d年' - }, - week : { - // GB/T 7408-1994《数据元和交换格式·信息交换·日期和时间表示法》与ISO 8601:1988等效 - dow : 1, // Monday is the first day of the week. - doy : 4 // The week that contains Jan 4th is the first week of the year. - } - }); -})); -// moment.js locale configuration -// locale : traditional chinese (zh-tw) -// author : Ben : https://github.com/ben-lin - -(function (factory) { - factory(moment); -}(function (moment) { - return moment.defineLocale('zh-tw', { - months : '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'), - monthsShort : '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'), - weekdays : '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'), - weekdaysShort : '週日_週一_週二_週三_週四_週五_週六'.split('_'), - weekdaysMin : '日_一_二_三_四_五_六'.split('_'), - longDateFormat : { - LT : 'Ah點mm', - L : 'YYYY年MMMD日', - LL : 'YYYY年MMMD日', - LLL : 'YYYY年MMMD日LT', - LLLL : 'YYYY年MMMD日ddddLT', - l : 'YYYY年MMMD日', - ll : 'YYYY年MMMD日', - lll : 'YYYY年MMMD日LT', - llll : 'YYYY年MMMD日ddddLT' - }, - meridiem : function (hour, minute, isLower) { - var hm = hour * 100 + minute; - if (hm < 900) { - return '早上'; - } else if (hm < 1130) { - return '上午'; - } else if (hm < 1230) { - return '中午'; - } else if (hm < 1800) { - return '下午'; - } else { - return '晚上'; - } - }, - calendar : { - sameDay : '[今天]LT', - nextDay : '[明天]LT', - nextWeek : '[下]ddddLT', - lastDay : '[昨天]LT', - lastWeek : '[上]ddddLT', - sameElse : 'L' - }, - ordinal : function (number, period) { - switch (period) { - case 'd' : - case 'D' : - case 'DDD' : - return number + '日'; - case 'M' : - return number + '月'; - case 'w' : - case 'W' : - return number + '週'; - default : - return number; - } - }, - relativeTime : { - future : '%s內', - past : '%s前', - s : '幾秒', - m : '一分鐘', - mm : '%d分鐘', - h : '一小時', - hh : '%d小時', - d : '一天', - dd : '%d天', - M : '一個月', - MM : '%d個月', - y : '一年', - yy : '%d年' - } - }); -})); - - moment.locale('en'); - - - /************************************ - Exposing Moment - ************************************/ - - function makeGlobal(shouldDeprecate) { - /*global ender:false */ - if (typeof ender !== 'undefined') { - return; - } - oldGlobalMoment = globalScope.moment; - if (shouldDeprecate) { - globalScope.moment = deprecate( - 'Accessing Moment through the global scope is ' + - 'deprecated, and will be removed in an upcoming ' + - 'release.', - moment); - } else { - globalScope.moment = moment; - } - } - - // CommonJS module is defined - if (hasModule) { - module.exports = moment; - } else if (typeof define === 'function' && define.amd) { - define('moment', function (require, exports, module) { - if (module.config && module.config() && module.config().noGlobal === true) { - // release the global variable - globalScope.moment = oldGlobalMoment; - } - - return moment; - }); - makeGlobal(true); - } else { - makeGlobal(); - } -}).call(this); From c3e4b611a61646d5de6988e29133bbc4107d7bb5 Mon Sep 17 00:00:00 2001 From: Simon Busborg Date: Tue, 31 May 2016 11:18:34 +0200 Subject: [PATCH 112/535] added subviews --- .../src/less/components/umb-packages.less | 10 +- .../views/packagesNew/overview.controller.js | 19 +++ .../src/views/packagesNew/overview.html | 91 +------------ .../views/install-local.controller.js | 7 + .../packagesNew/views/install-local.html | 7 + .../views/packagesNew/views/installed.html | 1 + .../packagesNew/views/repo.controller.js | 120 ++++++++++++++++++ .../src/views/packagesNew/views/repo.html | 91 +++++++++++++ 8 files changed, 255 insertions(+), 91 deletions(-) create mode 100644 src/Umbraco.Web.UI.Client/src/views/packagesNew/views/install-local.controller.js create mode 100644 src/Umbraco.Web.UI.Client/src/views/packagesNew/views/install-local.html create mode 100644 src/Umbraco.Web.UI.Client/src/views/packagesNew/views/installed.html create mode 100644 src/Umbraco.Web.UI.Client/src/views/packagesNew/views/repo.controller.js create mode 100644 src/Umbraco.Web.UI.Client/src/views/packagesNew/views/repo.html diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less index 658c690f39..6becc6805f 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less @@ -48,6 +48,7 @@ justify-content: center; position: relative; + box-sizing: border-box; height: 100%; width: 100%; @@ -237,7 +238,7 @@ max-width: 25%; - font-size: 13px; + font-size: 14px; font-weight: bold; color: @black; @@ -266,11 +267,8 @@ } .umb-packages-categories.-collapsed .umb-packages-category { - margin-right: 20px; - - &:last-child { - margin-right: 0; - } + margin-right: 15px; + margin-left: 15px; } .-ma0 { diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.controller.js b/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.controller.js index d98212e8fe..166b020a90 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.controller.js @@ -11,6 +11,25 @@ vm.selectCategory = selectCategory; vm.showPackageDetails = showPackageDetails; + vm.page.navigation = [ + { + "name": "Packages", + "icon": "icon-cloud", + "view": "views/packagesNew/views/repo.html", + "active": true + }, + { + "name": "Installed", + "icon": "icon-box", + "view": "views/packagesNew/views/installed.html" + }, + { + "name": "Install local", + "icon": "icon-add", + "view": "views/packagesNew/views/install-local.html" + } + ]; + vm.categories = [ { "id": 1, diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.html b/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.html index 3d18e27411..3f666ffba2 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.html +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.html @@ -11,96 +11,17 @@ name-locked="true" hide-icon="true" hide-description="true" + navigation="vm.page.navigation" hide-alias="true"> - - - - - - - - - - - - - - - -

    Popular

    - - - -

    Latest

    - + +
    diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/install-local.controller.js b/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/install-local.controller.js new file mode 100644 index 0000000000..9ac88fe6f9 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/install-local.controller.js @@ -0,0 +1,7 @@ +(function () { + "use strict"; + + + angular.module("umbraco").controller("Umbraco.Editors.Packages.InstallLocalController"); + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/install-local.html b/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/install-local.html new file mode 100644 index 0000000000..fa93b06f48 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/install-local.html @@ -0,0 +1,7 @@ +
    + + + + Install Local + +
    diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/installed.html b/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/installed.html new file mode 100644 index 0000000000..84376928ca --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/installed.html @@ -0,0 +1 @@ +Installed diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/repo.controller.js b/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/repo.controller.js new file mode 100644 index 0000000000..8286f3ff31 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/repo.controller.js @@ -0,0 +1,120 @@ +(function () { + "use strict"; + + function PackagesRepoController($scope, $route, $location) { + + var vm = this; + + vm.selectCategory = selectCategory; + vm.showPackageDetails = showPackageDetails; + + vm.categories = [ + { + "id": 1, + "icon": "icon-male-and-female", + "name": "All", + "active": true + }, + { + "icon": "icon-male-and-female", + "name": "Collaboration", + "active": false + }, + { + "id": 2, + "icon": "icon-molecular-network", + "name": "Backoffice extensions" + }, + { + "id": 3, + "icon": "icon-brackets", + "name": "Developer tools" + }, + { + "id": 4, + "icon": "icon-wand", + "name": "Starter kits" + }, + { + "id": 5, + "icon": "icon-medal", + "name": "Umbraco Pro" + }, + { + "id": 6, + "icon": "icon-wrench", + "name": "Website utilities" + } + ]; + + vm.packages = [ + { + "id": 1, + "name": "uSightly", + "description": "An HTML5 audio player based on jPlayer", + "karma": "1", + "downloads": "1672", + "icon":"https://our.umbraco.org/media/wiki/150283/635768313097111400_usightlylogopng.png?bgcolor=fff&height=154&width=281&format=png" + }, + { + "id": 2, + "name": "Kill IE6", + "description": "A simple port of the IE6 warning script (http://code.google.com/p/ie6-upgrade-warning/) to use in your Umbraco websites.", + "karma": "11", + "downloads": "688", + "icon":"https://our.umbraco.org/media/wiki/9138/634697622367666000_offroadcode-100x100.png?bgcolor=fff&height=154&width=281&format=png" + }, + { + "id": 3, + "name": "Examine Media Indexer", + "description": "CogUmbracoExamineMediaIndexer", + "karma": "3", + "downloads": "1329", + "icon":"https://our.umbraco.org/media/wiki/50703/634782902373558000_cogworks.jpg?bgcolor=fff&height=154&width=281&format=png" + }, + { + "id": 4, + "name": "SVG Icon Picker", + "description": "A picker, for picking icons from an SVG spritesheet.", + "karma": "5", + "downloads": "8", + "icon":"https://our.umbraco.org/media/wiki/154472/635997115126742822_logopng.png?bgcolor=fff&height=154&width=281&format=png" + }, + { + "id": 5, + "name": "Pipeline CRM", + "description": "Pipeline is a social CRM that lives in Umbraco back-office. It tracks opportunities and helps teams collaborate with timelines and tasks. It stores information about your customers and your interactions with them. It integrates with your website, capturing opportunities from forms and powering personal portals.", + "karma": "3", + "downloads": "105", + "icon":"https://our.umbraco.org/media/wiki/152476/635917291068518788_pipeline-crm-logopng.png?bgcolor=fff&height=154&width=281&format=png" + }, + { + "id": 6, + "name": "CodeMirror", + "description": "CodeMirror Editor for Umbraco", + "karma": "1", + "downloads": "70", + "icon":"https://our.umbraco.org/media/wiki/151028/635810233171153461_logopng.png?bgcolor=fff&height=154&width=281&format=png" + } + ]; + + function selectCategory(category) { + var section = $route.current.params.section; + var tree = $route.current.params.tree; + var path = "/" + section + "/" + tree + "/category/" + category.id; + $location.path(path); + } + + function showPackageDetails(selectedPackage) { + var section = $route.current.params.section; + var tree = $route.current.params.tree; + var path = "/" + section + "/" + tree + "/details/" + selectedPackage.id; + $location.path(path); + } + + + } + + angular.module("umbraco").controller("Umbraco.Editors.Packages.RepoController", PackagesRepoController); + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/repo.html b/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/repo.html new file mode 100644 index 0000000000..bd2dc96f77 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/repo.html @@ -0,0 +1,91 @@ + From 03d53737a04c8cd2bbe0acddc48d82629a07741e Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 31 May 2016 13:39:14 +0200 Subject: [PATCH 113/535] Fixes issue with a zero offset time - which in JS also means false, so need to check for undefined explicitly --- .../views/propertyeditors/datepicker/datepicker.controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js index 95d0a1bdf6..bb12f0404d 100644 --- a/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/propertyeditors/datepicker/datepicker.controller.js @@ -68,7 +68,7 @@ function dateTimePickerController($scope, notificationsService, assetsService, a var elementData = $element.find("div:first").data().DateTimePicker; if ($scope.model.config.pickTime) { //check if we are supposed to offset the time - if ($scope.model.value && $scope.model.config.offsetTime === "1" && Umbraco.Sys.ServerVariables.application.serverTimeOffset) { + if ($scope.model.value && $scope.model.config.offsetTime === "1" && Umbraco.Sys.ServerVariables.application.serverTimeOffset !== undefined) { $scope.model.value = dateHelper.convertToServerStringTime(elementData.getDate(), Umbraco.Sys.ServerVariables.application.serverTimeOffset); $scope.serverTime = dateHelper.convertToServerStringTime(elementData.getDate(), Umbraco.Sys.ServerVariables.application.serverTimeOffset, "YYYY-MM-DD HH:mm:ss Z"); } From 5ba2967c15b839ecf9101302e543c63b3f37dea2 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 31 May 2016 14:02:07 +0200 Subject: [PATCH 114/535] added design for package details --- .../src/less/components/umb-packages.less | 158 ++++++++++++++++++ .../views/packagesNew/details.controller.js | 76 +++++---- .../src/views/packagesNew/details.html | 126 ++++++++++++-- 3 files changed, 316 insertions(+), 44 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less index 6becc6805f..46516c48d4 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less @@ -215,6 +215,11 @@ background-color: @blueDark; } +.umb-era-button.-full-width { + display: block; + width: 100%; +} + /* CATEGORIES */ @@ -280,3 +285,156 @@ opacity: 1; border-bottom: 2px solid @black; } + +/* PACKAGE DETAILS */ + +.umb-package-details { + display: flex; +} + +.umb-package-details__main-content { + flex: 1 1 auto; + margin-right: 40px; +} + +.umb-package-details__sidebar { + flex: 0 0 350px; +} + +.umb-package-details__section { + background: @grayLighter; + padding: 20px; + margin-bottom: 20px; + border-radius: 3px; +} + +.umb-package-details__section-title { + font-size: 17px; + font-weight: bold; + color: black; + margin-top: 0; + margin-bottom: 15px; +} + +.umb-package-details__section-description { + font-size: 12px; + line-height: 1.6em; + margin-bottom: 15px; +} + +.umb-package-details__information-item { + display: flex; + margin-bottom: 5px; + font-size: 13px; +} + +.umb-package-details__information-item-label { + color: black; + font-weight: bold; + margin-right: 3px; +} + +.umb-package-details__information-item-label-2 { + font-size: 12px; + color: @grayMed; +} + +.umb-package-details__compatability { + margin-bottom: 15px; +} + +.umb-package-details__compatability-label { + margin-bottom: 3px; +} + +.umb-package-details__description { + margin-bottom: 20px; + line-height: 1.6em; +} + +.umb-package-details__description p { + margin-bottom: 20px; +} + +/* Links */ + +.umb-package-details__link { + color: #DA3287; +} + +.umb-package-details__link:hover { + color: #B32D71; + text-decoration: none; +} + +/* Owner profile */ + +.umb-package-details__owner-profile { + display: flex; + align-items: center; +} +.umb-package-details__owner-profile-avatar { + margin-right: 15px; +} + +.umb-package-details__owner-profile-name { + font-size: 15px; + color: #000000; + font-weight: bold; +} + +.umb-package-details__owner-profile-karma { + font-size: 12px; + color: @grayMed; +} + +/* gallery */ + +.umb-gallery__thumbnails { + display: flex; + flex-wrap: wrap; +} + +.umb-gallery__thumbnail { + flex: 1 1 100px; + border: 1px solid @grayLight; + border-radius: 3px; + margin: 5px; + padding: 10px; + box-sizing: border-box; +} + +.umb-gallery__thumbnail:hover { + cursor: pointer; + border-color: @blue; +} + +/* Avatar */ + +.umb-avatar { + border-radius: 50%; + width: 50px; +} + +/* Progress bar */ + +.umb-progress-bar { + background: @grayLight; + width: 100%; + display: block; + height: 10px; + border-radius: 10px; + box-sizing: border-box; + position: relative; + overflow: hidden; +} + +.umb-progress-bar__progress { + background: #50C878; + position: absolute; + left: 0; + top: 0; + bottom: 0; + width: 100%; + border-radius: 10px; +} diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/details.controller.js b/src/Umbraco.Web.UI.Client/src/views/packagesNew/details.controller.js index 834c894c0c..7f4a48ebb9 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/details.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/details.controller.js @@ -9,55 +9,29 @@ vm.package = { "name": "Merchello", - "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Curabitur dignissim purus pulvinar odio iaculis, sit amet euismod arcu volutpat. Sed ut hendrerit sem. Vestibulum enim nisl, luctus quis cursus et, porttitor a ligula. Donec sed congue urna. Integer tincidunt ultrices lorem vitae suscipit. Sed non turpis massa. Donec et velit ante. Sed interdum lectus id lorem congue, sit amet lacinia ex placerat. In id orci sed augue cursus sodales.", + "description": "<p>Merchello is a high performance, designer friendly, open source Umbraco ecommerce package built for the store owner.</p> <p><strong>What Merchello does for you</strong></p> <p>In version 1, Merchello supports a large variety of products with options that can be attached to a single warehouse, processes orders, manages taxes and shipping, and sends out email notifications to your customers. The beauty of Merchello is that while it oversees all of your products, orders, and store settings, it allows Umbraco to maintain your content. This seamless integration gives you the flexibility to build your store in any way imagineable on a robust platform capable of handling a wide variety of store sizes.</p> <p><strong>Find out more on our website</strong></p> <p><strong><a href="https://merchello.com">https://merchello.com</a></strong></p> <p><strong>Contribute</strong></p> <p>We would love and need your help. If you want to contribute to Merchello's core, the easiest way to get started is to fork the project on https://github.com/merchello/Merchello and open src/Merchello.sln in Visual Studio. We're excited to see what you do!</p> <p><strong>Starter Kit</strong></p> <p>We have built a simple starter kit for Merchello called Bazaar, and you can download it below in the package files tab.</p>", "compatibility": [ { "version": "7.4.x", - "compatibility": "100%" + "percentage": "100" }, { "version": "7.3.x", - "compatibility": "86%" + "percentage": "86" }, { "version": "7.2.x", - "compatibility": "93%" + "percentage": "93" }, { "version": "7.1.x", - "compatibility": "100%" - }, - { - "version": "7.0.x", - "compatibility": "untested" - }, - { - "version": "6.1.x", - "compatibility": "untested" - }, - { - "version": "6.0.x", - "compatibility": "untested" - }, - { - "version": "4.11.x", - "compatibility": "untested" - }, - { - "version": "4.10.x", - "compatibility": "untested" - }, - { - "version": "4.9.1", - "compatibility": "untested" - }, - { - "version": "4.9.0", - "compatibility": "untested" + "percentage": "100" } ], "information": { "owner": "Rusty Swayne", + "ownerAvatar": "https://our.umbraco.org/media/upload/d476d257-a494-46d9-9a00-56c2f94a55c8/our-profile.jpg?width=200&height=200&mode=crop", + "ownerKarma": "2673", "contributors": [ { "name": "Lee" @@ -68,7 +42,7 @@ ], "created": "18/12/2013", "currentVersion": "2.0.0", - ".netVersion": "4.5", + "netVersion": "4.5", "license": "MIT", "downloads": "4198", "karma": "53" @@ -82,6 +56,40 @@ "name": "Issue tracker", "url": "http://issues.merchello.com/youtrack/oauth?state=%2Fyoutrack%2FrootGo" } + ], + "images": [ + { + "thumbnail": "https://our.umbraco.org/media/wiki/104946/635591947547374885_Product-Listpng.png?bgcolor=fff&height=154&width=281&format=png", + "source": "https://our.umbraco.org/media/wiki/104946/635591947547374885_Product-Listpng.png" + }, + { + "thumbnail": "https://our.umbraco.org/media/wiki/104946/635591947547374885_Product-Listpng.png?bgcolor=fff&height=154&width=281&format=png", + "source": "https://our.umbraco.org/media/wiki/104946/635591947547374885_Product-Listpng.png" + }, + { + "thumbnail": "https://our.umbraco.org/media/wiki/104946/635591947547374885_Product-Listpng.png?bgcolor=fff&height=154&width=281&format=png", + "source": "https://our.umbraco.org/media/wiki/104946/635591947547374885_Product-Listpng.png" + }, + { + "thumbnail": "https://our.umbraco.org/media/wiki/104946/635591947547374885_Product-Listpng.png?bgcolor=fff&height=154&width=281&format=png", + "source": "https://our.umbraco.org/media/wiki/104946/635591947547374885_Product-Listpng.png" + }, + { + "thumbnail": "https://our.umbraco.org/media/wiki/104946/635591947547374885_Product-Listpng.png?bgcolor=fff&height=154&width=281&format=png", + "source": "https://our.umbraco.org/media/wiki/104946/635591947547374885_Product-Listpng.png" + }, + { + "thumbnail": "https://our.umbraco.org/media/wiki/104946/635591947547374885_Product-Listpng.png?bgcolor=fff&height=154&width=281&format=png", + "source": "https://our.umbraco.org/media/wiki/104946/635591947547374885_Product-Listpng.png" + }, + { + "thumbnail": "https://our.umbraco.org/media/wiki/104946/635591947547374885_Product-Listpng.png?bgcolor=fff&height=154&width=281&format=png", + "source": "https://our.umbraco.org/media/wiki/104946/635591947547374885_Product-Listpng.png" + }, + { + "thumbnail": "https://our.umbraco.org/media/wiki/104946/635591947547374885_Product-Listpng.png?bgcolor=fff&height=154&width=281&format=png", + "source": "https://our.umbraco.org/media/wiki/104946/635591947547374885_Product-Listpng.png" + } ] }; diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/details.html b/src/Umbraco.Web.UI.Client/src/views/packagesNew/details.html index 595dc03868..fa69f55407 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/details.html +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/details.html @@ -4,7 +4,7 @@
    - + -
    {{ vm.package | json }}
    +
    + +
    + +
    + + + +
    + +
    + +
    + +
    + +
    +
    +
    + +
    +
    +
    {{ vm.package.information.owner }}
    +
    + {{ vm.package.information.owner }} has {{ vm.package.information.ownerKarma }} karma points +
    +
    +
    +
    + +
    +
    Information
    +
    + +
    +
    Owner:
    +
    {{vm.package.information.owner}}
    +
    + +
    +
    Contributors:
    + +
    + +
    +
    Created:
    +
    {{vm.package.information.created}}
    +
    + +
    +
    Current version:
    +
    {{vm.package.information.created}}
    +
    + +
    +
    .Net Version:
    +
    {{vm.package.information.netVersion}}
    +
    + +
    +
    License:
    +
    {{vm.package.information.license}}
    +
    + +
    +
    Downloads:
    +
    {{vm.package.information.downloads}}
    +
    + +
    +
    Karma:
    +
    {{vm.package.information.karma}}
    +
    + +
    +
    + +
    +
    Compatibility
    +
    This project is compatible with the following versions as reported by community members who have downloaded this package:
    +
    +
    + {{compatibility.version}} + ({{compatibility.percentage}}%) +
    +
    + +
    +
    +
    + +
    +
    External sources
    + + +
    + +
    + +
    - - - - Breadcrumbs here - - - -
    From cff7dbc81a64e93f957eccf4dc5bb8875af7e3c2 Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Tue, 31 May 2016 15:21:37 +0200 Subject: [PATCH 115/535] Temp u4 8495 (#1293) * U4-8495 Create YML file for AppVeyor * Secret token needs to be in single quotes * Secure token instead of a configuration variable should make the slack notification work * Only post to Slack when build fails --- appveyor.yml | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 appveyor.yml diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000000..db69da4978 --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,51 @@ +version: '{build}' +shallow_clone: true +build_script: +- cmd: >- + cd build + + SET "release=" + + FOR /F "skip=1 delims=" %%i IN (UmbracoVersion.txt) DO IF NOT DEFINED release SET "release=%%i" + + SET PATH=C:\Program Files (x86)\MSBuild\14.0\Bin;%PATH% + + ECHO %PATH% + + + ECHO Building Release %release% build%APPVEYOR_BUILD_NUMBER% + + + SET nuGetFolder=%CD%\..\src\packages\ + + ..\src\.nuget\NuGet.exe sources Add -Name MyGetUmbracoCore -Source https://www.myget.org/F/umbracocore/api/v2/ >NUL + + ..\src\.nuget\NuGet.exe install ..\src\Umbraco.Web.UI\packages.config -OutputDirectory %nuGetFolder% -Verbosity quiet + + + IF EXIST ..\src\umbraco.businesslogic\packages.config ..\src\.nuget\NuGet.exe install ..\src\umbraco.businesslogic\packages.config -OutputDirectory %nuGetFolder% -Verbosity quiet + + ..\src\.nuget\NuGet.exe install ..\src\Umbraco.Core\packages.config -OutputDirectory %nuGetFolder% -Verbosity quiet + + + SET MSBUILD="C:\Program Files (x86)\MSBuild\14.0\Bin\MsBuild.exe" + + %MSBUILD% "../src/Umbraco.Tests/Umbraco.Tests.csproj" /verbosity:minimal + + + build.bat %release% build%APPVEYOR_BUILD_NUMBER% + + + ECHO %PATH% +test: + assemblies: src\Umbraco.Tests\bin\Debug\Umbraco.Tests.dll +artifacts: +- path: build\UmbracoCms.* +notifications: +- provider: Slack + auth_token: + secure: v2csJi2V5ghR0rPdODK8GJdOGNCA+XaK84iQ9MdPOClqB+VU+40ybdKp6gPirGSH + channel: '#build-umbraco-core' + on_build_success: false + on_build_failure: true + on_build_status_changed: false \ No newline at end of file From 8b3160cd79ece8f1768567904dbbf401c768742e Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 31 May 2016 15:56:56 +0200 Subject: [PATCH 116/535] remove unused model --- src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.html b/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.html index 3f666ffba2..d5ec07db74 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.html +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.html @@ -19,8 +19,7 @@ + sub-views="vm.page.navigation">
    From c36db267ce2415401f64bec18a80a45aa7637466 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 31 May 2016 15:57:34 +0200 Subject: [PATCH 117/535] add val-form-manager to fix js errors --- src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.html b/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.html index d5ec07db74..f698580e14 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.html +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/overview.html @@ -2,7 +2,7 @@ -
    + From 4545e8353401ed48e80804d6183eeba45e9c67b4 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 31 May 2016 16:00:23 +0200 Subject: [PATCH 118/535] added list for installed packages --- .../src/less/components/umb-packages.less | 61 ++++++++++++++++ .../packagesNew/views/installed.controller.js | 69 +++++++++++++++++++ .../views/packagesNew/views/installed.html | 27 +++++++- 3 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 src/Umbraco.Web.UI.Client/src/views/packagesNew/views/installed.controller.js diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less index 46516c48d4..12c4b3794b 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less @@ -1,3 +1,14 @@ +.umb-packages-view-title { + font-size: 20px; + font-weight: bold; + color: @black; + margin-bottom: 30px; +} + +.umb-packages-view-wrapper { + padding: 20px 60px; +} + .umb-packages-search { width: 100%; @@ -215,6 +226,11 @@ background-color: @blueDark; } +.umb-era-button.-red-orange { + background-color: #FF3F34; + color: white; +} + .umb-era-button.-full-width { display: block; width: 100%; @@ -438,3 +454,48 @@ width: 100%; border-radius: 10px; } + +/* PACKAGE LIST */ + +.umb-package-list { + display: flex; + flex-direction: column; +} + +.umb-package-list__item { + display: flex; + flex-direction: row; + background: @grayLighter; + margin-bottom: 10px; + border-radius: 3px; + padding: 20px; + align-items: center; +} + +.umb-package-list__item-icon { + flex: 0 0 50px; + margin-right: 20px; +} + +.umb-package-list__item-content { + flex: 1 1 auto; + margin-right: 20px; +} + +.umb-package-list__item-name { + font-size: 16px; + margin-bottom: 5px; + color: @black; + font-weight: bold; +} + +.umb-package-list__item-description { + font-size: 14px; + color: @grayMed; +} + +.umb-package-list__item-actions { + flex: 1 1 auto; + display: flex; + justify-content: flex-end; +} diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/installed.controller.js b/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/installed.controller.js new file mode 100644 index 0000000000..a4348df277 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/installed.controller.js @@ -0,0 +1,69 @@ +(function () { + "use strict"; + + function PackagesInstalledController($scope, $route, $location) { + + var vm = this; + + vm.installedPackages = [ + { + "id": 1, + "name": "uSightly", + "description": "An HTML5 audio player based on jPlayer", + "karma": "1", + "downloads": "1672", + "icon":"https://our.umbraco.org/media/wiki/150283/635768313097111400_usightlylogopng.png?bgcolor=fff&height=154&width=281&format=png" + }, + { + "id": 2, + "name": "Kill IE6", + "description": "A simple port of the IE6 warning script (http://code.google.com/p/ie6-upgrade-warning/) to use in your Umbraco websites.", + "karma": "11", + "downloads": "688", + "icon":"https://our.umbraco.org/media/wiki/9138/634697622367666000_offroadcode-100x100.png?bgcolor=fff&height=154&width=281&format=png" + }, + { + "id": 3, + "name": "Examine Media Indexer", + "description": "CogUmbracoExamineMediaIndexer", + "karma": "3", + "downloads": "1329", + "icon":"https://our.umbraco.org/media/wiki/50703/634782902373558000_cogworks.jpg?bgcolor=fff&height=154&width=281&format=png" + }, + { + "id": 4, + "name": "SVG Icon Picker", + "description": "A picker, for picking icons from an SVG spritesheet.", + "karma": "5", + "downloads": "8", + "icon":"https://our.umbraco.org/media/wiki/154472/635997115126742822_logopng.png?bgcolor=fff&height=154&width=281&format=png" + }, + { + "id": 5, + "name": "Pipeline CRM", + "description": "Pipeline is a social CRM that lives in Umbraco back-office. It tracks opportunities and helps teams collaborate with timelines and tasks. It stores information about your customers and your interactions with them. It integrates with your website, capturing opportunities from forms and powering personal portals.", + "karma": "3", + "downloads": "105", + "icon":"https://our.umbraco.org/media/wiki/152476/635917291068518788_pipeline-crm-logopng.png?bgcolor=fff&height=154&width=281&format=png" + }, + { + "id": 6, + "name": "CodeMirror", + "description": "CodeMirror Editor for Umbraco", + "karma": "1", + "downloads": "70", + "icon":"https://our.umbraco.org/media/wiki/151028/635810233171153461_logopng.png?bgcolor=fff&height=154&width=281&format=png" + } + ]; + + vm.uninstallPackage = uninstallPackage; + + function uninstallPackage(installedPackage) { + console.log(installedPackage); + } + + } + + angular.module("umbraco").controller("Umbraco.Editors.Packages.InstalledController", PackagesInstalledController); + +})(); diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/installed.html b/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/installed.html index 84376928ca..8550cfb00f 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/installed.html +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/installed.html @@ -1 +1,26 @@ -Installed +
    + +
    Installed packages
    + +
    + +
    + +
    + +
    + +
    +
    {{ installedPackage.name }}
    +
    {{ installedPackage.description }}
    +
    + +
    + +
    + +
    + +
    + +
    From c66de2298b9177712876f82cff4d4ea20fb58314 Mon Sep 17 00:00:00 2001 From: Simon Busborg Date: Tue, 31 May 2016 16:18:41 +0200 Subject: [PATCH 119/535] Added local installer --- .../src/less/components/umb-packages.less | 116 +++++++++++++++++- .../views/install-local.controller.js | 26 +++- .../packagesNew/views/install-local.html | 81 +++++++++++- 3 files changed, 213 insertions(+), 10 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less index 12c4b3794b..983a59364c 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less @@ -179,12 +179,10 @@ font-size: 14px; font-weight: bold; - text-transform: capitalize; height: 38px; line-height: 38px; - max-width: 100%; padding: 0 18px; @@ -200,6 +198,8 @@ border-radius: 3px; border: 0 none; + cursor: pointer; + transition: background-color 80ms ease, color 80ms ease; } @@ -226,18 +226,34 @@ background-color: @blueDark; } -.umb-era-button.-red-orange { - background-color: #FF3F34; - color: white; +.umb-era-button.-link { + padding: 0; + background: transparent; } +.umb-era-button.-link:hover { + background-color: transparent; + opacity: .6; +} + +.umb-era-button.-inactive { + cursor: not-allowed; + background: whitesmoke; + color: @grayMed; +} + +.umb-era-button.-inactive:hover { + background: whitesmoke; + color: @grayMed; +} + + .umb-era-button.-full-width { display: block; width: 100%; } - /* CATEGORIES */ .umb-packages-categories { @@ -499,3 +515,91 @@ display: flex; justify-content: flex-end; } + + + +// Install local package + +// Accept terms +.umb-accept-terms { + margin-bottom: 40px; + display: flex; + align-items: center; + + font-size: 13px; +} + +.umb-package-installer-label .label-text { + margin-left: 5px; +} + +.umb-package-installer-label input[type="radio"], +.umb-package-installer-label input[type="checkbox"] { + margin-top: 0px; +} + +.umb-package-installer-label { + display: flex; + align-items: center; + + font-size: 13px; + user-select: none; +} + +// Install local package +.umb-center-allthings { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + + max-width: 640px; + margin: 0 auto; + text-align: center; +} + + +// Upload state +.umb-upload-local input[type="file"] { + display: none; +} + +.umb-upload-local { + display: flex; + flex-direction: row; + align-items: flex-start; + + margin: 40px auto; +} + +.umb-upload-local .loaded { + margin-left: 10px; +} + +.umb-upload-local .upload i { + font-size: 20px; + line-height: 1; +} + +.umb-upload-local .-large { + font-size: 18px; +} + +.uploaded-file-name { + margin-left: 10px; +} + + +// Info state +.umb-info-local { + +} + +.umb-info-local-item { + margin: 10px 0; diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/install-local.controller.js b/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/install-local.controller.js index 9ac88fe6f9..56a67db062 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/install-local.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/install-local.controller.js @@ -1,7 +1,31 @@ (function () { "use strict"; + function PackagesInstallLocalController($scope, $route, $location) { - angular.module("umbraco").controller("Umbraco.Editors.Packages.InstallLocalController"); + var vm = this; + + vm.state = "upload"; + vm.localPackage = { + "packageName": "SvgIconPicker Version: 0.1.0", + "packageAuthor": "Søren Kottal", + "packageAuthorLink": "https://github.com/skttl/", + "packageInfo": "https://github.com/skttl/Umbraco.SvgIconPicker", + "packageLicens": "GPLv3", + "packageLicensLink": "http://www.gnu.org/licenses/quick-guide-gplv3.en.html", + "packageLicensAccept": false, + "packageReadme": false, + "filePath": "", + "riskAccept": false + }; + + vm.loadPackage = loadPackage; + + function loadPackage(){ + vm.state = "packageDetails"; + } + } + + angular.module("umbraco").controller("Umbraco.Editors.Packages.InstallLocalController", PackagesInstallLocalController); })(); diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/install-local.html b/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/install-local.html index fa93b06f48..93fb7d17ff 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/install-local.html +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/install-local.html @@ -1,7 +1,82 @@ -
    +
    - - Install Local + +
    + +

    Install local package

    +

    Browse for local packages, they usally have a ".zip" extension. You can find trusted packages on our.umbraco.com or in the package tab in Umbraco

    + + +
    + +
    + + + + + + +
    + + + +
    +

    {{ vm.localPackage.packageName }}

    + + + + + + + +
    + Accept license + +
    + +
    + Read me +
    + + +
    + +
    +        {{ vm.localPackage | json }}
    +    
    +
    From 86eaacc5d216687205e8c35101b6dd4b6f7172ca Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 31 May 2016 21:10:52 +0200 Subject: [PATCH 120/535] tighten repo overview a bit --- .../src/less/components/umb-packages.less | 65 ++++++------------- .../packagesNew/views/repo.controller.js | 43 ++++++++++-- .../src/views/packagesNew/views/repo.html | 31 +++------ 3 files changed, 67 insertions(+), 72 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less index 983a59364c..e58019553a 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less @@ -11,8 +11,6 @@ .umb-packages-search { width: 100%; - - margin-top: 40px; margin-bottom: 40px; background: @grayLighter; border-radius: 3px; @@ -38,11 +36,10 @@ .umb-packages { - // margin: 0 -10px; + margin: 0 -10px; } - -// List +// Cards .umb-package { float: left; padding: 10px; @@ -50,8 +47,6 @@ width: 20%; } - -// Link (Wrapper) .umb-package-link { display: flex; flex-wrap: wrap; @@ -64,7 +59,7 @@ height: 100%; width: 100%; - border: 2px solid #ececec; + border: 1px solid #ececec; border-radius: 3px; text-decoration: none !important; @@ -93,7 +88,7 @@ text-align: center; background-color: white; - min-height: 80px; + min-height: 60px; } .umb-package-icon img { @@ -107,13 +102,16 @@ padding-right: 15px; padding-bottom: 15px; padding-left: 15px; + padding-top: 15px; text-align: center; + background: @grayLighter; + border-top: 1px solid #ececec; } // Name .umb-package-name { - font-size: 15px; + font-size: 14px; max-width: 250px; margin-bottom: 5px; @@ -263,59 +261,37 @@ margin-bottom: 30px; } - - .umb-packages-category { display: flex; align-items: center; flex: 1 0 auto; justify-content: center; - - opacity: .6; - max-width: 25%; - font-size: 14px; font-weight: bold; color: @black; - box-sizing: border-box; - justify-content: center; + border-top: 1px solid @grayLight; + border-bottom: 1px solid @grayLight; + border-right: 1px solid @grayLight; + padding: 5px; } - .umb-packages-category:hover, -.umb-packages-category:focus { +.umb-packages-category.-active { text-decoration: none; - opacity: 1; + color: @blue; } -.umb-packages-category-icon { - font-size: 20px; - margin-right: 5px; - - display: none; +.umb-packages-category.-first { + border-left: 1px solid @grayLight; + border-radius: 3px 0 0 3px; } -// Collapsed -.umb-packages-categories.-collapsed { - margin-bottom: 0; -} - -.umb-packages-categories.-collapsed .umb-packages-category { - margin-right: 15px; - margin-left: 15px; -} - -.-ma0 { - margin: 0 !important; -} - -.-collapsed .umb-packages-category.-active { - color: @black; - opacity: 1; - border-bottom: 2px solid @black; +.umb-packages-category.-last { + border-right: 1px solid @grayLight; + border-radius: 0 3px 3px 0; } /* PACKAGE DETAILS */ @@ -603,3 +579,4 @@ .umb-info-local-item { margin: 10px 0; +} diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/repo.controller.js b/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/repo.controller.js index 8286f3ff31..5217b0d20c 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/repo.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/repo.controller.js @@ -17,8 +17,7 @@ }, { "icon": "icon-male-and-female", - "name": "Collaboration", - "active": false + "name": "Collaboration" }, { "id": 2, @@ -90,11 +89,43 @@ }, { "id": 6, - "name": "CodeMirror", - "description": "CodeMirror Editor for Umbraco", + "name": "uSightly", + "description": "An HTML5 audio player based on jPlayer", "karma": "1", - "downloads": "70", - "icon":"https://our.umbraco.org/media/wiki/151028/635810233171153461_logopng.png?bgcolor=fff&height=154&width=281&format=png" + "downloads": "1672", + "icon":"https://our.umbraco.org/media/wiki/150283/635768313097111400_usightlylogopng.png?bgcolor=fff&height=154&width=281&format=png" + }, + { + "id": 7, + "name": "Kill IE6", + "description": "A simple port of the IE6 warning script (http://code.google.com/p/ie6-upgrade-warning/) to use in your Umbraco websites.", + "karma": "11", + "downloads": "688", + "icon":"https://our.umbraco.org/media/wiki/9138/634697622367666000_offroadcode-100x100.png?bgcolor=fff&height=154&width=281&format=png" + }, + { + "id": 8, + "name": "Examine Media Indexer", + "description": "CogUmbracoExamineMediaIndexer", + "karma": "3", + "downloads": "1329", + "icon":"https://our.umbraco.org/media/wiki/50703/634782902373558000_cogworks.jpg?bgcolor=fff&height=154&width=281&format=png" + }, + { + "id": 9, + "name": "SVG Icon Picker", + "description": "A picker, for picking icons from an SVG spritesheet.", + "karma": "5", + "downloads": "8", + "icon":"https://our.umbraco.org/media/wiki/154472/635997115126742822_logopng.png?bgcolor=fff&height=154&width=281&format=png" + }, + { + "id": 10, + "name": "Pipeline CRM", + "description": "Pipeline is a social CRM that lives in Umbraco back-office. It tracks opportunities and helps teams collaborate with timelines and tasks. It stores information about your customers and your interactions with them. It integrates with your website, capturing opportunities from forms and powering personal portals.", + "karma": "3", + "downloads": "105", + "icon":"https://our.umbraco.org/media/wiki/152476/635917291068518788_pipeline-crm-logopng.png?bgcolor=fff&height=154&width=281&format=png" } ]; diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/repo.html b/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/repo.html index bd2dc96f77..714be5c0d6 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/repo.html +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/repo.html @@ -1,33 +1,20 @@ -
    - - - - - - - - - - +
    - - - +

    Popular

    From 5858823252a08d2bd40397a2c0af483e35871776 Mon Sep 17 00:00:00 2001 From: Mads Rasmussen Date: Tue, 31 May 2016 21:29:00 +0200 Subject: [PATCH 121/535] add even spacing to sections + a bit more padding to category nav --- .../src/less/components/umb-packages.less | 8 +- .../src/views/packagesNew/views/repo.html | 120 +++++++++--------- 2 files changed, 68 insertions(+), 60 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less index e58019553a..a5916fa14e 100644 --- a/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less +++ b/src/Umbraco.Web.UI.Client/src/less/components/umb-packages.less @@ -9,9 +9,12 @@ padding: 20px 60px; } +.umb-packages-section { + margin-bottom: 40px; +} + .umb-packages-search { width: 100%; - margin-bottom: 40px; background: @grayLighter; border-radius: 3px; padding: 30px; @@ -258,7 +261,6 @@ display: flex; user-select: center; flex-wrap: wrap; - margin-bottom: 30px; } .umb-packages-category { @@ -275,7 +277,7 @@ border-top: 1px solid @grayLight; border-bottom: 1px solid @grayLight; border-right: 1px solid @grayLight; - padding: 5px; + padding: 10px 0; } .umb-packages-category:hover, diff --git a/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/repo.html b/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/repo.html index 714be5c0d6..7aacb9a010 100644 --- a/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/repo.html +++ b/src/Umbraco.Web.UI.Client/src/views/packagesNew/views/repo.html @@ -1,78 +1,84 @@
    - -