From 324cd7e98f0c8ac8a92ed40fbfb7e9575eca863d Mon Sep 17 00:00:00 2001 From: Sebastiaan Janssen Date: Fri, 4 May 2018 10:33:19 +0200 Subject: [PATCH 01/25] Adds a quick start to setup a gulp environment - when you have NPM in the path the pre-requisites get taken care of --- src/Umbraco.Web.UI.Client/setupgulp.bat | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 src/Umbraco.Web.UI.Client/setupgulp.bat diff --git a/src/Umbraco.Web.UI.Client/setupgulp.bat b/src/Umbraco.Web.UI.Client/setupgulp.bat new file mode 100644 index 0000000000..5cddec3747 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/setupgulp.bat @@ -0,0 +1,23 @@ +@ECHO OFF + +ECHO. +ECHO. +ECHO This will only work when you have NPM available on the command line +ECHO Works great with NodeJS Portable - https://gareth.flowers/nodejs-portable/ +ECHO. +ECHO. +set /P c=Are you sure you want to continue [Y/N]? +if /I "%c%" EQU "Y" goto :setupgulp +if /I "%c%" EQU "N" goto :eof + +:setupgulp +call npm install +call npm -g install bower +call npm -g install gulp +call npm -g install gulp-cli + +ECHO. +ECHO. +ECHO You should now be able to run: gulp build +ECHO. +ECHO. \ No newline at end of file From 3f35eca999091e000dd0c8475a6055e5ffb4cc08 Mon Sep 17 00:00:00 2001 From: Dan Booth Date: Thu, 10 May 2018 14:28:16 +0100 Subject: [PATCH 02/25] Fixed ContainsAny method so that it uses the passed in Comparison method (which enabled case-insensitive comparisons to work) --- src/Umbraco.Core/StringExtensions.cs | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/Umbraco.Core/StringExtensions.cs b/src/Umbraco.Core/StringExtensions.cs index b5cb815676..141a8fe28b 100644 --- a/src/Umbraco.Core/StringExtensions.cs +++ b/src/Umbraco.Core/StringExtensions.cs @@ -121,8 +121,8 @@ namespace Umbraco.Core //if the resolution was success, return it, otherwise just return the path, we've detected // it's a path but maybe it's relative and resolution has failed, etc... in which case we're just // returning what was given to us. - return resolvedUrlResult.Success - ? resolvedUrlResult + return resolvedUrlResult.Success + ? resolvedUrlResult : Attempt.Succeed(input); } } @@ -144,7 +144,7 @@ namespace Umbraco.Core } internal static readonly Regex Whitespace = new Regex(@"\s+", RegexOptions.Compiled); - internal static readonly string[] JsonEmpties = new [] { "[]", "{}" }; + internal static readonly string[] JsonEmpties = new[] { "[]", "{}" }; internal static bool DetectIsEmptyJson(this string input) { return JsonEmpties.Contains(Whitespace.Replace(input, string.Empty)); @@ -1436,14 +1436,25 @@ namespace Umbraco.Core return ReplaceMany(text, regexSpecialCharacters); } + /// + /// Checks whether a string "haystack" contains within it any of the strings in the "needles" collection and returns true if it does or false if it doesn't + /// + /// The string to check + /// The collection of strings to check are contained within the first string + /// The type of comparision to perform - defaults to + /// True if any of the needles are contained with haystack; otherwise returns false + /// Added fix to ensure the comparison is used - see http://issues.umbraco.org/issue/U4-11313 public static bool ContainsAny(this string haystack, IEnumerable needles, StringComparison comparison = StringComparison.CurrentCulture) { - if (haystack == null) throw new ArgumentNullException("haystack"); - if (string.IsNullOrEmpty(haystack) == false || needles.Any()) + if (haystack == null) + throw new ArgumentNullException("haystack"); + + if (string.IsNullOrEmpty(haystack) || needles == null || !needles.Any()) { - return needles.Any(value => haystack.IndexOf(value) >= 0); + return false; } - return false; + + return needles.Any(value => haystack.IndexOf(value, comparison) >= 0); } public static bool CsvContains(this string csv, string value) From 9c65ed92f18859445db62c9d641f983a76e51e98 Mon Sep 17 00:00:00 2001 From: Dan Booth Date: Thu, 10 May 2018 14:29:00 +0100 Subject: [PATCH 03/25] Added string ContainsAny tests for the ContainsAny(haystack, needles, comparison) extension method --- .../Strings/StringExtensionsTests.cs | 82 +++++++++++-------- 1 file changed, 48 insertions(+), 34 deletions(-) diff --git a/src/Umbraco.Tests/Strings/StringExtensionsTests.cs b/src/Umbraco.Tests/Strings/StringExtensionsTests.cs index e0e80f3ab2..f5f69e37cd 100644 --- a/src/Umbraco.Tests/Strings/StringExtensionsTests.cs +++ b/src/Umbraco.Tests/Strings/StringExtensionsTests.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using NUnit.Framework; @@ -11,20 +12,20 @@ namespace Umbraco.Tests.Strings [TestFixture] public class StringExtensionsTests { - [SetUp] - public void Setup() - { + [SetUp] + public void Setup() + { ShortStringHelperResolver.Reset(); ShortStringHelperResolver.Current = new ShortStringHelperResolver(new MockShortStringHelper()); - Resolution.Freeze(); - } + Resolution.Freeze(); + } [TearDown] public void TearDown() { ShortStringHelperResolver.Reset(); } - + [TestCase("hello", "world", false)] [TestCase("hello", "hello", true)] [TestCase("hellohellohellohellohellohellohello", "hellohellohellohellohellohellohelloo", false)] @@ -53,43 +54,43 @@ namespace Umbraco.Tests.Strings [TestCase("hello.txt", "hello")] [TestCase("this.is.a.Txt", "this.is.a")] [TestCase("this.is.not.a. Txt", "this.is.not.a. Txt")] - [TestCase("not a file","not a file")] + [TestCase("not a file", "not a file")] public void Strip_File_Extension(string input, string result) { var stripped = input.StripFileExtension(); Assert.AreEqual(stripped, result); } - [TestCase("This is a string to encrypt")] - [TestCase("This is a string to encrypt\nThis is a second line")] - [TestCase(" White space is preserved ")] - [TestCase("\nWhite space is preserved\n")] - public void Encrypt_And_Decrypt(string input) - { - var encrypted = input.EncryptWithMachineKey(); - var decrypted = encrypted.DecryptWithMachineKey(); - Assert.AreNotEqual(input, encrypted); - Assert.AreEqual(input, decrypted); - } + [TestCase("This is a string to encrypt")] + [TestCase("This is a string to encrypt\nThis is a second line")] + [TestCase(" White space is preserved ")] + [TestCase("\nWhite space is preserved\n")] + public void Encrypt_And_Decrypt(string input) + { + var encrypted = input.EncryptWithMachineKey(); + var decrypted = encrypted.DecryptWithMachineKey(); + Assert.AreNotEqual(input, encrypted); + Assert.AreEqual(input, decrypted); + } - [Test()] - public void Encrypt_And_Decrypt_Long_Value() - { - // Generate a really long string - char[] chars = { 'a', 'b', 'c', '1', '2', '3', '\n' }; + [Test()] + public void Encrypt_And_Decrypt_Long_Value() + { + // Generate a really long string + char[] chars = { 'a', 'b', 'c', '1', '2', '3', '\n' }; - string valueToTest = string.Empty; + string valueToTest = string.Empty; - // Create a string 7035 chars long - for (int i = 0; i < 1005; i++) - for (int j = 0; j < chars.Length; j++) - valueToTest += chars[j].ToString(); + // Create a string 7035 chars long + for (int i = 0; i < 1005; i++) + for (int j = 0; j < chars.Length; j++) + valueToTest += chars[j].ToString(); - var encrypted = valueToTest.EncryptWithMachineKey(); - var decrypted = encrypted.DecryptWithMachineKey(); - Assert.AreNotEqual(valueToTest, encrypted); - Assert.AreEqual(valueToTest, decrypted); - } + var encrypted = valueToTest.EncryptWithMachineKey(); + var decrypted = encrypted.DecryptWithMachineKey(); + Assert.AreNotEqual(valueToTest, encrypted); + Assert.AreEqual(valueToTest, decrypted); + } [TestCase("Hello this is my string", " string", "Hello this is my")] [TestCase("Hello this is my string strung", " string", "Hello this is my string strung")] @@ -147,6 +148,19 @@ namespace Umbraco.Tests.Strings Assert.AreEqual(expected, output); } + [TestCase("pineapple", new string[] { "banana", "apple", "blueberry", "strawberry" }, StringComparison.CurrentCulture, true)] + [TestCase("PINEAPPLE", new string[] { "banana", "apple", "blueberry", "strawberry" }, StringComparison.CurrentCulture, false)] + [TestCase("pineapple", new string[] { "banana", "Apple", "blueberry", "strawberry" }, StringComparison.CurrentCulture, false)] + [TestCase("pineapple", new string[] { "banana", "Apple", "blueberry", "strawberry" }, StringComparison.OrdinalIgnoreCase, true)] + [TestCase("pineapple", new string[] { "banana", "blueberry", "strawberry" }, StringComparison.OrdinalIgnoreCase, false)] + [TestCase("Strawberry unicorn pie", new string[] { "Berry" }, StringComparison.OrdinalIgnoreCase, true)] + [TestCase("empty pie", new string[0], StringComparison.OrdinalIgnoreCase, false)] + public void ContainsAny(string haystack, IEnumerable needles, StringComparison comparison, bool expected) + { + bool output = haystack.ContainsAny(needles, comparison); + Assert.AreEqual(expected, output); + } + // FORMAT STRINGS // note: here we just ensure that the proper helper gets called properly @@ -239,7 +253,7 @@ namespace Umbraco.Tests.Strings [Test] public void ReplaceManyByOneChar() { - var output = "JUST-ANYTHING".ReplaceMany(new char[] {}, '*'); + var output = "JUST-ANYTHING".ReplaceMany(new char[] { }, '*'); Assert.AreEqual("REPLACE-MANY-B::JUST-ANYTHING", output); } } From d05819e125167ddec5b9d9496bb5c5335a7b7689 Mon Sep 17 00:00:00 2001 From: Poornima Nayar Date: Fri, 11 May 2018 12:23:51 +0100 Subject: [PATCH 04/25] Fixed typos in tours --- .../BackOfficeTours/getting-started.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Umbraco.Web.UI/config/BackOfficeTours/getting-started.json b/src/Umbraco.Web.UI/config/BackOfficeTours/getting-started.json index 836b7a965c..4556fd6496 100644 --- a/src/Umbraco.Web.UI/config/BackOfficeTours/getting-started.json +++ b/src/Umbraco.Web.UI/config/BackOfficeTours/getting-started.json @@ -73,7 +73,7 @@ { "element": "#applications [data-element='section-help']", "title": "Help", - "content": "If you ever find yourself in trouble click here to open the help drawer.", + "content": "If you ever find yourself in trouble click here to open the Help drawer.", "event": "click", "backdropOpacity": 0.6 }, @@ -108,7 +108,7 @@ "steps": [ { "title": "Create your first Document Type", - "content": "

Step 1 of any site is to create a Document Type.
A Document Type is a template for content. For each type of content you want to create you'll create a Document Type. This will define were content based on this Document Type can be created, how many properties it holds and what the input method should be for these properties.

When you have at least one Document type in place you can start creating content and this content can the be used in a template.

In this tour you will learn how to set up a basic Document Type with a property to enter a short text.

", + "content": "

Step 1 of any site is to create a Document Type.
A Document Type is a template for content. For each type of content you want to create you'll create a Document Type. This will define where content based on this Document Type can be created, how many properties it holds and what the input method should be for these properties.

When you have at least one Document type in place you can start creating content and this content can then be used in a template.

In this tour you will learn how to set up a basic Document Type with a property to enter a short text.

", "type": "intro" }, { @@ -121,14 +121,14 @@ { "element": "#tree [data-element='tree-item-documentTypes']", "title": "Create Document Type", - "content": "

Hover the Document Type tree and click the three small dots to open the context menu.

", + "content": "

Hover over the Document Type tree and click the three small dots to open the context menu.

", "event": "click", "eventElement": "#tree [data-element='tree-item-documentTypes'] [data-element='tree-item-options']" }, { "element": "#dialog [data-element='action-documentType']", "title": "Create Document Type", - "content": "

Click Document Type to create a new document type with a template. The template will be automatically created and set as the default template for this Document Type

You will use the template in a later tour render content.

", + "content": "

Click Document Type to create a new document type with a template. The template will be automatically created and set as the default template for this Document Type

You will use the template in a later tour to render content.

", "event": "click" }, { @@ -157,7 +157,7 @@ { "element": "[data-element='property-add']", "title": "Add a property", - "content": "

Properties are the different input fields on a content page.

On our Home Page we wan't to add a welcome text.

Click Add property to open the property dialog.

", + "content": "

Properties are the different input fields on a content page.

On our Home Page we want to add a welcome text.

Click Add property to open the property dialog.

", "event": "click" }, { @@ -181,7 +181,7 @@ "element": "[data-element~='overlay-editor-picker']", "elementPreventClick": true, "title": "Editor picker", - "content": "

In the editor picker dialog we can pick one of the many build in editor.

You can choose from preconfigured data types (Reuse) or create a new configuration (Available editors)

" + "content": "

In the editor picker dialog we can pick one of the many built-in editor.

You can choose from preconfigured data types (Reuse) or create a new configuration (Available editors)

" }, { "element": "[data-element~='overlay-editor-picker'] [data-element='editor-Textarea']", @@ -193,12 +193,12 @@ "element": "[data-element~='overlay-editor-settings']", "elementPreventClick": true, "title": "Editor settings", - "content": "Each property editor can have individual settings. For the textarea editor you can set a charachter limit but in this case it is not needed" + "content": "Each property editor can have individual settings. For the textarea editor you can set a character limit but in this case it is not needed" }, { "element": "[data-element~='overlay-editor-settings'] [data-element='button-overlaySubmit']", "title": "Save editor", - "content": "Click Submit to save the editor.", + "content": "Click Submit to save the changes.", "event": "click" }, { @@ -245,7 +245,7 @@ { "element": "[data-element='tree-root']", "title": "Open context menu", - "content": "

Open the context menu by hovering the root of the content section.

Now click the three small dots to the right.

", + "content": "

Open the context menu by hovering over the root of the content section.

Now click the three small dots to the right.

", "event": "click", "eventElement": "[data-element='tree-root'] [data-element='tree-item-options']" }, From 9a8f71dd8196a32ba453d96ccce5c83efb10d9e2 Mon Sep 17 00:00:00 2001 From: Dan Booth Date: Fri, 11 May 2018 14:53:03 +0100 Subject: [PATCH 05/25] Fixed issue where TypedMedia didn't work with UDI strings --- src/Umbraco.Web/UmbracoHelper.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web/UmbracoHelper.cs b/src/Umbraco.Web/UmbracoHelper.cs index 6ae449a584..75fba514cc 100644 --- a/src/Umbraco.Web/UmbracoHelper.cs +++ b/src/Umbraco.Web/UmbracoHelper.cs @@ -1033,10 +1033,14 @@ namespace Umbraco.Web return ContentQuery.TypedMedia(id); } + /// + /// Returns typed Media content based on an Identifier + /// + /// The id - this can be the numeric Id such as '1234' or a UDI string such as 'umb://media/a1276990a50e4784b25458fc8d0c487c' + /// PublishedContent if a corresponding media Id exists; otherwise null public IPublishedContent TypedMedia(string id) { - int intId; - return ConvertIdObjectToInt(id, out intId) ? ContentQuery.TypedMedia(intId) : null; + return TypedMediaForObject(id); } /// From 2b4cf7d18522ecf023192a82762853b542135085 Mon Sep 17 00:00:00 2001 From: ragivi <2657922+ragivi@users.noreply.github.com> Date: Mon, 14 May 2018 14:48:01 +0200 Subject: [PATCH 06/25] Update preview page In order to avoid indexing. --- src/Umbraco.Web.UI/Umbraco/Views/Preview/Index.cshtml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Umbraco.Web.UI/Umbraco/Views/Preview/Index.cshtml b/src/Umbraco.Web.UI/Umbraco/Views/Preview/Index.cshtml index 621d542edc..02209063fd 100644 --- a/src/Umbraco.Web.UI/Umbraco/Views/Preview/Index.cshtml +++ b/src/Umbraco.Web.UI/Umbraco/Views/Preview/Index.cshtml @@ -10,6 +10,7 @@ +
From 3c82315782793082db827814bc726e95de16e2e2 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Wed, 16 May 2018 12:56:00 +0200 Subject: [PATCH 07/25] cross link to the v8 branch --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8aee632cad..0677314a27 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ [![Build status](https://ci.appveyor.com/api/projects/status/6by6harxtxt0ocdx/branch/dev-v7?svg=true)](https://ci.appveyor.com/project/Umbraco/umbraco-cms-b2cri/branch/dev-v7) +_Looking for Umbraco version 8? [Click here](https://github.com/umbraco/Umbraco-CMS/tree/temp8) to go to the v8 branch_ + Umbraco CMS =========== The friendliest, most flexible and fastest growing ASP.NET CMS used by more than 443,000 websites worldwide: [https://umbraco.com](https://umbraco.com) From 8985d514ec0622ff71f22a69bca522703ddea0f7 Mon Sep 17 00:00:00 2001 From: Shannon Deminick Date: Wed, 16 May 2018 13:36:57 +0200 Subject: [PATCH 08/25] cross link to v8 branch --- CONTRIBUTING.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f8d8aac342..1be84657c0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,5 @@ +_Looking for Umbraco version 8? [Click here](https://github.com/umbraco/Umbraco-CMS/blob/temp8/CONTRIBUTING.md) to go to the v8 branch_ + # Contributing to Umbraco CMS 👍🎉 First off, thanks for taking the time to contribute! 🎉👍 From 1cef87ee3465a1d9960cd962f16fae0d2649bbc4 Mon Sep 17 00:00:00 2001 From: Roberto Bianchi Date: Mon, 21 May 2018 10:20:44 +0200 Subject: [PATCH 09/25] Update README img --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0677314a27..a724d34596 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Umbraco is a free open source Content Management System built on the ASP.NET pla ## Watch an introduction video -[![ScreenShot](http://umbraco.com/images/whatisumbraco.png)](https://umbraco.tv/videos/umbraco-v7/content-editor/basics/introduction/cms-explanation/) +[![ScreenShot](https://shop.umbraco.com/images/whatisumbraco.png)](https://umbraco.tv/videos/umbraco-v7/content-editor/basics/introduction/cms-explanation/) ## Umbraco - The Friendly CMS From 068ad194925bda03e32f60ea7ece5626eb414758 Mon Sep 17 00:00:00 2001 From: Anders Bjerner Date: Tue, 22 May 2018 10:44:43 +0200 Subject: [PATCH 10/25] Health Checks: the warning icon should be orange instead of yellow Both the yellow and orange colors used to be a bit darker, but when more colors were introduced in 7.10.x, the two colors were made a bit lighter. So now the yellow warning icon is hard to see on a white background, but the orange color now looks just right ;) --- .../src/views/dashboard/developer/healthcheck.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/dashboard/developer/healthcheck.html b/src/Umbraco.Web.UI.Client/src/views/dashboard/developer/healthcheck.html index 3d913012d7..1204af7ca4 100644 --- a/src/Umbraco.Web.UI.Client/src/views/dashboard/developer/healthcheck.html +++ b/src/Umbraco.Web.UI.Client/src/views/dashboard/developer/healthcheck.html @@ -31,7 +31,7 @@
- + {{ group.totalWarning }}
From 7c5fe63d0b394aca3195bba8728a346513d319bc Mon Sep 17 00:00:00 2001 From: Simone Chiaretta Date: Fri, 25 May 2018 10:01:12 +0200 Subject: [PATCH 11/25] Sort language by name The issue was that the web API was returning a dictionary that was interpreted as data object by AngularJS, with each key becoming a property of an enormous object, so when binding this object to the select element, it was sorted by property name, thus the key of the array, which was the And being an object it was impossible to sort it again by value. Only option was to convert it to an array. And since the original list of culture is already sorted correctly, no need to sort it again. --- .../src/views/languages/edit.controller.js | 9 ++++++++- src/Umbraco.Web.UI.Client/src/views/languages/edit.html | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Umbraco.Web.UI.Client/src/views/languages/edit.controller.js b/src/Umbraco.Web.UI.Client/src/views/languages/edit.controller.js index 3dc0845afc..6ee5a5bd7a 100644 --- a/src/Umbraco.Web.UI.Client/src/views/languages/edit.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/languages/edit.controller.js @@ -41,7 +41,14 @@ if($routeParams.create) { vm.page.name = vm.labels.addLanguage; - languageResource.getCultures().then(function(cultures) { + languageResource.getCultures().then(function (culturesDictionary) { + var cultures = []; + angular.forEach(culturesDictionary, function (value, key) { + cultures.push({ + name: key, + displayName: value + }); + }); vm.availableCultures = cultures; }); } diff --git a/src/Umbraco.Web.UI.Client/src/views/languages/edit.html b/src/Umbraco.Web.UI.Client/src/views/languages/edit.html index 4e0f3aba60..d2b5ef6433 100644 --- a/src/Umbraco.Web.UI.Client/src/views/languages/edit.html +++ b/src/Umbraco.Web.UI.Client/src/views/languages/edit.html @@ -25,7 +25,7 @@ Required From 4705a6bc1094d55cb88c28e272959dfa656bf7c6 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 30 May 2018 15:21:59 +1000 Subject: [PATCH 12/25] updates views web.config --- src/Umbraco.Web.UI/Views/Web.config | 38 +++++++++-------------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/src/Umbraco.Web.UI/Views/Web.config b/src/Umbraco.Web.UI/Views/Web.config index 9c0bd5b5df..b809c2167e 100644 --- a/src/Umbraco.Web.UI/Views/Web.config +++ b/src/Umbraco.Web.UI/Views/Web.config @@ -1,6 +1,6 @@ - +
@@ -31,35 +31,19 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + From 2c41f3dbfada815a44816f21c6cccf59a1a2fced Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 30 May 2018 15:32:33 +1000 Subject: [PATCH 13/25] Updated web.config for /umbraco/views --- src/Umbraco.Web.UI/Umbraco/Views/{Preview => }/web.config | 8 ++++++++ 1 file changed, 8 insertions(+) rename src/Umbraco.Web.UI/Umbraco/Views/{Preview => }/web.config (79%) diff --git a/src/Umbraco.Web.UI/Umbraco/Views/Preview/web.config b/src/Umbraco.Web.UI/Umbraco/Views/web.config similarity index 79% rename from src/Umbraco.Web.UI/Umbraco/Views/Preview/web.config rename to src/Umbraco.Web.UI/Umbraco/Views/web.config index 339972c139..853a4935fb 100644 --- a/src/Umbraco.Web.UI/Umbraco/Views/Preview/web.config +++ b/src/Umbraco.Web.UI/Umbraco/Views/web.config @@ -16,6 +16,13 @@ + + + + + + + @@ -35,6 +42,7 @@ + From 6868279909cb970ef10319dddd2298840aa5d301 Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 30 May 2018 16:15:23 +1000 Subject: [PATCH 14/25] csproj bump --- src/Umbraco.Web.UI/Umbraco.Web.UI.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj index 89151e65f4..c6877a1d9c 100644 --- a/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj +++ b/src/Umbraco.Web.UI/Umbraco.Web.UI.csproj @@ -488,7 +488,7 @@ - + Web.Template.config From 685a0523396b778f8b461cb65377f78e6a9ef9ae Mon Sep 17 00:00:00 2001 From: Shannon Date: Wed, 30 May 2018 16:29:16 +1000 Subject: [PATCH 15/25] tweak /umbraco/view/web.config to only block cshtml, so the *.html files can be downloaded --- src/Umbraco.Web.UI/Umbraco/Views/web.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Umbraco.Web.UI/Umbraco/Views/web.config b/src/Umbraco.Web.UI/Umbraco/Views/web.config index 853a4935fb..d378fee13b 100644 --- a/src/Umbraco.Web.UI/Umbraco/Views/web.config +++ b/src/Umbraco.Web.UI/Umbraco/Views/web.config @@ -34,7 +34,7 @@ - + From c5af3e51b04f509eb44fb1a10cd866073687148f Mon Sep 17 00:00:00 2001 From: Stephan Date: Wed, 30 May 2018 09:56:16 +0200 Subject: [PATCH 16/25] Update V8_GETTING_STARTED.md --- V8_GETTING_STARTED.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/V8_GETTING_STARTED.md b/V8_GETTING_STARTED.md index 3c954091f8..c5e20d2a1c 100644 --- a/V8_GETTING_STARTED.md +++ b/V8_GETTING_STARTED.md @@ -15,7 +15,7 @@ * When the website starts you'll see the Umbraco installer and just follow the prompts * Your all set! -### Wan't to run from a zip instead? +### Want to run from a zip instead? If you just want to try out a few things, you can run the site from a zip file which you can download from here https://github.com/umbraco/Umbraco-CMS/releases/tag/temp8-cg18. From 2fade2065629818b2bcaa08b3b8e51a4b23e3fae Mon Sep 17 00:00:00 2001 From: Stephan Date: Tue, 29 May 2018 13:05:17 +0200 Subject: [PATCH 17/25] Kill legacy, get rid of warnings --- src/Umbraco.Web/Umbraco.Web.csproj | 8 +- .../umbraco.presentation/default.aspx.cs | 18 +- .../umbraco.presentation/helper.cs | 37 -- src/Umbraco.Web/umbraco.presentation/item.cs | 38 +- .../umbraco.presentation/template.cs | 391 ------------------ .../umbraco/templateControls/Item.cs | 11 +- .../umbraco/templateControls/ItemRenderer.cs | 11 +- 7 files changed, 58 insertions(+), 456 deletions(-) delete mode 100644 src/Umbraco.Web/umbraco.presentation/helper.cs delete mode 100644 src/Umbraco.Web/umbraco.presentation/template.cs diff --git a/src/Umbraco.Web/Umbraco.Web.csproj b/src/Umbraco.Web/Umbraco.Web.csproj index 6f61144786..537be3fbfa 100644 --- a/src/Umbraco.Web/Umbraco.Web.csproj +++ b/src/Umbraco.Web/Umbraco.Web.csproj @@ -1189,9 +1189,6 @@ Code - - Code - Code @@ -1206,9 +1203,6 @@ True Settings.settings - - Code - Code @@ -1590,4 +1584,4 @@ - + \ No newline at end of file diff --git a/src/Umbraco.Web/umbraco.presentation/default.aspx.cs b/src/Umbraco.Web/umbraco.presentation/default.aspx.cs index dcfe5fb5b3..84888f13d7 100644 --- a/src/Umbraco.Web/umbraco.presentation/default.aspx.cs +++ b/src/Umbraco.Web/umbraco.presentation/default.aspx.cs @@ -62,9 +62,21 @@ namespace umbraco FireBeforeRequestInit(args); //if we are cancelling then return and don't proceed - if (args.Cancel) return; - - this.MasterPageFile = template.GetMasterPageName(_upage.Template); + if (args.Cancel) return; + + var template = Current.Services.FileService.GetTemplate(_upage.Template); + if (template != null) + { + var alias = template.MasterTemplateAlias; + var file = alias.Replace(" ", "") + ".master"; + var path = SystemDirectories.Masterpages + "/" + file; + + + if (File.Exists(IOHelper.MapPath(VirtualPathUtility.ToAbsolute(path)))) + this.MasterPageFile = path; + else + this.MasterPageFile = SystemDirectories.Umbraco + "/masterPages/default.master"; + } // reset the friendly path so it's used by forms, etc. Context.RewritePath(UmbracoContext.Current.OriginalRequestUrl.PathAndQuery); diff --git a/src/Umbraco.Web/umbraco.presentation/helper.cs b/src/Umbraco.Web/umbraco.presentation/helper.cs deleted file mode 100644 index e745f7cc95..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/helper.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using System.Collections; -using Umbraco.Web.Macros; - -namespace umbraco -{ - /// - /// Summary description for helper. - /// - [Obsolete("This needs to be removed, do not use")] - public class helper - { - public static bool IsNumeric(string number) - { - int result; - return int.TryParse(number, out result); - } - - public static string FindAttribute(IDictionary attributes, string key) - { - return FindAttribute(null, attributes, key); - } - - public static string FindAttribute(IDictionary pageElements, IDictionary attributes, string key) - { - // fix for issue 14862: lowercase for case insensitive matching - key = key.ToLower(); - - var attributeValue = string.Empty; - if (attributes[key] != null) - attributeValue = attributes[key].ToString(); - - attributeValue = MacroRenderer.ParseAttribute(pageElements, attributeValue); - return attributeValue; - } - } -} diff --git a/src/Umbraco.Web/umbraco.presentation/item.cs b/src/Umbraco.Web/umbraco.presentation/item.cs index bd36ee429c..c183e3833e 100644 --- a/src/Umbraco.Web/umbraco.presentation/item.cs +++ b/src/Umbraco.Web/umbraco.presentation/item.cs @@ -11,6 +11,7 @@ using Umbraco.Web; using Umbraco.Core.Profiling; using Umbraco.Core.Strings; using Umbraco.Web.Composing; +using Umbraco.Web.Macros; namespace umbraco { @@ -55,7 +56,7 @@ namespace umbraco /// internal item(IPublishedContent publishedContent, IDictionary elements, IDictionary attributes) { - _fieldName = helper.FindAttribute(attributes, "field"); + _fieldName = FindAttribute(attributes, "field"); if (_fieldName.StartsWith("#")) { @@ -64,7 +65,7 @@ namespace umbraco else { // Loop through XML children we need to find the fields recursive - var recursive = helper.FindAttribute(attributes, "recursive") == "true"; + var recursive = FindAttribute(attributes, "recursive") == "true"; if (publishedContent == null) { @@ -90,7 +91,7 @@ namespace umbraco //now we check if the value is still empty and if so we'll check useIfEmpty if (string.IsNullOrEmpty(_fieldContent)) { - var altFieldName = helper.FindAttribute(attributes, "useIfEmpty"); + var altFieldName = FindAttribute(attributes, "useIfEmpty"); if (string.IsNullOrEmpty(altFieldName) == false) { if (publishedContent != null && (publishedContent.HasProperty(altFieldName) || recursive)) @@ -114,6 +115,13 @@ namespace umbraco ParseItem(attributes); } + static string FindAttribute(IDictionary attributes, string key) + { + key = key.ToLowerInvariant(); + var attributeValue = attributes.Contains(key) ? attributes[key].ToString() : string.Empty; + return MacroRenderer.ParseAttribute(null, attributeValue); + } + /// /// Returns the recursive value using a legacy strategy of looking at the xml cache and the splitPath in the elements collection /// @@ -160,21 +168,21 @@ namespace umbraco using (Current.ProfilingLogger.DebugDuration("Start parsing " + _fieldName)) { HttpContext.Current.Trace.Write("item", "Start parsing '" + _fieldName + "'"); - if (helper.FindAttribute(attributes, "textIfEmpty") != "" && _fieldContent == "") - _fieldContent = helper.FindAttribute(attributes, "textIfEmpty"); + if (FindAttribute(attributes, "textIfEmpty") != "" && _fieldContent == "") + _fieldContent = FindAttribute(attributes, "textIfEmpty"); _fieldContent = _fieldContent.Trim(); // DATE FORMATTING FUNCTIONS - if (helper.FindAttribute(attributes, "formatAsDateWithTime") == "true") + if (FindAttribute(attributes, "formatAsDateWithTime") == "true") { if (_fieldContent == "") _fieldContent = DateTime.Now.ToString(); _fieldContent = Convert.ToDateTime(_fieldContent).ToLongDateString() + - helper.FindAttribute(attributes, "formatAsDateWithTimeSeparator") + + FindAttribute(attributes, "formatAsDateWithTimeSeparator") + Convert.ToDateTime(_fieldContent).ToShortTimeString(); } - else if (helper.FindAttribute(attributes, "formatAsDate") == "true") + else if (FindAttribute(attributes, "formatAsDate") == "true") { if (_fieldContent == "") _fieldContent = DateTime.Now.ToString(); @@ -183,7 +191,7 @@ namespace umbraco // TODO: Needs revision to check if parameter-tags has attributes - if (helper.FindAttribute(attributes, "stripParagraph") == "true" && _fieldContent.Length > 5) + if (FindAttribute(attributes, "stripParagraph") == "true" && _fieldContent.Length > 5) { _fieldContent = _fieldContent.Trim(); string fieldContentLower = _fieldContent.ToLower(); @@ -200,20 +208,20 @@ namespace umbraco } // CASING - if (helper.FindAttribute(attributes, "case") == "lower") + if (FindAttribute(attributes, "case") == "lower") _fieldContent = _fieldContent.ToLower(); - else if (helper.FindAttribute(attributes, "case") == "upper") + else if (FindAttribute(attributes, "case") == "upper") _fieldContent = _fieldContent.ToUpper(); - else if (helper.FindAttribute(attributes, "case") == "title") + else if (FindAttribute(attributes, "case") == "title") _fieldContent = _fieldContent.ToCleanString(CleanStringType.Ascii | CleanStringType.Alias | CleanStringType.PascalCase); // OTHER FORMATTING FUNCTIONS - if (helper.FindAttribute(attributes, "urlEncode") == "true") + if (FindAttribute(attributes, "urlEncode") == "true") _fieldContent = HttpUtility.UrlEncode(_fieldContent); - if (helper.FindAttribute(attributes, "htmlEncode") == "true") + if (FindAttribute(attributes, "htmlEncode") == "true") _fieldContent = HttpUtility.HtmlEncode(_fieldContent); - if (helper.FindAttribute(attributes, "convertLineBreaks") == "true") + if (FindAttribute(attributes, "convertLineBreaks") == "true") _fieldContent = _fieldContent.Replace("\n", "
\n"); HttpContext.Current.Trace.Write("item", "Done parsing '" + _fieldName + "'"); diff --git a/src/Umbraco.Web/umbraco.presentation/template.cs b/src/Umbraco.Web/umbraco.presentation/template.cs deleted file mode 100644 index 8fad4c8b55..0000000000 --- a/src/Umbraco.Web/umbraco.presentation/template.cs +++ /dev/null @@ -1,391 +0,0 @@ -using System; -using System.Text; -using System.IO; -using System.Text.RegularExpressions; -using System.Web.UI; -using System.Collections; -using Umbraco.Core.Cache; -using Umbraco.Core.Configuration; -using Umbraco.Web; -using Umbraco.Web.Cache; -using Umbraco.Core.IO; -using System.Web; -using Umbraco.Core.Models; -using Umbraco.Core.Xml; -using Umbraco.Web.Composing; -using Umbraco.Web.Macros; - -namespace umbraco -{ - /// - /// Holds methods for parsing and building umbraco templates - /// - [Obsolete("Do not use this class, use Umbraco.Core.Service.IFileService to work with templates")] - public class template - { - #region private variables - - readonly StringBuilder _templateOutput = new StringBuilder(); - - private string _templateDesign = ""; - int _masterTemplate = -1; - private string _templateName = ""; - private string _templateAlias = ""; - - #endregion - - #region public properties - public string TemplateContent - { - set - { - _templateOutput.Append(value); - } - get - { - return _templateOutput.ToString(); - } - } - - public int MasterTemplate - { - get { return _masterTemplate; } - } - - //added fallback to the default template to avoid nasty .net errors. - //This is referenced in /default.aspx.cs during page rendering. - public string MasterPageFile - { - get - { - - string file = TemplateAlias.Replace(" ", "") + ".master"; - string path = SystemDirectories.Masterpages + "/" + file; - - - if (System.IO.File.Exists(IOHelper.MapPath(VirtualPathUtility.ToAbsolute(path)))) - return path; - else - return SystemDirectories.Umbraco + "/masterPages/default.master"; - } - } - - //Support for template folders, if a alternative skin folder is requested - //we will try to look for template files in another folder - public string AlternateMasterPageFile(string templateFolder) - { - string file = TemplateAlias.Replace(" ", "") + ".master"; - string path = SystemDirectories.Masterpages + "/" + templateFolder + "/" + file; - - //if it doesn't exists then we return the normal file - if (!System.IO.File.Exists(IOHelper.MapPath(VirtualPathUtility.ToAbsolute(path)))) - { - - string originalPath = IOHelper.MapPath(VirtualPathUtility.ToAbsolute(MasterPageFile)); - string copyPath = IOHelper.MapPath(VirtualPathUtility.ToAbsolute(path)); - - string newFile; - using (var fs = new FileStream(originalPath, FileMode.Open, FileAccess.ReadWrite)) - using (var f = new StreamReader(fs)) - { - newFile = f.ReadToEnd(); - } - - newFile = newFile.Replace("MasterPageFile=\"~/masterpages/", "MasterPageFile=\""); - - using (var fs = new FileStream(copyPath, FileMode.Create, FileAccess.Write)) - using (var replacement = new StreamWriter(fs)) - { - replacement.Write(newFile); - } - } - - return path; - - } - - - public string TemplateAlias - { - get { return _templateAlias; } - } - #endregion - - #region public methods - - public override string ToString() - { - return this._templateName; - } - - public Control parseStringBuilder(StringBuilder tempOutput, page umbPage) - { - - Control pageContent = new Control(); - - bool stop = false; - bool debugMode = UmbracoContext.Current.HttpContext.IsDebuggingEnabled; - - while (!stop) - { - System.Web.HttpContext.Current.Trace.Write("template", "Begining of parsing rutine..."); - int tagIndex = tempOutput.ToString().ToLower().IndexOf(" -1) - { - string tempElementContent = ""; - pageContent.Controls.Add(new LiteralControl(tempOutput.ToString().Substring(0, tagIndex))); - - tempOutput.Remove(0, tagIndex); - - string tag = tempOutput.ToString().Substring(0, tempOutput.ToString().IndexOf(">") + 1); - Hashtable attributes = new Hashtable(XmlHelper.GetAttributesFromElement(tag)); - - // Check whether it's a single tag () or a tag with children (...) - if (tag.Substring(tag.Length - 2, 1) != "/" && tag.IndexOf(" ") > -1) - { - string closingTag = ""; - // Tag with children are only used when a macro is inserted by the umbraco-editor, in the - // following format: "", so we - // need to delete extra information inserted which is the image-tag and the closing - // umbraco_macro tag - if (tempOutput.ToString().IndexOf(closingTag) > -1) - { - tempOutput.Remove(0, tempOutput.ToString().IndexOf(closingTag)); - } - } - - - - System.Web.HttpContext.Current.Trace.Write("umbTemplate", "Outputting item: " + tag); - - // Handle umbraco macro tags - if (tag.ToString().ToLower().IndexOf("umbraco_macro") > -1) - { - if (debugMode) - pageContent.Controls.Add(new LiteralControl("
")); - - umbraco.presentation.templateControls.Macro macroControl = new umbraco.presentation.templateControls.Macro(); - macroControl.Alias = helper.FindAttribute(attributes, "macroalias"); - IDictionaryEnumerator ide = attributes.GetEnumerator(); - while (ide.MoveNext()) - if (macroControl.Attributes[ide.Key.ToString()] == null) - macroControl.Attributes.Add(ide.Key.ToString(), ide.Value.ToString()); - pageContent.Controls.Add(macroControl); - - if (debugMode) - pageContent.Controls.Add(new LiteralControl("
")); - } - else - { - if (tag.ToLower().IndexOf("umbraco_getitem") > -1) - { - umbraco.presentation.templateControls.Item itemControl = new umbraco.presentation.templateControls.Item(); - itemControl.Field = helper.FindAttribute(attributes, "field"); - IDictionaryEnumerator ide = attributes.GetEnumerator(); - while (ide.MoveNext()) - if (itemControl.Attributes[ide.Key.ToString()] == null) - itemControl.Attributes.Add(ide.Key.ToString(), ide.Value.ToString()); - pageContent.Controls.Add(itemControl); - - } - } - tempOutput.Remove(0, tempOutput.ToString().IndexOf(">") + 1); - tempOutput.Insert(0, tempElementContent); - } - else - { - pageContent.Controls.Add(new LiteralControl(tempOutput.ToString())); - break; - } - - } - - return pageContent; - - } - - - /// - /// Parses the content of the templateOutput stringbuilder, and matches any tags given in the - /// XML-file /umbraco/config/umbracoTemplateTags.xml. - /// Replaces the found tags in the StringBuilder object, with "real content" - /// - /// - public void Parse(page umbPage) - { - System.Web.HttpContext.Current.Trace.Write("umbracoTemplate", "Start parsing"); - - // First parse for known umbraco tags - // - macros - // - print item from page, level, or recursive - MatchCollection tags = Regex.Matches(_templateOutput.ToString(), "<\\?UMBRACO_MACRO[^>]*/>|<\\?UMBRACO_GETITEM[^>]*/>|<\\?(?[\\S]*)[^>]*/>", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); - - foreach (Match tag in tags) - { - Hashtable attributes = new Hashtable(XmlHelper.GetAttributesFromElement(tag.Value)); - - - if (tag.ToString().ToLower().IndexOf("umbraco_macro") > -1) - { - var macroId = helper.FindAttribute(attributes, "macroid"); - if (macroId != "") - _templateOutput.Replace(tag.Value, string.Empty); - } - else - { - if (tag.ToString().ToLower().IndexOf("umbraco_getitem") > -1) - { - try - { - var tempElementContent = umbPage.Elements[helper.FindAttribute(attributes, "field")].ToString(); - var tempMacros = Regex.Matches(tempElementContent, "<\\?UMBRACO_MACRO(?[^>]*)>]*><\\/\\?UMBRACO_MACRO>", RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace); - foreach (Match tempMacro in tempMacros) - { - var tempAttributes = new Hashtable(XmlHelper.GetAttributesFromElement(tempMacro.Groups["attributes"].Value)); - var macroId = helper.FindAttribute(tempAttributes, "macroid"); - if (Convert.ToInt32(macroId) > 0) - _templateOutput.Replace(tag.Value, string.Empty); - } - - _templateOutput.Replace(tag.Value, tempElementContent); - } - catch (Exception e) - { - System.Web.HttpContext.Current.Trace.Warn("umbracoTemplate", "Error reading element (" + helper.FindAttribute(attributes, "field") + ")", e); - } - } - } - } - - System.Web.HttpContext.Current.Trace.Write("umbracoTemplate", "Done parsing"); - } - - - - #endregion - - #region private methods - - private static MacroModel GetMacro(string macroId) - { - HttpContext.Current.Trace.Write("umbracoTemplate", "Starting macro (" + macroId + ")"); - // it's all obsolete anyways... - var macro = Current.Services.MacroService.GetByAlias(macroId); - return macro == null ? null : new MacroModel(macro); - } - - #endregion - - #region constructors - - public static string GetMasterPageName(int templateID) - { - return GetMasterPageName(templateID, null); - } - - public static string GetMasterPageName(int templateID, string templateFolder) - { - var t = new template(templateID); - - return !string.IsNullOrEmpty(templateFolder) - ? t.AlternateMasterPageFile(templateFolder) - : t.MasterPageFile; - } - - public template(int templateID) - { - var tId = templateID; - - var t = Current.ApplicationCache.RuntimeCache.GetCacheItem