Merge remote-tracking branch 'origin/v8/dev' into netcore/dev
This commit is contained in:
@@ -438,14 +438,11 @@
|
||||
Write-Host "Prepare C# Documentation"
|
||||
|
||||
$src = "$($this.SolutionRoot)\src"
|
||||
$tmp = $this.BuildTemp
|
||||
$out = $this.BuildOutput
|
||||
$tmp = $this.BuildTemp
|
||||
$out = $this.BuildOutput
|
||||
$DocFxJson = Join-Path -Path $src "\ApiDocs\docfx.json"
|
||||
$DocFxSiteOutput = Join-Path -Path $tmp "\_site\*.*"
|
||||
|
||||
|
||||
#restore nuget packages
|
||||
$this.RestoreNuGet()
|
||||
# run DocFx
|
||||
$DocFx = $this.BuildEnv.DocFx
|
||||
|
||||
@@ -463,13 +460,18 @@
|
||||
$src = "$($this.SolutionRoot)\src"
|
||||
$out = $this.BuildOutput
|
||||
|
||||
# Check if the solution has been built
|
||||
if (!(Test-Path "$src\Umbraco.Web.UI.Client\node_modules")) {throw "Umbraco needs to be built before generating the Angular Docs"}
|
||||
|
||||
"Moving to Umbraco.Web.UI.Docs folder"
|
||||
cd ..\src\Umbraco.Web.UI.Docs
|
||||
cd $src\Umbraco.Web.UI.Docs
|
||||
|
||||
"Generating the docs and waiting before executing the next commands"
|
||||
& npm install
|
||||
& npx gulp docs
|
||||
|
||||
Pop-Location
|
||||
|
||||
# change baseUrl
|
||||
$BaseUrl = "https://our.umbraco.com/apidocs/v8/ui/"
|
||||
$IndexPath = "./api/index.html"
|
||||
|
||||
@@ -29,5 +29,7 @@ namespace Umbraco.Web.Models
|
||||
public string EventElement { get; set; }
|
||||
[DataMember(Name = "customProperties")]
|
||||
public JObject CustomProperties { get; set; }
|
||||
[DataMember(Name = "skipStepIfVisible")]
|
||||
public string SkipStepIfVisible { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,405 @@
|
||||
using Newtonsoft.Json;
|
||||
using NUnit.Framework;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Umbraco.Web.Compose;
|
||||
|
||||
namespace Umbraco.Tests.PropertyEditors
|
||||
{
|
||||
[TestFixture]
|
||||
public class NestedContentPropertyComponentTests
|
||||
{
|
||||
[Test]
|
||||
public void Invalid_Json()
|
||||
{
|
||||
var component = new NestedContentPropertyComponent();
|
||||
|
||||
Assert.DoesNotThrow(() => component.CreateNestedContentKeys("this is not json", true));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void No_Nesting()
|
||||
{
|
||||
var guids = new[] { Guid.NewGuid(), Guid.NewGuid() };
|
||||
var guidCounter = 0;
|
||||
Func<Guid> guidFactory = () => guids[guidCounter++];
|
||||
|
||||
var json = @"[
|
||||
{""key"":""04a6dba8-813c-4144-8aca-86a3f24ebf08"",""name"":""Item 1"",""ncContentTypeAlias"":""nested"",""text"":""woot""},
|
||||
{""key"":""d8e214d8-c5a5-4b45-9b51-4050dd47f5fa"",""name"":""Item 2"",""ncContentTypeAlias"":""nested"",""text"":""zoot""}
|
||||
]";
|
||||
var expected = json
|
||||
.Replace("04a6dba8-813c-4144-8aca-86a3f24ebf08", guids[0].ToString())
|
||||
.Replace("d8e214d8-c5a5-4b45-9b51-4050dd47f5fa", guids[1].ToString());
|
||||
|
||||
var component = new NestedContentPropertyComponent();
|
||||
var result = component.CreateNestedContentKeys(json, false, guidFactory);
|
||||
|
||||
Assert.AreEqual(JsonConvert.DeserializeObject(expected).ToString(), JsonConvert.DeserializeObject(result).ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void One_Level_Nesting_Unescaped()
|
||||
{
|
||||
var guids = new[] { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() };
|
||||
var guidCounter = 0;
|
||||
Func<Guid> guidFactory = () => guids[guidCounter++];
|
||||
|
||||
var json = @"[{
|
||||
""key"": ""04a6dba8-813c-4144-8aca-86a3f24ebf08"",
|
||||
""name"": ""Item 1"",
|
||||
""ncContentTypeAlias"": ""text"",
|
||||
""text"": ""woot""
|
||||
}, {
|
||||
""key"": ""d8e214d8-c5a5-4b45-9b51-4050dd47f5fa"",
|
||||
""name"": ""Item 2"",
|
||||
""ncContentTypeAlias"": ""list"",
|
||||
""text"": ""zoot"",
|
||||
""subItems"": [{
|
||||
""key"": ""dccf550c-3a05-469e-95e1-a8f560f788c2"",
|
||||
""name"": ""Item 1"",
|
||||
""ncContentTypeAlias"": ""text"",
|
||||
""text"": ""woot""
|
||||
}, {
|
||||
""key"": ""fbde4288-8382-4e13-8933-ed9c160de050"",
|
||||
""name"": ""Item 2"",
|
||||
""ncContentTypeAlias"": ""text"",
|
||||
""text"": ""zoot""
|
||||
}
|
||||
]
|
||||
}
|
||||
]";
|
||||
|
||||
var expected = json
|
||||
.Replace("04a6dba8-813c-4144-8aca-86a3f24ebf08", guids[0].ToString())
|
||||
.Replace("d8e214d8-c5a5-4b45-9b51-4050dd47f5fa", guids[1].ToString())
|
||||
.Replace("dccf550c-3a05-469e-95e1-a8f560f788c2", guids[2].ToString())
|
||||
.Replace("fbde4288-8382-4e13-8933-ed9c160de050", guids[3].ToString());
|
||||
|
||||
var component = new NestedContentPropertyComponent();
|
||||
var result = component.CreateNestedContentKeys(json, false, guidFactory);
|
||||
|
||||
Assert.AreEqual(JsonConvert.DeserializeObject(expected).ToString(), JsonConvert.DeserializeObject(result).ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void One_Level_Nesting_Escaped()
|
||||
{
|
||||
var guids = new[] { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() };
|
||||
var guidCounter = 0;
|
||||
Func<Guid> guidFactory = () => guids[guidCounter++];
|
||||
|
||||
// we need to ensure the escaped json is consistent with how it will be re-escaped after parsing
|
||||
// and this is how to do that, the result will also include quotes around it.
|
||||
var subJsonEscaped = JsonConvert.ToString(JsonConvert.DeserializeObject(@"[{
|
||||
""key"": ""dccf550c-3a05-469e-95e1-a8f560f788c2"",
|
||||
""name"": ""Item 1"",
|
||||
""ncContentTypeAlias"": ""text"",
|
||||
""text"": ""woot""
|
||||
}, {
|
||||
""key"": ""fbde4288-8382-4e13-8933-ed9c160de050"",
|
||||
""name"": ""Item 2"",
|
||||
""ncContentTypeAlias"": ""text"",
|
||||
""text"": ""zoot""
|
||||
}
|
||||
]").ToString());
|
||||
|
||||
var json = @"[{
|
||||
""key"": ""04a6dba8-813c-4144-8aca-86a3f24ebf08"",
|
||||
""name"": ""Item 1"",
|
||||
""ncContentTypeAlias"": ""text"",
|
||||
""text"": ""woot""
|
||||
}, {
|
||||
""key"": ""d8e214d8-c5a5-4b45-9b51-4050dd47f5fa"",
|
||||
""name"": ""Item 2"",
|
||||
""ncContentTypeAlias"": ""list"",
|
||||
""text"": ""zoot"",
|
||||
""subItems"":" + subJsonEscaped + @"
|
||||
}
|
||||
]";
|
||||
|
||||
var expected = json
|
||||
.Replace("04a6dba8-813c-4144-8aca-86a3f24ebf08", guids[0].ToString())
|
||||
.Replace("d8e214d8-c5a5-4b45-9b51-4050dd47f5fa", guids[1].ToString())
|
||||
.Replace("dccf550c-3a05-469e-95e1-a8f560f788c2", guids[2].ToString())
|
||||
.Replace("fbde4288-8382-4e13-8933-ed9c160de050", guids[3].ToString());
|
||||
|
||||
var component = new NestedContentPropertyComponent();
|
||||
var result = component.CreateNestedContentKeys(json, false, guidFactory);
|
||||
|
||||
Assert.AreEqual(JsonConvert.DeserializeObject(expected).ToString(), JsonConvert.DeserializeObject(result).ToString());
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Nested_In_Complex_Editor_Escaped()
|
||||
{
|
||||
var guids = new[] { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() };
|
||||
var guidCounter = 0;
|
||||
Func<Guid> guidFactory = () => guids[guidCounter++];
|
||||
|
||||
// we need to ensure the escaped json is consistent with how it will be re-escaped after parsing
|
||||
// and this is how to do that, the result will also include quotes around it.
|
||||
var subJsonEscaped = JsonConvert.ToString(JsonConvert.DeserializeObject(@"[{
|
||||
""key"": ""dccf550c-3a05-469e-95e1-a8f560f788c2"",
|
||||
""name"": ""Item 1"",
|
||||
""ncContentTypeAlias"": ""text"",
|
||||
""text"": ""woot""
|
||||
}, {
|
||||
""key"": ""fbde4288-8382-4e13-8933-ed9c160de050"",
|
||||
""name"": ""Item 2"",
|
||||
""ncContentTypeAlias"": ""text"",
|
||||
""text"": ""zoot""
|
||||
}
|
||||
]").ToString());
|
||||
|
||||
// Complex editor such as the grid
|
||||
var complexEditorJsonEscaped = @"{
|
||||
""name"": ""1 column layout"",
|
||||
""sections"": [
|
||||
{
|
||||
""grid"": ""12"",
|
||||
""rows"": [
|
||||
{
|
||||
""name"": ""Article"",
|
||||
""id"": ""b4f6f651-0de3-ef46-e66a-464f4aaa9c57"",
|
||||
""areas"": [
|
||||
{
|
||||
""grid"": ""4"",
|
||||
""controls"": [
|
||||
{
|
||||
""value"": ""I am quote"",
|
||||
""editor"": {
|
||||
""alias"": ""quote"",
|
||||
""view"": ""textstring""
|
||||
},
|
||||
""styles"": null,
|
||||
""config"": null
|
||||
}],
|
||||
""styles"": null,
|
||||
""config"": null
|
||||
},
|
||||
{
|
||||
""grid"": ""8"",
|
||||
""controls"": [
|
||||
{
|
||||
""value"": ""Header"",
|
||||
""editor"": {
|
||||
""alias"": ""headline"",
|
||||
""view"": ""textstring""
|
||||
},
|
||||
""styles"": null,
|
||||
""config"": null
|
||||
},
|
||||
{
|
||||
""value"": " + subJsonEscaped + @",
|
||||
""editor"": {
|
||||
""alias"": ""madeUpNestedContent"",
|
||||
""view"": ""madeUpNestedContentInGrid""
|
||||
},
|
||||
""styles"": null,
|
||||
""config"": null
|
||||
}],
|
||||
""styles"": null,
|
||||
""config"": null
|
||||
}],
|
||||
""styles"": null,
|
||||
""config"": null
|
||||
}]
|
||||
}]
|
||||
}";
|
||||
|
||||
|
||||
var json = @"[{
|
||||
""key"": ""04a6dba8-813c-4144-8aca-86a3f24ebf08"",
|
||||
""name"": ""Item 1"",
|
||||
""ncContentTypeAlias"": ""text"",
|
||||
""text"": ""woot""
|
||||
}, {
|
||||
""key"": ""d8e214d8-c5a5-4b45-9b51-4050dd47f5fa"",
|
||||
""name"": ""Item 2"",
|
||||
""ncContentTypeAlias"": ""list"",
|
||||
""text"": ""zoot"",
|
||||
""subItems"":" + complexEditorJsonEscaped + @"
|
||||
}
|
||||
]";
|
||||
|
||||
var expected = json
|
||||
.Replace("04a6dba8-813c-4144-8aca-86a3f24ebf08", guids[0].ToString())
|
||||
.Replace("d8e214d8-c5a5-4b45-9b51-4050dd47f5fa", guids[1].ToString())
|
||||
.Replace("dccf550c-3a05-469e-95e1-a8f560f788c2", guids[2].ToString())
|
||||
.Replace("fbde4288-8382-4e13-8933-ed9c160de050", guids[3].ToString());
|
||||
|
||||
var component = new NestedContentPropertyComponent();
|
||||
var result = component.CreateNestedContentKeys(json, false, guidFactory);
|
||||
|
||||
Assert.AreEqual(JsonConvert.DeserializeObject(expected).ToString(), JsonConvert.DeserializeObject(result).ToString());
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void No_Nesting_Generates_Keys_For_Missing_Items()
|
||||
{
|
||||
var guids = new[] { Guid.NewGuid() };
|
||||
var guidCounter = 0;
|
||||
Func<Guid> guidFactory = () => guids[guidCounter++];
|
||||
|
||||
var json = @"[
|
||||
{""key"":""04a6dba8-813c-4144-8aca-86a3f24ebf08"",""name"":""Item 1 my key wont change"",""ncContentTypeAlias"":""nested"",""text"":""woot""},
|
||||
{""name"":""Item 2 was copied and has no key prop"",""ncContentTypeAlias"":""nested"",""text"":""zoot""}
|
||||
]";
|
||||
|
||||
var component = new NestedContentPropertyComponent();
|
||||
var result = component.CreateNestedContentKeys(json, true, guidFactory);
|
||||
|
||||
// Ensure the new GUID is put in a key into the JSON
|
||||
Assert.IsTrue(JsonConvert.DeserializeObject(result).ToString().Contains(guids[0].ToString()));
|
||||
|
||||
// Ensure that the original key is NOT changed/modified & still exists
|
||||
Assert.IsTrue(JsonConvert.DeserializeObject(result).ToString().Contains("04a6dba8-813c-4144-8aca-86a3f24ebf08"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void One_Level_Nesting_Escaped_Generates_Keys_For_Missing_Items()
|
||||
{
|
||||
var guids = new[] { Guid.NewGuid(), Guid.NewGuid(), Guid.NewGuid() };
|
||||
var guidCounter = 0;
|
||||
Func<Guid> guidFactory = () => guids[guidCounter++];
|
||||
|
||||
// we need to ensure the escaped json is consistent with how it will be re-escaped after parsing
|
||||
// and this is how to do that, the result will also include quotes around it.
|
||||
var subJsonEscaped = JsonConvert.ToString(JsonConvert.DeserializeObject(@"[{
|
||||
""name"": ""Item 1"",
|
||||
""ncContentTypeAlias"": ""text"",
|
||||
""text"": ""woot""
|
||||
}, {
|
||||
""name"": ""Nested Item 2 was copied and has no key"",
|
||||
""ncContentTypeAlias"": ""text"",
|
||||
""text"": ""zoot""
|
||||
}
|
||||
]").ToString());
|
||||
|
||||
var json = @"[{
|
||||
""name"": ""Item 1 was copied and has no key"",
|
||||
""ncContentTypeAlias"": ""text"",
|
||||
""text"": ""woot""
|
||||
}, {
|
||||
""key"": ""d8e214d8-c5a5-4b45-9b51-4050dd47f5fa"",
|
||||
""name"": ""Item 2"",
|
||||
""ncContentTypeAlias"": ""list"",
|
||||
""text"": ""zoot"",
|
||||
""subItems"":" + subJsonEscaped + @"
|
||||
}
|
||||
]";
|
||||
|
||||
var component = new NestedContentPropertyComponent();
|
||||
var result = component.CreateNestedContentKeys(json, true, guidFactory);
|
||||
|
||||
// Ensure the new GUID is put in a key into the JSON for each item
|
||||
Assert.IsTrue(JsonConvert.DeserializeObject(result).ToString().Contains(guids[0].ToString()));
|
||||
Assert.IsTrue(JsonConvert.DeserializeObject(result).ToString().Contains(guids[1].ToString()));
|
||||
Assert.IsTrue(JsonConvert.DeserializeObject(result).ToString().Contains(guids[2].ToString()));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Nested_In_Complex_Editor_Escaped_Generates_Keys_For_Missing_Items()
|
||||
{
|
||||
var guids = new[] { Guid.NewGuid(), Guid.NewGuid() };
|
||||
var guidCounter = 0;
|
||||
Func<Guid> guidFactory = () => guids[guidCounter++];
|
||||
|
||||
// we need to ensure the escaped json is consistent with how it will be re-escaped after parsing
|
||||
// and this is how to do that, the result will also include quotes around it.
|
||||
var subJsonEscaped = JsonConvert.ToString(JsonConvert.DeserializeObject(@"[{
|
||||
""key"": ""dccf550c-3a05-469e-95e1-a8f560f788c2"",
|
||||
""name"": ""Item 1"",
|
||||
""ncContentTypeAlias"": ""text"",
|
||||
""text"": ""woot""
|
||||
}, {
|
||||
""name"": ""Nested Item 2 was copied and has no key"",
|
||||
""ncContentTypeAlias"": ""text"",
|
||||
""text"": ""zoot""
|
||||
}
|
||||
]").ToString());
|
||||
|
||||
// Complex editor such as the grid
|
||||
var complexEditorJsonEscaped = @"{
|
||||
""name"": ""1 column layout"",
|
||||
""sections"": [
|
||||
{
|
||||
""grid"": ""12"",
|
||||
""rows"": [
|
||||
{
|
||||
""name"": ""Article"",
|
||||
""id"": ""b4f6f651-0de3-ef46-e66a-464f4aaa9c57"",
|
||||
""areas"": [
|
||||
{
|
||||
""grid"": ""4"",
|
||||
""controls"": [
|
||||
{
|
||||
""value"": ""I am quote"",
|
||||
""editor"": {
|
||||
""alias"": ""quote"",
|
||||
""view"": ""textstring""
|
||||
},
|
||||
""styles"": null,
|
||||
""config"": null
|
||||
}],
|
||||
""styles"": null,
|
||||
""config"": null
|
||||
},
|
||||
{
|
||||
""grid"": ""8"",
|
||||
""controls"": [
|
||||
{
|
||||
""value"": ""Header"",
|
||||
""editor"": {
|
||||
""alias"": ""headline"",
|
||||
""view"": ""textstring""
|
||||
},
|
||||
""styles"": null,
|
||||
""config"": null
|
||||
},
|
||||
{
|
||||
""value"": " + subJsonEscaped + @",
|
||||
""editor"": {
|
||||
""alias"": ""madeUpNestedContent"",
|
||||
""view"": ""madeUpNestedContentInGrid""
|
||||
},
|
||||
""styles"": null,
|
||||
""config"": null
|
||||
}],
|
||||
""styles"": null,
|
||||
""config"": null
|
||||
}],
|
||||
""styles"": null,
|
||||
""config"": null
|
||||
}]
|
||||
}]
|
||||
}";
|
||||
|
||||
|
||||
var json = @"[{
|
||||
""key"": ""04a6dba8-813c-4144-8aca-86a3f24ebf08"",
|
||||
""name"": ""Item 1"",
|
||||
""ncContentTypeAlias"": ""text"",
|
||||
""text"": ""woot""
|
||||
}, {
|
||||
""name"": ""Item 2 was copied and has no key"",
|
||||
""ncContentTypeAlias"": ""list"",
|
||||
""text"": ""zoot"",
|
||||
""subItems"":" + complexEditorJsonEscaped + @"
|
||||
}
|
||||
]";
|
||||
|
||||
var component = new NestedContentPropertyComponent();
|
||||
var result = component.CreateNestedContentKeys(json, true, guidFactory);
|
||||
|
||||
// Ensure the new GUID is put in a key into the JSON for each item
|
||||
Assert.IsTrue(JsonConvert.DeserializeObject(result).ToString().Contains(guids[0].ToString()));
|
||||
Assert.IsTrue(JsonConvert.DeserializeObject(result).ToString().Contains(guids[1].ToString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -157,6 +157,7 @@
|
||||
<Compile Include="Persistence\Repositories\UserRepositoryTest.cs" />
|
||||
<Compile Include="UmbracoExamine\ExamineExtensions.cs" />
|
||||
<Compile Include="PropertyEditors\DataValueReferenceFactoryCollectionTests.cs" />
|
||||
<Compile Include="PropertyEditors\NestedContentPropertyComponentTests.cs" />
|
||||
<Compile Include="PublishedContent\NuCacheChildrenTests.cs" />
|
||||
<Compile Include="PublishedContent\PublishedContentLanguageVariantTests.cs" />
|
||||
<Compile Include="PublishedContent\PublishedContentSnapshotTestBase.cs" />
|
||||
|
||||
@@ -5,14 +5,14 @@
|
||||
@scope
|
||||
|
||||
@description
|
||||
<b>Added in Umbraco 7.8</b>. The tour component is a global component and is already added to the umbraco markup.
|
||||
In the Umbraco UI the tours live in the "Help drawer" which opens when you click the Help-icon in the bottom left corner of Umbraco.
|
||||
You can easily add you own tours to the Help-drawer or show and start tours from
|
||||
<b>Added in Umbraco 7.8</b>. The tour component is a global component and is already added to the umbraco markup.
|
||||
In the Umbraco UI the tours live in the "Help drawer" which opens when you click the Help-icon in the bottom left corner of Umbraco.
|
||||
You can easily add you own tours to the Help-drawer or show and start tours from
|
||||
anywhere in the Umbraco backoffice. To see a real world example of a custom tour implementation, install <a href="https://our.umbraco.com/projects/starter-kits/the-starter-kit/">The Starter Kit</a> in Umbraco 7.8
|
||||
|
||||
<h1><b>Extending the help drawer with custom tours</b></h1>
|
||||
The easiet way to add new tours to Umbraco is through the Help-drawer. All it requires is a my-tour.json file.
|
||||
Place the file in <i>App_Plugins/{MyPackage}/backoffice/tours/{my-tour}.json</i> and it will automatically be
|
||||
The easiet way to add new tours to Umbraco is through the Help-drawer. All it requires is a my-tour.json file.
|
||||
Place the file in <i>App_Plugins/{MyPackage}/backoffice/tours/{my-tour}.json</i> and it will automatically be
|
||||
picked up by Umbraco and shown in the Help-drawer.
|
||||
|
||||
<h3><b>The tour object</b></h3>
|
||||
@@ -26,7 +26,7 @@ The tour object consist of two parts - The overall tour configuration and a list
|
||||
"groupOrder": 200 // Control the order of tour groups
|
||||
"allowDisable": // Adds a "Don't" show this tour again"-button to the intro step
|
||||
"culture" : // From v7.11+. Specifies the culture of the tour (eg. en-US), if set the tour will only be shown to users with this culture set on their profile. If omitted or left empty the tour will be visible to all users
|
||||
"requiredSections":["content", "media", "mySection"] // Sections that the tour will access while running, if the user does not have access to the required tour sections, the tour will not load.
|
||||
"requiredSections":["content", "media", "mySection"] // Sections that the tour will access while running, if the user does not have access to the required tour sections, the tour will not load.
|
||||
"steps": [] // tour steps - see next example
|
||||
}
|
||||
</pre>
|
||||
@@ -43,11 +43,12 @@ The tour object consist of two parts - The overall tour configuration and a list
|
||||
"backdropOpacity": 0.4 // the backdrop opacity
|
||||
"view": "" // add a custom view
|
||||
"customProperties" : {} // add any custom properties needed for the custom view
|
||||
"skipStepIfVisible": ".dashboard div [data-element='my-tour-button']" // if we can find this DOM element on the page then we will skip this step
|
||||
}
|
||||
</pre>
|
||||
|
||||
<h1><b>Adding tours to other parts of the Umbraco backoffice</b></h1>
|
||||
It is also possible to add a list of custom tours to other parts of the Umbraco backoffice,
|
||||
It is also possible to add a list of custom tours to other parts of the Umbraco backoffice,
|
||||
as an example on a Dashboard in a Custom section. You can then use the {@link umbraco.services.tourService tourService} to start and stop tours but you don't have to register them as part of the tour service.
|
||||
|
||||
<h1><b>Using the tour service</b></h1>
|
||||
@@ -86,7 +87,8 @@ as an example on a Dashboard in a Custom section. You can then use the {@link um
|
||||
"element": "[data-element='my-tour-button']",
|
||||
"title": "Click the button",
|
||||
"content": "Click the button",
|
||||
"event": "click"
|
||||
"event": "click",
|
||||
"skipStepIfVisible": "[data-element='my-other-tour-button']"
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -257,9 +259,26 @@ In the following example you see how to run some custom logic before a step goes
|
||||
|
||||
// make sure we don't go too far
|
||||
if (scope.model.currentStepIndex !== scope.model.steps.length) {
|
||||
|
||||
var upcomingStep = scope.model.steps[scope.model.currentStepIndex];
|
||||
|
||||
// If the currentStep JSON object has 'skipStepIfVisible'
|
||||
// It's a DOM selector - if we find it then we ship over this step
|
||||
if(upcomingStep.skipStepIfVisible) {
|
||||
let tryFindDomEl = document.querySelector(upcomingStep.element);
|
||||
if(tryFindDomEl) {
|
||||
// check if element is visible:
|
||||
if( tryFindDomEl.offsetWidth || tryFindDomEl.offsetHeight || tryFindDomEl.getClientRects().length ) {
|
||||
// if it was visible then we skip the step.
|
||||
nextStep();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
startStep();
|
||||
// tour completed - final step
|
||||
|
||||
} else {
|
||||
// tour completed - final step
|
||||
scope.loadingStep = true;
|
||||
|
||||
waitForPendingRerequests().then(function () {
|
||||
|
||||
@@ -48,6 +48,9 @@ label.umb-form-check--checkbox{
|
||||
&:checked ~ .umb-form-check__state .umb-form-check__check {
|
||||
border-color: @ui-option-type;
|
||||
}
|
||||
&[type='checkbox']:checked ~ .umb-form-check__state .umb-form-check__check {
|
||||
background-color: @ui-option-type;
|
||||
}
|
||||
&:checked:hover ~ .umb-form-check__state .umb-form-check__check {
|
||||
&::before {
|
||||
background: @ui-option-type-hover;
|
||||
|
||||
@@ -188,27 +188,21 @@
|
||||
"event": "click"
|
||||
},
|
||||
{
|
||||
"element": "[data-element~='editor-data-type-picker']",
|
||||
"element": "[ng-controller*='Umbraco.Editors.DataTypePickerController'] [data-element='editor-data-type-picker']",
|
||||
"elementPreventClick": true,
|
||||
"title": "Editor picker",
|
||||
"content": "<p>In the editor picker dialog we can pick one of the many built-in editors.</p><p><em>You can choose from preconfigured data types (Reuse) or create a new configuration (Available editors)</em>.</p>"
|
||||
"content": "<p>In the editor picker dialog we can pick one of the many built-in editors.</p>"
|
||||
},
|
||||
{
|
||||
"element": "[data-element~='editor-data-type-picker'] [data-element='editor-Textarea']",
|
||||
"element": "[data-element~='editor-data-type-picker'] [data-element='datatype-Textarea']",
|
||||
"title": "Select editor",
|
||||
"content": "Select the <b>Textarea</b> editor. This will add a textarea to the Welcome Text property.",
|
||||
"event": "click"
|
||||
},
|
||||
{
|
||||
"element": "[data-element~='editor-data-type-settings']",
|
||||
"elementPreventClick": true,
|
||||
"element": "[data-element='editor-data-type-picker'] [data-element='datatypeconfig-Textarea'] > a",
|
||||
"title": "Editor settings",
|
||||
"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~='editor-data-type-settings'] [data-element='button-submit']",
|
||||
"title": "Save editor",
|
||||
"content": "Click <b>Submit</b> to save the changes.",
|
||||
"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.",
|
||||
"event": "click"
|
||||
},
|
||||
{
|
||||
@@ -317,7 +311,8 @@
|
||||
"content": "<p>To see all our templates click the <b>small triangle</b> to the left of the templates node.</p>",
|
||||
"event": "click",
|
||||
"eventElement": "#tree [data-element='tree-item-templates'] [data-element='tree-item-expand']",
|
||||
"view": "templatetree"
|
||||
"view": "templatetree",
|
||||
"skipStepIfVisible": "#tree [data-element='tree-item-templates'] > div > button[data-element=tree-item-expand].icon-navigation-down"
|
||||
},
|
||||
{
|
||||
"element": "#tree [data-element='tree-item-templates'] [data-element='tree-item-Home Page']",
|
||||
|
||||
Reference in New Issue
Block a user