Merge remote-tracking branch 'origin/v8/dev' into v8/feature/0000-DataType-DeleteWarning-with-links-to-references
# Conflicts: # src/Umbraco.Web.UI.Client/src/views/datatypes/delete.html
This commit is contained in:
+3
-1
@@ -39,6 +39,8 @@ To build Umbraco, fire up PowerShell and move to Umbraco's repository root (the
|
||||
|
||||
build/build.ps1
|
||||
|
||||
If you only see a build.bat-file, you're probably on the wrong branch. If you switch to the correct branch (dev-v8) the file will appear and you can build it.
|
||||
|
||||
You might run into [Powershell quirks](#powershell-quirks).
|
||||
|
||||
### Build Infrastructure
|
||||
@@ -209,4 +211,4 @@ The best solution is to unblock the Zip file before un-zipping: right-click the
|
||||
|
||||
### Git Quirks
|
||||
|
||||
Git might have issues dealing with long file paths during build. You may want/need to enable `core.longpaths` support (see [this page](https://github.com/msysgit/msysgit/wiki/Git-cannot-create-a-file-or-directory-with-a-long-path) for details).
|
||||
Git might have issues dealing with long file paths during build. You may want/need to enable `core.longpaths` support (see [this page](https://github.com/msysgit/msysgit/wiki/Git-cannot-create-a-file-or-directory-with-a-long-path) for details).
|
||||
|
||||
+38
-29
@@ -2,15 +2,15 @@
|
||||
|
||||
👍🎉 First off, thanks for taking the time to contribute! 🎉👍
|
||||
|
||||
The following is a set of guidelines for contributing to Umbraco CMS.
|
||||
The following is a set of guidelines, for contributing to Umbraco CMS.
|
||||
|
||||
These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.
|
||||
These are mostly guidelines, not rules. Use your best judgement, and feel free to propose changes to this document in a pull request.
|
||||
|
||||
Remember, we're a friendly bunch and are happy with whatever contribution you might provide. Below are guidelines for success that we've gathered over the years. If you choose to ignore them then we still love you 💖.
|
||||
|
||||
**Code of conduct**
|
||||
|
||||
This project and everyone participating in it is governed by the [our Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to [Sebastiaan Janssen - sj@umbraco.dk](mailto:sj@umbraco.dk).
|
||||
This project and everyone participating in it, is governed by the [our Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to [Sebastiaan Janssen - sj@umbraco.dk](mailto:sj@umbraco.dk).
|
||||
|
||||
**Table of contents**
|
||||
|
||||
@@ -40,9 +40,9 @@ This document gives you a quick overview on how to get started.
|
||||
|
||||
Not all changes are wanted, so on occasion we might close a PR without merging it. We will give you feedback why we can't accept your changes and we'll be nice about it, thanking you for spending your valuable time.
|
||||
|
||||
We have [documented what we consider small and large changes](CONTRIBUTION_GUIDELINES.md). Make sure to talk to us before making large changes.
|
||||
We have [documented what we consider small and large changes](CONTRIBUTION_GUIDELINES.md). Make sure to talk to us before making large changes, so we can ensure that you don't put all your hard work into something we would not be able to merge.
|
||||
|
||||
Remember, if an issue is in the `Up for grabs` list or you've asked for some feedback before you sent us a PR, your PR will not be closed as unwanted.
|
||||
Remember, it is always worth working on an issue from the `Up for grabs` list or even asking for some feedback before you send us a PR. This way, your PR will not be closed as unwanted.
|
||||
|
||||
### What can I start with?
|
||||
|
||||
@@ -59,37 +59,38 @@ Great question! The short version goes like this:
|
||||
* **Clone** - when GitHub has created your fork, you can clone it in your favorite Git tool
|
||||
|
||||

|
||||
|
||||
|
||||
* **Switch to the correct branch** - switch to the v8-dev branch
|
||||
* **Build** - build your fork of Umbraco locally as described in [building Umbraco from source code](BUILD.md)
|
||||
* **Change** - make your changes, experiment, have fun, explore and learn, and don't be afraid. We welcome all contributions and will [happily give feedback](#questions)
|
||||
* **Commit** - done? Yay! 🎉 **Important:** create a new branch now and name it after the issue you're fixing, we usually follow the format: `temp-12345`. This means it's a temporary branch for the particular issue you're working on, in this case `12345`. When you have a branch, commit your changes. Don't commit to `v8/dev`, create a new branch first.
|
||||
* **Push** - great, now you can push the changes up to your fork on GitHub
|
||||
* **Create pull request** - exciting! You're ready to show us your changes (or not quite ready, you just need some feedback to progress). GitHub has picked up on the new branch you've pushed and will offer to create a Pull Request. Click that green button and away you go.
|
||||
* **Create pull request** - exciting! You're ready to show us your changes (or not quite ready, you just need some feedback to progress - you can now make use of GitHub's draft pull request status, detailed [here] (https://github.blog/2019-02-14-introducing-draft-pull-requests/)). GitHub has picked up on the new branch you've pushed and will offer to create a Pull Request. Click that green button and away you go.
|
||||
|
||||

|
||||
|
||||
### Pull requests
|
||||
The most successful pull requests usually look a like this:
|
||||
|
||||
* Fill in the required template
|
||||
* Fill in the required template, linking your pull request to an issue on the [issue tracker,](https://github.com/umbraco/Umbraco-CMS/issues) if applicable.
|
||||
* Include screenshots and animated GIFs in your pull request whenever possible.
|
||||
* Unit tests, while optional are awesome, thank you!
|
||||
* New code is commented with documentation from which [the reference documentation](https://our.umbraco.com/documentation/Reference/) is generated
|
||||
* Unit tests, while optional, are awesome. Thank you!
|
||||
* New code is commented with documentation from which [the reference documentation](https://our.umbraco.com/documentation/Reference/) is generated.
|
||||
|
||||
Again, these are guidelines, not strict requirements.
|
||||
Again, these are guidelines, not strict requirements. However, the more information that you give to us, the more we have to work with when considering your contributions. Good documentation of a pull request can really speed up the time it takes to review and merge your work!
|
||||
|
||||
## Reviews
|
||||
|
||||
You've sent us your first contribution, congratulations! Now what?
|
||||
You've sent us your first contribution - congratulations! Now what?
|
||||
|
||||
The [pull request team](#the-pr-team) can now start reviewing your proposed changes and give you feedback on them. If it's not perfect, we'll either fix up what we need or we can request you to make some additional changes.
|
||||
The [pull request team](#the-pr-team) can now start reviewing your proposed changes and give you feedback on them. If it's not perfect, we'll either fix up what we need or we can request that you make some additional changes.
|
||||
|
||||
We have [a process in place which you can read all about](REVIEW_PROCESS.md). The very abbreviated version is:
|
||||
|
||||
- Your PR will get a reply within 48 hours
|
||||
- An in-depth reply will be added within at most 2 weeks
|
||||
- The PR will be either merged or rejected within at most 4 weeks
|
||||
- Sometimes it is difficult to meet these timelines and we'll talk to you
|
||||
- Sometimes it is difficult to meet these timelines and we'll talk to you if this is the case.
|
||||
|
||||
### Styleguides
|
||||
|
||||
@@ -99,21 +100,21 @@ That said, the Umbraco development team likes to follow the hints that ReSharper
|
||||
|
||||
### The PR team
|
||||
|
||||
The pull request team consists of a member of Umbraco HQ, [Sebastiaan](https://github.com/nul800sebastiaan), who gets assistance from the following community members
|
||||
The pull request team consists of one member of Umbraco HQ, [Sebastiaan](https://github.com/nul800sebastiaan), who gets assistance from the following community members who have comitted to volunteering their free time:
|
||||
|
||||
- [Anders Bjerner](https://github.com/abjerner)
|
||||
- [Dave Woestenborghs](https://github.com/dawoe)
|
||||
- [Emma Burstow](https://github.com/emmaburstow)
|
||||
- [Poornima Nayar](https://github.com/poornimanayar)
|
||||
|
||||
These wonderful volunteers will provide you with a first reply to your PR, review and test out your changes and might ask more questions. After that they'll let Umbraco HQ know if everything seems okay.
|
||||
These wonderful people aim to provide you with a first reply to your PR, review and test out your changes and on occasions, they might ask more questions. If they are happy with your work, they'll let Umbraco HQ know by approving the PR. Hq will have final sign-off and will check the work again before it is merged.
|
||||
|
||||
### Questions?
|
||||
|
||||
You can get in touch with [the PR team](#the-pr-team) in multiple ways, we love open conversations and we are a friendly bunch. No question you have is stupid. Any questions you have usually helps out multiple people with the same question. Ask away:
|
||||
You can get in touch with [the PR team](#the-pr-team) in multiple ways; we love open conversations and we are a friendly bunch. No question you have is stupid. Any question you have usually helps out multiple people with the same question. Ask away:
|
||||
|
||||
- If there's an existing issue on the issue tracker then that's a good place to leave questions and discuss how to start or move forward
|
||||
- Unsure where to start? Did something not work as expected? Try leaving a note in the ["Contributing to Umbraco"](https://our.umbraco.com/forum/contributing-to-umbraco-cms/) forum, the team monitors that one closely
|
||||
- If there's an existing issue on the issue tracker then that's a good place to leave questions and discuss how to start or move forward.
|
||||
- Unsure where to start? Did something not work as expected? Try leaving a note in the ["Contributing to Umbraco"](https://our.umbraco.com/forum/contributing-to-umbraco-cms/) forum. The team monitors that one closely, so one of us will be on hand and ready to point you in the right direction.
|
||||
|
||||
## Working with the code
|
||||
|
||||
@@ -125,19 +126,19 @@ In order to build the Umbraco source code locally, first make sure you have the
|
||||
* Node v10+
|
||||
* npm v6.4.1+
|
||||
|
||||
The easiest way to get started is to run `build.ps1` which will build both the backoffice (also known as "Belle") and the Umbraco core. You can then easily start debugging from Visual Studio, or if you need to debug Belle you can run `gulp dev` in `src\Umbraco.Web.UI.Client`. See [this page](BUILD.md) for more details.
|
||||
The easiest way to get started is to open `src\umbraco.sln` in Visual Studio 2017 (version 15.9.7 or higher, [the community edition is free](https://www.visualstudio.com/thank-you-downloading-visual-studio/?sku=Community&rel=15) for you to use to contribute to Open Source projects). In Visual Studio, find the Task Runner Explorer (in the View menu under Other Windows) and run the build task under the gulpfile.
|
||||
|
||||
Alternatively, you can open `src\umbraco.sln` in Visual Studio 2017 (version 15.9.7 or higher, [the community edition is free](https://www.visualstudio.com/thank-you-downloading-visual-studio/?sku=Community&rel=15) for you to use to contribute to Open Source projects). In Visual Studio, find the Task Runner Explorer (in the View menu under Other Windows) and run the build task under the gulpfile.
|
||||
Alternatively, you can run `build.ps1` from the Powershell command line, which will build both the backoffice (also known as "Belle") and the Umbraco core. You can then easily start debugging from Visual Studio, or if you need to debug Belle you can run `gulp dev` in `src\Umbraco.Web.UI.Client`. See [this page](BUILD.md) for more details.
|
||||
|
||||

|
||||
|
||||
After this build completes, you should be able to hit `F5` in Visual Studio to build and run the project. A IISExpress webserver will start and the Umbraco installer will pop up in your browser, follow the directions there to get a working Umbraco install up and running.
|
||||
After this build completes, you should be able to hit `F5` in Visual Studio to build and run the project. A IISExpress webserver will start and the Umbraco installer will pop up in your browser. Follow the directions there to get a working Umbraco install up and running.
|
||||
|
||||
### Working with the source code
|
||||
|
||||
Some parts of our source code are over 10 years old now. And when we say "old", we mean "mature" of course!
|
||||
|
||||
There's two big areas that you should know about:
|
||||
There are two big areas that you should know about:
|
||||
|
||||
1. The Umbraco backoffice is a extensible AngularJS app and requires you to run a `gulp dev` command while you're working with it, so changes are copied over to the appropriate directories and you can refresh your browser to view the results of your changes.
|
||||
You may need to run the following commands to set up gulp properly:
|
||||
@@ -146,30 +147,34 @@ There's two big areas that you should know about:
|
||||
npm install
|
||||
npm run build
|
||||
```
|
||||
The caching for the back office has been described as 'aggressive' so we often find it's best when making back office changes to disable caching in the browser to help you to see the changes you're making.
|
||||
|
||||
2. "The rest" is a C# based codebase, which is mostly ASP.NET MVC based. You can make changes, build them in Visual Studio, and hit `F5` to see the result.
|
||||
|
||||
To find the general areas of something you're looking to fix or improve, have a look at the following two parts of the API documentation.
|
||||
To find the general areas for something you're looking to fix or improve, have a look at the following two parts of the API documentation.
|
||||
|
||||
* [The AngularJS based backoffice files](https://our.umbraco.com/apidocs/ui/#/api) (to be found in `src\Umbraco.Web.UI.Client\src`)
|
||||
* [The C# application](https://our.umbraco.com/apidocs/csharp/)
|
||||
|
||||
### Which branch should I target for my contributions?
|
||||
|
||||
We like to use [Gitflow as much as possible](https://jeffkreeftmeijer.com/git-flow/), don't worry if you are not familiar with it. The most important thing you need to know is that when you fork the Umbraco repository, the default branch is set to something, usually `v8/dev`. Whatever the default is, that's where we'd like you to target your contributions.
|
||||
We like to use [Gitflow as much as possible](https://jeffkreeftmeijer.com/git-flow/), but don't worry if you are not familiar with it. The most important thing you need to know is that when you fork the Umbraco repository, the default branch is set to something, usually `v8/dev`. If you are working on v8, this is the branch you should be targetting. For v7 contributions, please target 'v7/dev'.
|
||||
|
||||
Please note: we are no longer accepting features for v7 but will continue to merge bug fixes as and when they arise.
|
||||
|
||||

|
||||
|
||||
### Making changes after the PR was opened
|
||||
### Making changes after the PR is open
|
||||
|
||||
If you make the corrections we ask for in the same branch and push them to your fork again, the pull request automatically updates with the additional commit(s) so we can review it again. If all is well, we'll merge the code and your commits are forever part of Umbraco!
|
||||
|
||||
### Keeping your Umbraco fork in sync with the main repository
|
||||
|
||||
We recommend you sync with our repository before you submit your pull request. That way, you can fix any potential merge conflicts and make our lives a little bit easier.
|
||||
We recommend you to sync with our repository before you submit your pull request. That way, you can fix any potential merge conflicts and make our lives a little bit easier.
|
||||
|
||||
Also, if you've submitted a pull request three weeks ago and want to work on something new, you'll want to get the latest code to build against of course.
|
||||
Also, if you have submitted a pull request three weeks ago and want to work on something new, you'll want to get the latest code to build against of course.
|
||||
|
||||
To sync your fork with this original one, you'll have to add the upstream url, you only have to do this once:
|
||||
To sync your fork with this original one, you'll have to add the upstream url. You only have to do this once:
|
||||
|
||||
```
|
||||
git remote add upstream https://github.com/umbraco/Umbraco-CMS.git
|
||||
@@ -185,3 +190,7 @@ git rebase upstream/v8/dev
|
||||
In this command we're syncing with the `v8/dev` branch, but you can of course choose another one if needed.
|
||||
|
||||
(More info on how this works: [http://robots.thoughtbot.com/post/5133345960/keeping-a-git-fork-updated](http://robots.thoughtbot.com/post/5133345960/keeping-a-git-fork-updated))
|
||||
|
||||
### And finally
|
||||
|
||||
We welcome all kinds of contributions to this repository. If you don't feel you'd like to make code changes here, you can visit our [documentation repository](https://github.com/umbraco/UmbracoDocs) and use your experience to contribute to making the docs we have, even better. We also encourage community members to feel free to comment on others' pull requests and issues - the expertise we have is not limited to the PR team and HQ. So, if you see something on the issue tracker or pull requests you feel you can add to, please don't be shy.
|
||||
|
||||
@@ -7,15 +7,15 @@ A brief description of the issue goes here.
|
||||
|
||||
<!--
|
||||
|
||||
If you haven't yet done so, please read the "contributing guidelines"
|
||||
thoroughly. Then, proceed by filling out the rest of the details in the issue
|
||||
template below. The more details you can give us, the easier it will be for us
|
||||
Please fill out the rest of the details in the issue template below.
|
||||
The more details you can give us, the easier it will be for us
|
||||
to determine the cause of a problem.
|
||||
|
||||
See: https://github.com/umbraco/Umbraco-CMS/blob/v8/dev/.github/CONTRIBUTING.md
|
||||
|
||||
-->
|
||||
|
||||
## Umbraco version
|
||||
|
||||
I am seeing this issue on Umbraco version: <!-- please note the version here -->
|
||||
|
||||
|
||||
Reproduction
|
||||
|
||||
+2
-2
@@ -21,7 +21,7 @@ Please also see our [Code of Conduct](CODE_OF_CONDUCT.md).
|
||||
|
||||
[Umbraco Cloud](https://umbraco.com/cloud) is the easiest and fastest way to use Umbraco yet, with full support for all your custom .NET code and integrations. You're up and running in less than a minute, and your life will be made easier with automated upgrades and a built-in deployment engine. We offer a free 14-day trial, no credit card needed.
|
||||
|
||||
If you want to DIY, you can [download Umbraco]((https://our.umbraco.com/download)) either as a ZIP file or via NuGet. It's the same version of Umbraco CMS that powers Umbraco Cloud, but you'll need to find a place to host it yourself, and handling deployments and upgrades will be all up to you.
|
||||
If you want to DIY, then you can [download Umbraco]((https://our.umbraco.com/download)) either as a ZIP file or via NuGet. It's the same version of Umbraco CMS that powers Umbraco Cloud, but you'll need to find a place to host it yourself, and handling deployments and upgrades will be all up to you.
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -29,7 +29,7 @@ The documentation for Umbraco CMS can be found [on Our Umbraco](https://our.umbr
|
||||
|
||||
## Join the Umbraco community
|
||||
|
||||
Our friendly community is available 24/7 at the community hub we call ["Our Umbraco"](https://our.umbraco.com/). Our Umbraco features forums for questions and answers, documentation, downloadable plugins for Umbraco, and a rich collection of community resources.
|
||||
Our friendly community is available 24/7 at the community hub, we call ["Our Umbraco"](https://our.umbraco.com/). Our Umbraco features forums for questions and answers, documentation, downloadable plugins for Umbraco, and a rich collection of community resources.
|
||||
|
||||
Besides "Our", we all support each other also via Twitter: [Umbraco HQ](https://twitter.com/umbraco), [Release Updates](https://twitter.com/umbracoproject), [#umbraco](https://twitter.com/hashtag/umbraco)
|
||||
|
||||
|
||||
@@ -11,21 +11,16 @@ Y88 88Y 888 888 888 888 d88P 888 888 888 Y88b. Y88..88P
|
||||
|
||||
Don't forget to build!
|
||||
|
||||
We've done our best to transform your configuration files but in case something is not quite right: remember we
|
||||
backed up your files in App_Data\NuGetBackup so you can find the original files before they were transformed.
|
||||
|
||||
We've overwritten all the files in the Umbraco folder, these have been backed up in
|
||||
App_Data\NuGetBackup. We didn't overwrite the UI.xml file nor did we remove any files or folders that you or
|
||||
a package might have added. Only the existing files were overwritten. If you customized anything then make
|
||||
sure to do a compare and merge with the NuGetBackup folder.
|
||||
We've done our best to transform your configuration files but in case something is not quite right: we recommmend you look in source control for the previous version so you can find the original files before they were transformed.
|
||||
|
||||
This NuGet package includes build targets that extend the creation of a deploy package, which is generated by
|
||||
Publishing from Visual Studio. The targets will only work once Publishing is configured, so if you don't use
|
||||
Publish this won't affect you.
|
||||
|
||||
The following items will now be automatically included when creating a deploy package or publishing to the file
|
||||
system: umbraco, config\splashes and global.asax.
|
||||
|
||||
Please read the release notes on our.umbraco.com:
|
||||
http://our.umbraco.com/contribute/releases
|
||||
https://our.umbraco.com/contribute/releases
|
||||
|
||||
- Umbraco
|
||||
|
||||
+2
-2
@@ -18,5 +18,5 @@ using System.Resources;
|
||||
[assembly: AssemblyVersion("8.0.0")]
|
||||
|
||||
// these are FYI and changed automatically
|
||||
[assembly: AssemblyFileVersion("8.3.0")]
|
||||
[assembly: AssemblyInformationalVersion("8.3.0")]
|
||||
[assembly: AssemblyFileVersion("8.4.0")]
|
||||
[assembly: AssemblyInformationalVersion("8.4.0")]
|
||||
|
||||
@@ -11,5 +11,6 @@
|
||||
public const string TemplateFrontEndCacheKey = "template";
|
||||
|
||||
public const string MacroContentCacheKey = "macroContent_"; // used in MacroRenderers
|
||||
public const string MacroFromAliasCacheKey = "macroFromAlias_";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace Umbraco.Core.Configuration.Grid
|
||||
public interface IGridEditorConfig
|
||||
{
|
||||
string Name { get; }
|
||||
string NameTemplate { get; }
|
||||
string Alias { get; }
|
||||
string View { get; }
|
||||
string Render { get; }
|
||||
|
||||
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
|
||||
{
|
||||
internal class ContentElement : UmbracoConfigurationElement, IContentSection
|
||||
{
|
||||
private const string DefaultPreviewBadge = @"<a id=""umbracoPreviewBadge"" style=""z-index:99999; position: absolute; top: 0; right: 0; border: 0; width: 149px; height: 149px; background: url('{0}/assets/img/preview-mode-badge.png') no-repeat;"" href=""#"" OnClick=""javascript:window.top.location.href = '{0}/preview/end?redir={1}'""><span style=""display:none;"">In Preview Mode - click to end</span></a>";
|
||||
private const string DefaultPreviewBadge = @"<div id=""umbracoPreviewBadge"" class=""umbraco-preview-badge""><span class=""umbraco-preview-badge__header"">Preview mode</span><a href=""{0}/preview/end?redir={1}"" class=""umbraco-preview-badge__end""><svg viewBox=""0 0 100 100"" xmlns=""http://www.w3.org/2000/svg""><title>Click to end</title><path d=""M5273.1 2400.1v-2c0-2.8-5-4-9.7-4s-9.7 1.3-9.7 4v2a7 7 0 002 4.9l5 4.9c.3.3.4.6.4 1v6.4c0 .4.2.7.6.8l2.9.9c.5.1 1-.2 1-.8v-7.2c0-.4.2-.7.4-1l5.1-5a7 7 0 002-4.9zm-9.7-.1c-4.8 0-7.4-1.3-7.5-1.8.1-.5 2.7-1.8 7.5-1.8s7.3 1.3 7.5 1.8c-.2.5-2.7 1.8-7.5 1.8z""/><path d=""M5268.4 2410.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1s-.4-1-1-1h-4.3zM5272.7 2413.7h-4.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1s-.4-1-1-1zM5272.7 2417h-4.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1 0-.5-.4-1-1-1z""/><path d=""M78.2 13l-8.7 11.7a32.5 32.5 0 11-51.9 25.8c0-10.3 4.7-19.7 12.9-25.8L21.8 13a47 47 0 1056.4 0z""/><path d=""M42.7 2.5h14.6v49.4H42.7z""/></svg></a></div><style type=""text/css"">.umbraco-preview-badge {{position: absolute;top: 1em;right: 1em;display: inline-flex;background: #1b264f;color: #fff;padding: 1em;font-size: 12px;z-index: 99999999;justify-content: center;align-items: center;box-shadow: 0 10px 50px rgba(0, 0, 0, .1), 0 6px 20px rgba(0, 0, 0, .16);line-height: 1;}}.umbraco-preview-badge__header {{font-weight: bold;}}.umbraco-preview-badge__end {{width: 3em;padding: 1em;margin: -1em -1em -1em 2em;display: flex;flex-shrink: 0;align-items: center;align-self: stretch;}}.umbraco-preview-badge__end:hover,.umbraco-preview-badge__end:focus {{background: #f5c1bc;}}.umbraco-preview-badge__end svg {{fill: #fff;width:1em;}}</style>";
|
||||
|
||||
[ConfigurationProperty("imaging")]
|
||||
internal ContentImagingElement Imaging => (ContentImagingElement) this["imaging"];
|
||||
|
||||
@@ -221,7 +221,8 @@ namespace Umbraco.Core
|
||||
FailedPasswordAttempts,
|
||||
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Integer, true, FailedPasswordAttempts)
|
||||
{
|
||||
Name = FailedPasswordAttemptsLabel
|
||||
Name = FailedPasswordAttemptsLabel,
|
||||
DataTypeId = Constants.DataTypes.LabelInt
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -242,35 +243,40 @@ namespace Umbraco.Core
|
||||
LastLockoutDate,
|
||||
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastLockoutDate)
|
||||
{
|
||||
Name = LastLockoutDateLabel
|
||||
Name = LastLockoutDateLabel,
|
||||
DataTypeId = Constants.DataTypes.LabelDateTime
|
||||
}
|
||||
},
|
||||
{
|
||||
LastLoginDate,
|
||||
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastLoginDate)
|
||||
{
|
||||
Name = LastLoginDateLabel
|
||||
Name = LastLoginDateLabel,
|
||||
DataTypeId = Constants.DataTypes.LabelDateTime
|
||||
}
|
||||
},
|
||||
{
|
||||
LastPasswordChangeDate,
|
||||
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Date, true, LastPasswordChangeDate)
|
||||
{
|
||||
Name = LastPasswordChangeDateLabel
|
||||
Name = LastPasswordChangeDateLabel,
|
||||
DataTypeId = Constants.DataTypes.LabelDateTime
|
||||
}
|
||||
},
|
||||
{
|
||||
PasswordAnswer,
|
||||
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar, true, PasswordAnswer)
|
||||
{
|
||||
Name = PasswordAnswerLabel
|
||||
Name = PasswordAnswerLabel,
|
||||
DataTypeId = Constants.DataTypes.LabelString
|
||||
}
|
||||
},
|
||||
{
|
||||
PasswordQuestion,
|
||||
new PropertyType(PropertyEditors.Aliases.Label, ValueStorageType.Nvarchar, true, PasswordQuestion)
|
||||
{
|
||||
Name = PasswordQuestionLabel
|
||||
Name = PasswordQuestionLabel,
|
||||
DataTypeId = Constants.DataTypes.LabelString
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading;
|
||||
using System.Web.Hosting;
|
||||
using Umbraco.Core.Logging;
|
||||
@@ -65,7 +65,7 @@ namespace Umbraco.Core
|
||||
// a new process for the same application path
|
||||
|
||||
var appPath = HostingEnvironment.ApplicationPhysicalPath;
|
||||
var hash = (appId + ":::" + appPath).ToSHA1();
|
||||
var hash = (appId + ":::" + appPath).GenerateHash<SHA1>();
|
||||
|
||||
var lockName = "UMBRACO-" + hash + "-MAINDOM-LCK";
|
||||
_asyncLock = new AsyncLock(lockName);
|
||||
|
||||
@@ -67,6 +67,12 @@ namespace Umbraco.Core.Models.ContentEditing
|
||||
/// </remarks>
|
||||
[DataMember(Name = "active")]
|
||||
public bool Active { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the content app badge.
|
||||
/// </summary>
|
||||
[DataMember(Name = "badge")]
|
||||
public ContentAppBadge Badge { get; set; }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
namespace Umbraco.Core.Models.ContentEditing
|
||||
{
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
using Umbraco.Core.Events;
|
||||
|
||||
/// <summary>
|
||||
/// Represents a content app badge
|
||||
/// </summary>
|
||||
[DataContract(Name = "badge", Namespace = "")]
|
||||
public class ContentAppBadge
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ContentAppBadge"/> class.
|
||||
/// </summary>
|
||||
public ContentAppBadge()
|
||||
{
|
||||
this.Type = ContentAppBadgeType.Default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the number displayed in the badge
|
||||
/// </summary>
|
||||
[DataMember(Name = "count")]
|
||||
public int Count { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type of badge to display
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>This controls the background color of the badge.</para>
|
||||
/// <para>Warning will display a dark yellow badge</para>
|
||||
/// <para>Alert will display a red badge</para>
|
||||
/// <para>Default will display a turquoise badge</para>
|
||||
/// </remarks>
|
||||
[DataMember(Name = "type")]
|
||||
public ContentAppBadgeType Type { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
namespace Umbraco.Core.Models.ContentEditing
|
||||
{
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
|
||||
/// <summary>
|
||||
/// Represent the content app badge types
|
||||
/// </summary>
|
||||
[DataContract(Name = "contentAppBadgeType")]
|
||||
[JsonConverter(typeof(StringEnumConverter))]
|
||||
public enum ContentAppBadgeType
|
||||
{
|
||||
[EnumMember(Value = "default")]
|
||||
Default = 0,
|
||||
|
||||
[EnumMember(Value = "warning")]
|
||||
Warning = 1,
|
||||
|
||||
[EnumMember(Value = "alert")]
|
||||
Alert = 2
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
@@ -9,7 +8,7 @@ namespace Umbraco.Core.Models
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
[DataContract(Name = "pagedCollection", Namespace = "")]
|
||||
public class PagedResult<T>
|
||||
public abstract class PagedResult
|
||||
{
|
||||
public PagedResult(long totalItems, long pageNumber, long pageSize)
|
||||
{
|
||||
@@ -39,9 +38,6 @@ namespace Umbraco.Core.Models
|
||||
[DataMember(Name = "totalItems")]
|
||||
public long TotalItems { get; private set; }
|
||||
|
||||
[DataMember(Name = "items")]
|
||||
public IEnumerable<T> Items { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the skip size based on the paged parameters specified
|
||||
/// </summary>
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Umbraco.Core.Models
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a paged result for a model collection
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
[DataContract(Name = "pagedCollection", Namespace = "")]
|
||||
public class PagedResult<T> : PagedResult
|
||||
{
|
||||
public PagedResult(long totalItems, long pageNumber, long pageSize)
|
||||
: base(totalItems, pageNumber, pageSize)
|
||||
{ }
|
||||
|
||||
[DataMember(Name = "items")]
|
||||
public IEnumerable<T> Items { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,7 @@ namespace Umbraco.Core.Models
|
||||
|
||||
if (user.Avatar.IsNullOrWhiteSpace())
|
||||
{
|
||||
var gravatarHash = user.Email.ToMd5();
|
||||
var gravatarHash = user.Email.GenerateHash<MD5>();
|
||||
var gravatarUrl = "https://www.gravatar.com/avatar/" + gravatarHash + "?d=404";
|
||||
|
||||
//try Gravatar
|
||||
|
||||
@@ -542,7 +542,7 @@ namespace Umbraco.Core
|
||||
{
|
||||
return "\"{0}\"".InvariantFormat(obj);
|
||||
}
|
||||
if (obj is int || obj is Int16 || obj is Int64 || obj is float || obj is double || obj is bool || obj is int? || obj is Int16? || obj is Int64? || obj is float? || obj is double? || obj is bool?)
|
||||
if (obj is int || obj is short || obj is long || obj is float || obj is double || obj is bool || obj is int? || obj is float? || obj is double? || obj is bool?)
|
||||
{
|
||||
return "{0}".InvariantFormat(obj);
|
||||
}
|
||||
@@ -723,7 +723,7 @@ namespace Umbraco.Core
|
||||
{
|
||||
return typeConverter;
|
||||
}
|
||||
|
||||
|
||||
var converter = TypeDescriptor.GetConverter(target);
|
||||
if (converter.CanConvertFrom(source))
|
||||
{
|
||||
@@ -788,6 +788,6 @@ namespace Umbraco.Core
|
||||
return BoolConvertCache[type] = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -470,7 +470,7 @@ namespace Umbraco.Core.Persistence
|
||||
break;
|
||||
|
||||
case SqlDbType.SmallInt:
|
||||
dataType = typeof(Int16);
|
||||
dataType = typeof(short);
|
||||
dataTypeName = "smallint";
|
||||
break;
|
||||
|
||||
@@ -688,34 +688,34 @@ namespace Umbraco.Core.Persistence
|
||||
|
||||
DataColumnCollection columns = _schemaTable.Columns;
|
||||
|
||||
columns.Add(SchemaTableColumn.ColumnName, typeof(System.String));
|
||||
columns.Add(SchemaTableColumn.ColumnOrdinal, typeof(System.Int32));
|
||||
columns.Add(SchemaTableColumn.ColumnSize, typeof(System.Int32));
|
||||
columns.Add(SchemaTableColumn.NumericPrecision, typeof(System.Int16));
|
||||
columns.Add(SchemaTableColumn.NumericScale, typeof(System.Int16));
|
||||
columns.Add(SchemaTableColumn.IsUnique, typeof(System.Boolean));
|
||||
columns.Add(SchemaTableColumn.IsKey, typeof(System.Boolean));
|
||||
columns.Add(SchemaTableOptionalColumn.BaseServerName, typeof(System.String));
|
||||
columns.Add(SchemaTableOptionalColumn.BaseCatalogName, typeof(System.String));
|
||||
columns.Add(SchemaTableColumn.BaseColumnName, typeof(System.String));
|
||||
columns.Add(SchemaTableColumn.BaseSchemaName, typeof(System.String));
|
||||
columns.Add(SchemaTableColumn.BaseTableName, typeof(System.String));
|
||||
columns.Add(SchemaTableColumn.DataType, typeof(System.Type));
|
||||
columns.Add(SchemaTableColumn.AllowDBNull, typeof(System.Boolean));
|
||||
columns.Add(SchemaTableColumn.ProviderType, typeof(System.Int32));
|
||||
columns.Add(SchemaTableColumn.IsAliased, typeof(System.Boolean));
|
||||
columns.Add(SchemaTableColumn.IsExpression, typeof(System.Boolean));
|
||||
columns.Add(BulkDataReader.IsIdentitySchemaColumn, typeof(System.Boolean));
|
||||
columns.Add(SchemaTableOptionalColumn.IsAutoIncrement, typeof(System.Boolean));
|
||||
columns.Add(SchemaTableOptionalColumn.IsRowVersion, typeof(System.Boolean));
|
||||
columns.Add(SchemaTableOptionalColumn.IsHidden, typeof(System.Boolean));
|
||||
columns.Add(SchemaTableColumn.IsLong, typeof(System.Boolean));
|
||||
columns.Add(SchemaTableOptionalColumn.IsReadOnly, typeof(System.Boolean));
|
||||
columns.Add(SchemaTableOptionalColumn.ProviderSpecificDataType, typeof(System.Type));
|
||||
columns.Add(BulkDataReader.DataTypeNameSchemaColumn, typeof(System.String));
|
||||
columns.Add(BulkDataReader.XmlSchemaCollectionDatabaseSchemaColumn, typeof(System.String));
|
||||
columns.Add(BulkDataReader.XmlSchemaCollectionOwningSchemaSchemaColumn, typeof(System.String));
|
||||
columns.Add(BulkDataReader.XmlSchemaCollectionNameSchemaColumn, typeof(System.String));
|
||||
columns.Add(SchemaTableColumn.ColumnName, typeof(string));
|
||||
columns.Add(SchemaTableColumn.ColumnOrdinal, typeof(int));
|
||||
columns.Add(SchemaTableColumn.ColumnSize, typeof(int));
|
||||
columns.Add(SchemaTableColumn.NumericPrecision, typeof(short));
|
||||
columns.Add(SchemaTableColumn.NumericScale, typeof(short));
|
||||
columns.Add(SchemaTableColumn.IsUnique, typeof(bool));
|
||||
columns.Add(SchemaTableColumn.IsKey, typeof(bool));
|
||||
columns.Add(SchemaTableOptionalColumn.BaseServerName, typeof(string));
|
||||
columns.Add(SchemaTableOptionalColumn.BaseCatalogName, typeof(string));
|
||||
columns.Add(SchemaTableColumn.BaseColumnName, typeof(string));
|
||||
columns.Add(SchemaTableColumn.BaseSchemaName, typeof(string));
|
||||
columns.Add(SchemaTableColumn.BaseTableName, typeof(string));
|
||||
columns.Add(SchemaTableColumn.DataType, typeof(Type));
|
||||
columns.Add(SchemaTableColumn.AllowDBNull, typeof(bool));
|
||||
columns.Add(SchemaTableColumn.ProviderType, typeof(int));
|
||||
columns.Add(SchemaTableColumn.IsAliased, typeof(bool));
|
||||
columns.Add(SchemaTableColumn.IsExpression, typeof(bool));
|
||||
columns.Add(BulkDataReader.IsIdentitySchemaColumn, typeof(bool));
|
||||
columns.Add(SchemaTableOptionalColumn.IsAutoIncrement, typeof(bool));
|
||||
columns.Add(SchemaTableOptionalColumn.IsRowVersion, typeof(bool));
|
||||
columns.Add(SchemaTableOptionalColumn.IsHidden, typeof(bool));
|
||||
columns.Add(SchemaTableColumn.IsLong, typeof(bool));
|
||||
columns.Add(SchemaTableOptionalColumn.IsReadOnly, typeof(bool));
|
||||
columns.Add(SchemaTableOptionalColumn.ProviderSpecificDataType, typeof(Type));
|
||||
columns.Add(BulkDataReader.DataTypeNameSchemaColumn, typeof(string));
|
||||
columns.Add(BulkDataReader.XmlSchemaCollectionDatabaseSchemaColumn, typeof(string));
|
||||
columns.Add(BulkDataReader.XmlSchemaCollectionOwningSchemaSchemaColumn, typeof(string));
|
||||
columns.Add(BulkDataReader.XmlSchemaCollectionNameSchemaColumn, typeof(string));
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -1090,7 +1090,7 @@ namespace Umbraco.Core.Persistence
|
||||
/// <seealso cref="IDataRecord.GetDecimal(Int32)"/>
|
||||
public decimal GetDecimal(int i)
|
||||
{
|
||||
return (Decimal)GetValue(i);
|
||||
return (decimal)GetValue(i);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -225,8 +225,17 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
|
||||
if (builtinProperties.ContainsKey(propertyType.Alias))
|
||||
{
|
||||
//this reset's its current data type reference which will be re-assigned based on the property editor assigned on the next line
|
||||
propertyType.DataTypeId = 0;
|
||||
propertyType.DataTypeKey = default;
|
||||
var propDefinition = builtinProperties[propertyType.Alias];
|
||||
if (propDefinition != null)
|
||||
{
|
||||
propertyType.DataTypeId = propDefinition.DataTypeId;
|
||||
propertyType.DataTypeKey = propDefinition.DataTypeKey;
|
||||
}
|
||||
else
|
||||
{
|
||||
propertyType.DataTypeId = 0;
|
||||
propertyType.DataTypeKey = default;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using NPoco;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Logging;
|
||||
@@ -105,7 +106,7 @@ JOIN umbracoNode ON umbracoRedirectUrl.contentKey=umbracoNode.uniqueID");
|
||||
CreateDateUtc = redirectUrl.CreateDateUtc,
|
||||
Url = redirectUrl.Url,
|
||||
Culture = redirectUrl.Culture,
|
||||
UrlHash = redirectUrl.Url.ToSHA1()
|
||||
UrlHash = redirectUrl.Url.GenerateHash<SHA1>()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -134,7 +135,7 @@ JOIN umbracoNode ON umbracoRedirectUrl.contentKey=umbracoNode.uniqueID");
|
||||
|
||||
public IRedirectUrl Get(string url, Guid contentKey, string culture)
|
||||
{
|
||||
var urlHash = url.ToSHA1();
|
||||
var urlHash = url.GenerateHash<SHA1>();
|
||||
var sql = GetBaseQuery(false).Where<RedirectUrlDto>(x => x.Url == url && x.UrlHash == urlHash && x.ContentKey == contentKey && x.Culture == culture);
|
||||
var dto = Database.Fetch<RedirectUrlDto>(sql).FirstOrDefault();
|
||||
return dto == null ? null : Map(dto);
|
||||
@@ -157,7 +158,7 @@ JOIN umbracoNode ON umbracoRedirectUrl.contentKey=umbracoNode.uniqueID");
|
||||
|
||||
public IRedirectUrl GetMostRecentUrl(string url)
|
||||
{
|
||||
var urlHash = url.ToSHA1();
|
||||
var urlHash = url.GenerateHash<SHA1>();
|
||||
var sql = GetBaseQuery(false)
|
||||
.Where<RedirectUrlDto>(x => x.Url == url && x.UrlHash == urlHash)
|
||||
.OrderByDescending<RedirectUrlDto>(x => x.CreateDateUtc);
|
||||
|
||||
@@ -18,6 +18,9 @@ namespace Umbraco.Core.PropertyEditors
|
||||
[JsonProperty("name", Required = Required.Always)]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonProperty("nameTemplate")]
|
||||
public string NameTemplate { get; set; }
|
||||
|
||||
[JsonProperty("alias", Required = Required.Always)]
|
||||
public string Alias { get; set; }
|
||||
|
||||
|
||||
@@ -3083,7 +3083,7 @@ namespace Umbraco.Core.Services.Implement
|
||||
var version = GetVersion(versionId);
|
||||
|
||||
//Good ole null checks
|
||||
if (content == null || version == null)
|
||||
if (content == null || version == null || content.Trashed)
|
||||
{
|
||||
return new OperationResult(OperationResultType.FailedCannot, evtMsgs);
|
||||
}
|
||||
|
||||
@@ -405,6 +405,21 @@ namespace Umbraco.Core.Services.Implement
|
||||
/// <returns></returns>
|
||||
public ITemplate CreateTemplateWithIdentity(string name, string alias, string content, ITemplate masterTemplate = null, int userId = Constants.Security.SuperUserId)
|
||||
{
|
||||
if (name == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(name));
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(name))
|
||||
{
|
||||
throw new ArgumentException("Name cannot be empty or contain only white-space characters", nameof(name));
|
||||
}
|
||||
|
||||
if (name.Length > 255)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(name), "Name cannot be more than 255 characters in length.");
|
||||
}
|
||||
|
||||
// file might already be on disk, if so grab the content to avoid overwriting
|
||||
var template = new Template(name, alias)
|
||||
{
|
||||
@@ -539,6 +554,17 @@ namespace Umbraco.Core.Services.Implement
|
||||
/// <param name="userId"></param>
|
||||
public void SaveTemplate(ITemplate template, int userId = Constants.Security.SuperUserId)
|
||||
{
|
||||
if (template == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(template));
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(template.Name) || template.Name.Length > 255)
|
||||
{
|
||||
throw new InvalidOperationException("Name cannot be null, empty, contain only white-space characters or be more than 255 characters in length.");
|
||||
}
|
||||
|
||||
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
if (scope.Events.DispatchCancelable(SavingTemplate, this, new SaveEventArgs<ITemplate>(template)))
|
||||
|
||||
@@ -816,8 +816,8 @@ namespace Umbraco.Core.Services.Implement
|
||||
{
|
||||
//trimming username and email to make sure we have no trailing space
|
||||
member.Username = member.Username.Trim();
|
||||
member.Email = member.Email.Trim();
|
||||
|
||||
member.Email = member.Email.Trim();
|
||||
|
||||
using (var scope = ScopeProvider.CreateScope())
|
||||
{
|
||||
var saveEventArgs = new SaveEventArgs<IMember>(member);
|
||||
|
||||
@@ -131,6 +131,12 @@ namespace Umbraco.Core.Services
|
||||
private bool IsPropertyValueValid(PropertyType propertyType, object value)
|
||||
{
|
||||
var editor = _propertyEditors[propertyType.PropertyEditorAlias];
|
||||
if (editor == null)
|
||||
{
|
||||
// nothing much we can do validation wise if the property editor has been removed.
|
||||
// the property will be displayed as a label, so flagging it as invalid would be pointless.
|
||||
return true;
|
||||
}
|
||||
var configuration = _dataTypeService.GetDataType(propertyType.DataTypeId).Configuration;
|
||||
var valueEditor = editor.GetValueEditor(configuration);
|
||||
return !valueEditor.Validate(value, propertyType.Mandatory, propertyType.ValidationRegExp).Any();
|
||||
|
||||
@@ -724,67 +724,56 @@ namespace Umbraco.Core
|
||||
/// <summary>
|
||||
/// Generates a hash of a string based on the FIPS compliance setting.
|
||||
/// </summary>
|
||||
/// <param name="str">Refers to itself</param>
|
||||
/// <returns>The hashed string</returns>
|
||||
/// <param name="str">The <see cref="string" /> to hash.</param>
|
||||
/// <returns>
|
||||
/// The hashed string.
|
||||
/// </returns>
|
||||
public static string GenerateHash(this string str)
|
||||
{
|
||||
return CryptoConfig.AllowOnlyFipsAlgorithms
|
||||
? str.ToSHA1()
|
||||
: str.ToMd5();
|
||||
return str.GenerateHash(CryptoConfig.AllowOnlyFipsAlgorithms ? "SHA1" : "MD5");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the string to MD5
|
||||
/// Generate a hash of a string based on the specified hash algorithm.
|
||||
/// </summary>
|
||||
/// <param name="stringToConvert">Refers to itself</param>
|
||||
/// <returns>The MD5 hashed string</returns>
|
||||
[Obsolete("Please use the GenerateHash method instead. This may be removed in future versions")]
|
||||
internal static string ToMd5(this string stringToConvert)
|
||||
/// <typeparam name="T">The hash algorithm implementation to use.</typeparam>
|
||||
/// <param name="str">The <see cref="string" /> to hash.</param>
|
||||
/// <returns>
|
||||
/// The hashed string.
|
||||
/// </returns>
|
||||
internal static string GenerateHash<T>(this string str)
|
||||
where T : HashAlgorithm
|
||||
{
|
||||
return stringToConvert.GenerateHash("MD5");
|
||||
return str.GenerateHash(typeof(T).FullName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Converts the string to SHA1
|
||||
/// Generate a hash of a string based on the specified <paramref name="hashType" />.
|
||||
/// </summary>
|
||||
/// <param name="stringToConvert">refers to itself</param>
|
||||
/// <returns>The SHA1 hashed string</returns>
|
||||
[Obsolete("Please use the GenerateHash method instead. This may be removed in future versions")]
|
||||
internal static string ToSHA1(this string stringToConvert)
|
||||
/// <param name="str">The <see cref="string" /> to hash.</param>
|
||||
/// <param name="hashType">The hash algorithm implementation to use.</param>
|
||||
/// <returns>
|
||||
/// The hashed string.
|
||||
/// </returns>
|
||||
/// <exception cref="System.InvalidOperationException">No hashing type found by name <paramref name="hashType" />.</exception>
|
||||
/// <seealso cref="https://docs.microsoft.com/en-us/dotnet/api/system.security.cryptography.hashalgorithm.create#System_Security_Cryptography_HashAlgorithm_Create_System_String_" />
|
||||
internal static string GenerateHash(this string str, string hashType)
|
||||
{
|
||||
return stringToConvert.GenerateHash("SHA1");
|
||||
}
|
||||
|
||||
/// <summary>Generate a hash of a string based on the hashType passed in
|
||||
/// </summary>
|
||||
/// <param name="str">Refers to itself</param>
|
||||
/// <param name="hashType">String with the hash type. See remarks section of the CryptoConfig Class in MSDN docs for a list of possible values.</param>
|
||||
/// <returns>The hashed string</returns>
|
||||
private static string GenerateHash(this string str, string hashType)
|
||||
{
|
||||
//create an instance of the correct hashing provider based on the type passed in
|
||||
var hasher = HashAlgorithm.Create(hashType);
|
||||
if (hasher == null) throw new InvalidOperationException("No hashing type found by name " + hashType);
|
||||
if (hasher == null) throw new InvalidOperationException($"No hashing type found by name {hashType}.");
|
||||
|
||||
using (hasher)
|
||||
{
|
||||
//convert our string into byte array
|
||||
var byteArray = Encoding.UTF8.GetBytes(str);
|
||||
|
||||
//get the hashed values created by our selected provider
|
||||
var hashedByteArray = hasher.ComputeHash(byteArray);
|
||||
|
||||
//create a StringBuilder object
|
||||
var stringBuilder = new StringBuilder();
|
||||
|
||||
//loop to each byte
|
||||
var sb = new StringBuilder();
|
||||
foreach (var b in hashedByteArray)
|
||||
{
|
||||
//append it to our StringBuilder
|
||||
stringBuilder.Append(b.ToString("x2"));
|
||||
sb.Append(b.ToString("x2"));
|
||||
}
|
||||
|
||||
//return the hashed value
|
||||
return stringBuilder.ToString();
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
<RootNamespace>Umbraco.Core</RootNamespace>
|
||||
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
|
||||
<TargetFrameworkProfile />
|
||||
<AdditionalFileItemNames>$(AdditionalFileItemNames);Content</AdditionalFileItemNames>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@@ -60,6 +61,11 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="SecurityCodeScan">
|
||||
<Version>3.3.0</Version>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Serilog.Sinks.Async">
|
||||
<Version>1.3.0</Version>
|
||||
</PackageReference>
|
||||
@@ -245,6 +251,8 @@
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\RichTextPreValueMigrator.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\DropDownFlexiblePreValueMigrator.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\MergeDateAndDateTimePropertyEditor.cs" />
|
||||
<Compile Include="Models\ContentEditing\ContentAppBadge.cs" />
|
||||
<Compile Include="Models\ContentEditing\ContentAppBadgeType.cs" />
|
||||
<Compile Include="Models\Entities\EntityExtensions.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\PreValueMigratorBase.cs" />
|
||||
<Compile Include="Migrations\Upgrade\V_8_0_0\DataTypes\PreValueDto.cs" />
|
||||
@@ -265,6 +273,7 @@
|
||||
<Compile Include="Models\Entities\IMediaEntitySlim.cs" />
|
||||
<Compile Include="Models\Entities\IMemberEntitySlim.cs" />
|
||||
<Compile Include="Models\Entities\MediaEntitySlim.cs" />
|
||||
<Compile Include="Models\PagedResult.cs" />
|
||||
<Compile Include="Models\Entities\MemberEntitySlim.cs" />
|
||||
<Compile Include="Models\PublishedContent\ILivePublishedModelFactory.cs" />
|
||||
<Compile Include="Models\PublishedContent\IPublishedContentType.cs" />
|
||||
@@ -839,7 +848,7 @@
|
||||
<Compile Include="Models\Packaging\InstallationSummary.cs" />
|
||||
<Compile Include="Models\Packaging\PackageAction.cs" />
|
||||
<Compile Include="Models\Packaging\PreInstallWarnings.cs" />
|
||||
<Compile Include="Models\PagedResult.cs" />
|
||||
<Compile Include="Models\PagedResultOfT.cs" />
|
||||
<Compile Include="Models\PartialView.cs" />
|
||||
<Compile Include="Models\PartialViewType.cs" />
|
||||
<Compile Include="Models\Property.cs" />
|
||||
@@ -1563,4 +1572,4 @@
|
||||
<Folder Include="Auditing\" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -236,7 +236,7 @@ namespace Umbraco.Core.Xml
|
||||
_name = name;
|
||||
_value = value;
|
||||
|
||||
if (value is String)
|
||||
if (value is string)
|
||||
_type = XPathResultType.String;
|
||||
else if (value is bool)
|
||||
_type = XPathResultType.Boolean;
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace Umbraco.Examine
|
||||
/// <summary>
|
||||
/// Performs the data lookups required to rebuild a content index
|
||||
/// </summary>
|
||||
public class ContentIndexPopulator : IndexPopulator<UmbracoContentIndex>
|
||||
public class ContentIndexPopulator : IndexPopulator<IUmbracoContentIndex>
|
||||
{
|
||||
private readonly IContentService _contentService;
|
||||
private readonly IValueSetBuilder<IContent> _contentValueSetBuilder;
|
||||
@@ -36,7 +36,7 @@ namespace Umbraco.Examine
|
||||
/// <param name="contentValueSetBuilder"></param>
|
||||
public ContentIndexPopulator(IContentService contentService, ISqlContext sqlContext, IContentValueSetBuilder contentValueSetBuilder)
|
||||
: this(false, null, contentService, sqlContext, contentValueSetBuilder)
|
||||
{
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
using Examine;
|
||||
|
||||
namespace Umbraco.Examine
|
||||
{
|
||||
public interface IUmbracoContentIndex : IIndex
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
using Examine;
|
||||
|
||||
namespace Umbraco.Examine
|
||||
{
|
||||
public interface IUmbracoMemberIndex : IIndex
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ using Umbraco.Core.Services;
|
||||
|
||||
namespace Umbraco.Examine
|
||||
{
|
||||
public class MemberIndexPopulator : IndexPopulator<UmbracoMemberIndex>
|
||||
public class MemberIndexPopulator : IndexPopulator<IUmbracoMemberIndex>
|
||||
{
|
||||
private readonly IMemberService _memberService;
|
||||
private readonly IValueSetBuilder<IMember> _valueSetBuilder;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
<RootNamespace>Umbraco.Examine</RootNamespace>
|
||||
<SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\</SolutionDir>
|
||||
<TargetFrameworkProfile />
|
||||
<AdditionalFileItemNames>$(AdditionalFileItemNames);Content</AdditionalFileItemNames>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
@@ -56,6 +57,11 @@
|
||||
</PackageReference>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
|
||||
<PackageReference Include="NPoco" Version="3.9.4" />
|
||||
<PackageReference Include="SecurityCodeScan">
|
||||
<Version>3.3.0</Version>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="BaseValueSetBuilder.cs" />
|
||||
@@ -64,10 +70,12 @@
|
||||
<Compile Include="ExamineExtensions.cs" />
|
||||
<Compile Include="IContentValueSetBuilder.cs" />
|
||||
<Compile Include="IContentValueSetValidator.cs" />
|
||||
<Compile Include="IUmbracoContentIndex.cs" />
|
||||
<Compile Include="IUmbracoIndexConfig.cs" />
|
||||
<Compile Include="IIndexCreator.cs" />
|
||||
<Compile Include="IIndexDiagnostics.cs" />
|
||||
<Compile Include="IIndexPopulator.cs" />
|
||||
<Compile Include="IUmbracoMemberIndex.cs" />
|
||||
<Compile Include="UmbracoIndexConfig.cs" />
|
||||
<Compile Include="IndexPopulator.cs" />
|
||||
<Compile Include="IndexRebuilder.cs" />
|
||||
@@ -104,4 +112,4 @@
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
</Project>
|
||||
</Project>
|
||||
|
||||
@@ -17,13 +17,13 @@ namespace Umbraco.Examine
|
||||
/// <summary>
|
||||
/// An indexer for Umbraco content and media
|
||||
/// </summary>
|
||||
public class UmbracoContentIndex : UmbracoExamineIndex
|
||||
public class UmbracoContentIndex : UmbracoExamineIndex, IUmbracoContentIndex
|
||||
{
|
||||
public const string VariesByCultureFieldName = SpecialFieldPrefix + "VariesByCulture";
|
||||
protected ILocalizationService LanguageService { get; }
|
||||
|
||||
#region Constructors
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Create an index at runtime
|
||||
/// </summary>
|
||||
@@ -141,6 +141,6 @@ namespace Umbraco.Examine
|
||||
|
||||
base.PerformDeleteFromIndex(idsAsList, onComplete);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace Umbraco.Examine
|
||||
/// <summary>
|
||||
/// Custom indexer for members
|
||||
/// </summary>
|
||||
public class UmbracoMemberIndex : UmbracoExamineIndex
|
||||
public class UmbracoMemberIndex : UmbracoExamineIndex, IUmbracoMemberIndex
|
||||
{
|
||||
/// <summary>
|
||||
/// Constructor to allow for creating an indexer at runtime
|
||||
@@ -32,6 +32,6 @@ namespace Umbraco.Examine
|
||||
base(name, luceneDirectory, fieldDefinitions, analyzer, profilingLogger, validator)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,7 +165,7 @@ namespace Umbraco.Tests.Composing
|
||||
Assert.IsTrue(TypeHelper.MatchType(typeof(int?), typeof(Nullable<>)));
|
||||
|
||||
|
||||
Assert.IsTrue(TypeHelper.MatchType(typeof(Derived<int>), typeof(Object)));
|
||||
Assert.IsTrue(TypeHelper.MatchType(typeof(Derived<int>), typeof(object)));
|
||||
Assert.IsFalse(TypeHelper.MatchType(typeof(Derived<int>), typeof(List<>)));
|
||||
Assert.IsFalse(TypeHelper.MatchType(typeof(Derived<int>), typeof(IEnumerable<>)));
|
||||
Assert.IsTrue(TypeHelper.MatchType(typeof(Derived<int>), typeof(Base<int>)));
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings
|
||||
[Test]
|
||||
public void PreviewBadge()
|
||||
{
|
||||
Assert.AreEqual(SettingsSection.Content.PreviewBadge, @"<a id=""umbracoPreviewBadge"" style=""z-index:99999; position: absolute; top: 0; right: 0; border: 0; width: 149px; height: 149px; background: url('{0}/assets/img/preview-mode-badge.png') no-repeat;"" href=""#"" OnClick=""javascript:window.top.location.href = '{0}/preview/end?redir={1}'""><span style=""display:none;"">In Preview Mode - click to end</span></a>");
|
||||
Assert.AreEqual(SettingsSection.Content.PreviewBadge, @"<div id=""umbracoPreviewBadge"" class=""umbraco-preview-badge""><span class=""umbraco-preview-badge__header"">Preview mode</span><a href=""{0}/preview/end?redir={1}"" class=""umbraco-preview-badge__end""><svg viewBox=""0 0 100 100"" xmlns=""http://www.w3.org/2000/svg""><title>Click to end</title><path d=""M5273.1 2400.1v-2c0-2.8-5-4-9.7-4s-9.7 1.3-9.7 4v2a7 7 0 002 4.9l5 4.9c.3.3.4.6.4 1v6.4c0 .4.2.7.6.8l2.9.9c.5.1 1-.2 1-.8v-7.2c0-.4.2-.7.4-1l5.1-5a7 7 0 002-4.9zm-9.7-.1c-4.8 0-7.4-1.3-7.5-1.8.1-.5 2.7-1.8 7.5-1.8s7.3 1.3 7.5 1.8c-.2.5-2.7 1.8-7.5 1.8z""/><path d=""M5268.4 2410.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1s-.4-1-1-1h-4.3zM5272.7 2413.7h-4.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1s-.4-1-1-1zM5272.7 2417h-4.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1 0-.5-.4-1-1-1z""/><path d=""M78.2 13l-8.7 11.7a32.5 32.5 0 11-51.9 25.8c0-10.3 4.7-19.7 12.9-25.8L21.8 13a47 47 0 1056.4 0z""/><path d=""M42.7 2.5h14.6v49.4H42.7z""/></svg></a></div><style type=""text/css"">.umbraco-preview-badge {{position: absolute;top: 1em;right: 1em;display: inline-flex;background: #1b264f;color: #fff;padding: 1em;font-size: 12px;z-index: 99999999;justify-content: center;align-items: center;box-shadow: 0 10px 50px rgba(0, 0, 0, .1), 0 6px 20px rgba(0, 0, 0, .16);line-height: 1;}}.umbraco-preview-badge__header {{font-weight: bold;}}.umbraco-preview-badge__end {{width: 3em;padding: 1em;margin: -1em -1em -1em 2em;display: flex;flex-shrink: 0;align-items: center;align-self: stretch;}}.umbraco-preview-badge__end:hover,.umbraco-preview-badge__end:focus {{background: #f5c1bc;}}.umbraco-preview-badge__end svg {{fill: #fff;width:1em;}}</style>");
|
||||
}
|
||||
[Test]
|
||||
public void ResolveUrlsFromTextString()
|
||||
|
||||
@@ -41,9 +41,7 @@
|
||||
</notifications>
|
||||
|
||||
<PreviewBadge>
|
||||
<![CDATA[
|
||||
<a id="umbracoPreviewBadge" style="z-index:99999; position: absolute; top: 0; right: 0; border: 0; width: 149px; height: 149px; background: url('{0}/assets/img/preview-mode-badge.png') no-repeat;" href="#" OnClick="javascript:window.top.location.href = '{0}/preview/end?redir={1}'"><span style="display:none;">In Preview Mode - click to end</span></a>
|
||||
]]></PreviewBadge>
|
||||
<![CDATA[<div id="umbracoPreviewBadge" class="umbraco-preview-badge"><span class="umbraco-preview-badge__header">Preview mode</span><a href="{0}/preview/end?redir={1}" class="umbraco-preview-badge__end"><svg viewBox="0 0 100 100" xmlns="http://www.w3.org/2000/svg"><title>Click to end</title><path d="M5273.1 2400.1v-2c0-2.8-5-4-9.7-4s-9.7 1.3-9.7 4v2a7 7 0 002 4.9l5 4.9c.3.3.4.6.4 1v6.4c0 .4.2.7.6.8l2.9.9c.5.1 1-.2 1-.8v-7.2c0-.4.2-.7.4-1l5.1-5a7 7 0 002-4.9zm-9.7-.1c-4.8 0-7.4-1.3-7.5-1.8.1-.5 2.7-1.8 7.5-1.8s7.3 1.3 7.5 1.8c-.2.5-2.7 1.8-7.5 1.8z"/><path d="M5268.4 2410.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1s-.4-1-1-1h-4.3zM5272.7 2413.7h-4.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1s-.4-1-1-1zM5272.7 2417h-4.3c-.6 0-1 .4-1 1s.4 1 1 1h4.3c.6 0 1-.4 1-1 0-.5-.4-1-1-1z"/><path d="M78.2 13l-8.7 11.7a32.5 32.5 0 11-51.9 25.8c0-10.3 4.7-19.7 12.9-25.8L21.8 13a47 47 0 1056.4 0z"/><path d="M42.7 2.5h14.6v49.4H42.7z"/></svg></a></div><style type="text/css">.umbraco-preview-badge {{position: absolute;top: 1em;right: 1em;display: inline-flex;background: #1b264f;color: #fff;padding: 1em;font-size: 12px;z-index: 99999999;justify-content: center;align-items: center;box-shadow: 0 10px 50px rgba(0, 0, 0, .1), 0 6px 20px rgba(0, 0, 0, .16);line-height: 1;}}.umbraco-preview-badge__header {{font-weight: bold;}}.umbraco-preview-badge__end {{width: 3em;padding: 1em;margin: -1em -1em -1em 2em;display: flex;flex-shrink: 0;align-items: center;align-self: stretch;}}.umbraco-preview-badge__end:hover,.umbraco-preview-badge__end:focus {{background: #f5c1bc;}}.umbraco-preview-badge__end svg {{fill: #fff;width:1em;}}</style>]]></PreviewBadge>
|
||||
|
||||
<!-- How Umbraco should handle errors during macro execution. Can be one of the following values:
|
||||
- inline - show an inline error within the macro but allow the page to continue rendering. Historial Umbraco behaviour.
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using NUnit.Framework;
|
||||
@@ -8,6 +9,8 @@ namespace Umbraco.Tests.Testing
|
||||
{
|
||||
public abstract class TestOptionAttributeBase : Attribute
|
||||
{
|
||||
public static readonly List<Assembly> ScanAssemblies = new List<Assembly>();
|
||||
|
||||
public static TOptions GetTestOptions<TOptions>(MethodInfo method)
|
||||
where TOptions : TestOptionAttributeBase, new()
|
||||
{
|
||||
@@ -28,9 +31,18 @@ namespace Umbraco.Tests.Testing
|
||||
var test = TestContext.CurrentContext.Test;
|
||||
var typeName = test.ClassName;
|
||||
var methodName = test.MethodName;
|
||||
var type = Type.GetType(typeName, true);
|
||||
var type = Type.GetType(typeName, false);
|
||||
if (type == null)
|
||||
throw new PanicException($"Could not resolve the type from type name {typeName}"); // makes no sense
|
||||
{
|
||||
type = ScanAssemblies
|
||||
.Select(assembly => assembly.GetType(typeName, false))
|
||||
.FirstOrDefault(x => x != null);
|
||||
if (type == null)
|
||||
{
|
||||
throw new PanicException($"Could not resolve the running test fixture from type name {typeName}.\n" +
|
||||
$"To use base classes from Umbraco.Tests, add your test assembly to TestOptionAttributeBase.ScanAssemblies");
|
||||
}
|
||||
}
|
||||
var methodInfo = type.GetMethod(methodName); // what about overloads?
|
||||
var options = GetTestOptions<TOptions>(methodInfo);
|
||||
return options;
|
||||
|
||||
@@ -7,10 +7,13 @@ using NUnit.Framework;
|
||||
using Umbraco.Core;
|
||||
using Umbraco.Core.Cache;
|
||||
using Umbraco.Core.Composing;
|
||||
using Umbraco.Core.Configuration;
|
||||
using Umbraco.Core.Dictionary;
|
||||
using Umbraco.Core.Logging;
|
||||
using Umbraco.Core.Mapping;
|
||||
using Umbraco.Core.Models;
|
||||
using Umbraco.Core.Models.PublishedContent;
|
||||
using Umbraco.Core.Persistence;
|
||||
using Umbraco.Core.Services;
|
||||
using Umbraco.Tests.TestHelpers;
|
||||
using Umbraco.Tests.TestHelpers.Stubs;
|
||||
@@ -19,6 +22,7 @@ using Umbraco.Web;
|
||||
using Umbraco.Web.PublishedCache;
|
||||
using Umbraco.Web.Routing;
|
||||
using Umbraco.Web.Security;
|
||||
using Umbraco.Web.WebApi;
|
||||
using Current = Umbraco.Web.Composing.Current;
|
||||
|
||||
namespace Umbraco.Tests.Testing.TestingTests
|
||||
@@ -88,5 +92,26 @@ namespace Umbraco.Tests.Testing.TestingTests
|
||||
|
||||
Assert.AreEqual("/hello/world/1234", theUrlProvider.GetUrl(publishedContent));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Can_Mock_UmbracoApiController_Dependencies_With_Injected_UmbracoMapper()
|
||||
{
|
||||
var umbracoContext = TestObjects.GetUmbracoContextMock();
|
||||
|
||||
var membershipHelper = new MembershipHelper(umbracoContext.HttpContext, Mock.Of<IPublishedMemberCache>(), Mock.Of<MembershipProvider>(), Mock.Of<RoleProvider>(), Mock.Of<IMemberService>(), Mock.Of<IMemberTypeService>(), Mock.Of<IUserService>(), Mock.Of<IPublicAccessService>(), Mock.Of<AppCaches>(), Mock.Of<ILogger>());
|
||||
var umbracoHelper = new UmbracoHelper(Mock.Of<IPublishedContent>(), Mock.Of<ITagQuery>(), Mock.Of<ICultureDictionaryFactory>(), Mock.Of<IUmbracoComponentRenderer>(), Mock.Of<IPublishedContentQuery>(), membershipHelper);
|
||||
var umbracoMapper = new UmbracoMapper(new MapDefinitionCollection(new[] { Mock.Of<IMapDefinition>() }));
|
||||
|
||||
// ReSharper disable once UnusedVariable
|
||||
var umbracoApiController = new FakeUmbracoApiController(Mock.Of<IGlobalSettings>(), Mock.Of<IUmbracoContextAccessor>(), Mock.Of<ISqlContext>(), ServiceContext.CreatePartial(), AppCaches.NoCache, Mock.Of<IProfilingLogger>(), Mock.Of<IRuntimeState>(), umbracoHelper, umbracoMapper);
|
||||
|
||||
Assert.Pass();
|
||||
}
|
||||
}
|
||||
|
||||
internal class FakeUmbracoApiController : UmbracoApiController
|
||||
{
|
||||
public FakeUmbracoApiController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper) : base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper) { }
|
||||
public FakeUmbracoApiController(IGlobalSettings globalSettings, IUmbracoContextAccessor umbracoContextAccessor, ISqlContext sqlContext, ServiceContext services, AppCaches appCaches, IProfilingLogger logger, IRuntimeState runtimeState, UmbracoHelper umbracoHelper, UmbracoMapper umbracoMapper) : base(globalSettings, umbracoContextAccessor, sqlContext, services, appCaches, logger, runtimeState, umbracoHelper, umbracoMapper) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,26 +3,26 @@
|
||||
module.exports = {
|
||||
sources: {
|
||||
|
||||
//less files used by backoffice and preview
|
||||
//processed in the less task
|
||||
// less files used by backoffice and preview
|
||||
// processed in the less task
|
||||
less: {
|
||||
installer: { files: ["./src/less/installer.less"], out: "installer.css" },
|
||||
nonodes: { files: ["./src/less/pages/nonodes.less"], out: "nonodes.style.min.css"},
|
||||
preview: { files: ["./src/less/canvas-designer.less"], out: "canvasdesigner.css" },
|
||||
umbraco: { files: ["./src/less/belle.less"], out: "umbraco.css" },
|
||||
rteContent: { files: ["./src/less/rte-content.less"], out: "rte-content.css" }
|
||||
installer: { files: "./src/less/installer.less", watch: "./src/less/**/*.less", out: "installer.css" },
|
||||
nonodes: { files: "./src/less/pages/nonodes.less", watch: "./src/less/**/*.less", out: "nonodes.style.min.css"},
|
||||
preview: { files: "./src/less/canvas-designer.less", watch: "./src/less/**/*.less", out: "canvasdesigner.css" },
|
||||
umbraco: { files: "./src/less/belle.less", watch: "./src/less/**/*.less", out: "umbraco.css" },
|
||||
rteContent: { files: "./src/less/rte-content.less", watch: "./src/less/**/*.less", out: "rte-content.css" }
|
||||
},
|
||||
|
||||
//js files for backoffie
|
||||
//processed in the js task
|
||||
// js files for backoffice
|
||||
// processed in the js task
|
||||
js: {
|
||||
preview: { files: ["./src/preview/**/*.js"], out: "umbraco.preview.js" },
|
||||
installer: { files: ["./src/installer/**/*.js"], out: "umbraco.installer.js" },
|
||||
filters: { files: ["./src/common/filters/**/*.js"], out: "umbraco.filters.js" },
|
||||
resources: { files: ["./src/common/resources/**/*.js"], out: "umbraco.resources.js" },
|
||||
services: { files: ["./src/common/services/**/*.js"], out: "umbraco.services.js" },
|
||||
security: { files: ["./src/common/interceptors/**/*.js"], out: "umbraco.interceptors.js" },
|
||||
|
||||
preview: { files: "./src/preview/**/*.js", out: "umbraco.preview.js" },
|
||||
installer: { files: "./src/installer/**/*.js", out: "umbraco.installer.js" },
|
||||
filters: { files: "./src/common/filters/**/*.js", out: "umbraco.filters.js" },
|
||||
resources: { files: "./src/common/resources/**/*.js", out: "umbraco.resources.js" },
|
||||
services: { files: "./src/common/services/**/*.js", out: "umbraco.services.js" },
|
||||
security: { files: "./src/common/interceptors/**/*.js", out: "umbraco.interceptors.js" },
|
||||
|
||||
//the controllers for views
|
||||
controllers: {
|
||||
files: [
|
||||
@@ -42,13 +42,16 @@ module.exports = {
|
||||
],
|
||||
out: "umbraco.directives.js"
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
//selectors for copying all views into the build
|
||||
//processed in the views task
|
||||
views:{
|
||||
umbraco: {files: ["./src/views/**/*.html"], folder: ""},
|
||||
installer: {files: ["./src/installer/steps/*.html"], folder: "install/"}
|
||||
views: {files: "./src/views/**/*.html", folder: ""},
|
||||
directives: {files: "./src/common/directives/**/*.html", folder: ""},
|
||||
components: {files: "./src/common/components/**/*.html", folder: ""},
|
||||
installer: {files: "./src/installer/steps/*.html", folder: "install/"}
|
||||
},
|
||||
|
||||
//globs for file-watching
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var fs = require('fs');
|
||||
|
||||
var onlyScripts = require('./util/scriptFilter');
|
||||
var tasks = fs.readdirSync('./gulp/tasks/').filter(onlyScripts);
|
||||
|
||||
tasks.forEach(function(task) {
|
||||
require('./tasks/' + task);
|
||||
});
|
||||
@@ -1,10 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var config = require('../config');
|
||||
var gulp = require('gulp');
|
||||
var runSequence = require('run-sequence');
|
||||
|
||||
// Build - build the files ready for production
|
||||
gulp.task('build', function(cb) {
|
||||
runSequence(["js", "dependencies", "less", "views"], "test:unit", cb);
|
||||
});
|
||||
@@ -10,7 +10,7 @@ var imagemin = require('gulp-imagemin');
|
||||
/**************************
|
||||
* Task processes and copies all dependencies, either installed by npm or stored locally in the project
|
||||
**************************/
|
||||
gulp.task('dependencies', function () {
|
||||
function dependencies() {
|
||||
|
||||
//as we do multiple things in this task, we merge the multiple streams
|
||||
var stream = new MergeStream();
|
||||
@@ -244,21 +244,21 @@ gulp.task('dependencies', function () {
|
||||
nodeModules.forEach(module => {
|
||||
stream.add(
|
||||
gulp.src(module.src,
|
||||
{ base: module.base })
|
||||
{ base: module.base, allowEmpty: true })
|
||||
.pipe(gulp.dest(config.root + config.targets.lib + "/" + module.name))
|
||||
);
|
||||
});
|
||||
|
||||
//copy over libs which are not on npm (/lib)
|
||||
stream.add(
|
||||
gulp.src(config.sources.globs.lib)
|
||||
gulp.src(config.sources.globs.lib, { allowEmpty: true })
|
||||
.pipe(gulp.dest(config.root + config.targets.lib))
|
||||
);
|
||||
|
||||
//Copies all static assets into /root / assets folder
|
||||
//css, fonts and image files
|
||||
|
||||
var assetsTask = gulp.src(config.sources.globs.assets);
|
||||
var assetsTask = gulp.src(config.sources.globs.assets, { allowEmpty: true });
|
||||
if (global.isProd === true) {
|
||||
assetsTask = assetsTask.pipe(imagemin([
|
||||
imagemin.gifsicle({interlaced: true}),
|
||||
@@ -277,21 +277,23 @@ gulp.task('dependencies', function () {
|
||||
stream.add(assetsTask);
|
||||
|
||||
// Copies all the less files related to the preview into their folder
|
||||
//these are not pre-processed as preview has its own less combiler client side
|
||||
//these are not pre-processed as preview has its own less compiler client side
|
||||
stream.add(
|
||||
gulp.src("src/canvasdesigner/editors/*.less")
|
||||
gulp.src("src/canvasdesigner/editors/*.less", { allowEmpty: true })
|
||||
.pipe(gulp.dest(config.root + config.targets.assets + "/less"))
|
||||
);
|
||||
|
||||
// Todo: check if we need these fileSize
|
||||
// TODO: check if we need these fileSize
|
||||
stream.add(
|
||||
gulp.src("src/views/propertyeditors/grid/config/*.*")
|
||||
gulp.src("src/views/propertyeditors/grid/config/*.*", { allowEmpty: true })
|
||||
.pipe(gulp.dest(config.root + config.targets.views + "/propertyeditors/grid/config"))
|
||||
);
|
||||
stream.add(
|
||||
gulp.src("src/views/dashboard/default/*.jpg")
|
||||
gulp.src("src/views/dashboard/default/*.jpg", { allowEmpty: true })
|
||||
.pipe(gulp.dest(config.root + config.targets.views + "/dashboard/default"))
|
||||
);
|
||||
|
||||
return stream;
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = { dependencies: dependencies };
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var config = require('../config');
|
||||
var gulp = require('gulp');
|
||||
var runSequence = require('run-sequence');
|
||||
|
||||
// Dev - build the files ready for development and start watchers
|
||||
gulp.task('dev', function (cb) {
|
||||
|
||||
global.isProd = false;
|
||||
|
||||
runSequence(["dependencies", "js", "less", "views"], "watch", cb);
|
||||
});
|
||||
@@ -9,21 +9,24 @@ var MergeStream = require('merge-stream');
|
||||
var processJs = require('../util/processJs');
|
||||
|
||||
/**************************
|
||||
* Copies all angular JS files into their seperate umbraco.*.js file
|
||||
* Copies all angular JS files into their separate umbraco.*.js file
|
||||
**************************/
|
||||
gulp.task('js', function () {
|
||||
function js() {
|
||||
|
||||
//we run multiple streams, so merge them all together
|
||||
var stream = new MergeStream();
|
||||
|
||||
stream.add(
|
||||
gulp.src(config.sources.globs.js)
|
||||
.pipe(gulp.dest(config.root + config.targets.js))
|
||||
);
|
||||
gulp.src(config.sources.globs.js).pipe( gulp.dest(config.root + config.targets.js) )
|
||||
);
|
||||
|
||||
_.forEach(config.sources.js, function (group) {
|
||||
stream.add (processJs(group.files, group.out) );
|
||||
});
|
||||
_.forEach(config.sources.js, function (group) {
|
||||
stream.add(
|
||||
processJs(group.files, group.out)
|
||||
);
|
||||
});
|
||||
|
||||
return stream;
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = { js: js };
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
var config = require('../config');
|
||||
var gulp = require('gulp');
|
||||
|
||||
var _ = require('lodash');
|
||||
var MergeStream = require('merge-stream');
|
||||
|
||||
var processLess = require('../util/processLess');
|
||||
|
||||
gulp.task('less', function () {
|
||||
function less() {
|
||||
|
||||
var stream = new MergeStream();
|
||||
|
||||
@@ -17,4 +16,6 @@ gulp.task('less', function () {
|
||||
});
|
||||
|
||||
return stream;
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = { less: less };
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
'use strict';
|
||||
|
||||
var gulp = require('gulp');
|
||||
var through2 = require('through2');
|
||||
|
||||
function createEmptyStream() {
|
||||
var pass = through2.obj();
|
||||
process.nextTick(pass.end.bind(pass));
|
||||
return pass;
|
||||
}
|
||||
|
||||
/**************************
|
||||
* Copies all angular JS files into their separate umbraco.*.js file
|
||||
**************************/
|
||||
function removeProductionMode() {
|
||||
|
||||
global.isProd = false;
|
||||
|
||||
return createEmptyStream();
|
||||
};
|
||||
|
||||
module.exports = { removeProductionMode: removeProductionMode };
|
||||
@@ -1,32 +1,27 @@
|
||||
'use strict';
|
||||
|
||||
var config = require('../config');
|
||||
var gulp = require('gulp');
|
||||
var karmaServer = require('karma').Server;
|
||||
var runSequence = require('run-sequence');
|
||||
|
||||
/**************************
|
||||
* Build tests
|
||||
**************************/
|
||||
|
||||
// Karma test
|
||||
gulp.task('runTests', function(cb) {
|
||||
runSequence("js", "test:unit", cb);
|
||||
});
|
||||
function testUnit() {
|
||||
|
||||
gulp.task('test:unit', function () {
|
||||
|
||||
new karmaServer({
|
||||
return new karmaServer({
|
||||
configFile: __dirname + "/../../test/config/karma.conf.js",
|
||||
keepalive: true
|
||||
})
|
||||
.start();
|
||||
});
|
||||
};
|
||||
|
||||
gulp.task('test:e2e', function() {
|
||||
new karmaServer({
|
||||
function testE2e() {
|
||||
return new karmaServer({
|
||||
configFile: __dirname + "/../../test/config/e2e.js",
|
||||
keepalive: true
|
||||
})
|
||||
.start();
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = { testUnit: testUnit, testE2e: testE2e };
|
||||
|
||||
@@ -6,7 +6,7 @@ var gulp = require('gulp');
|
||||
var _ = require('lodash');
|
||||
var MergeStream = require('merge-stream');
|
||||
|
||||
gulp.task('views', function () {
|
||||
function views() {
|
||||
|
||||
var stream = new MergeStream();
|
||||
|
||||
@@ -22,4 +22,7 @@ gulp.task('views', function () {
|
||||
});
|
||||
|
||||
return stream;
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = { views: views };
|
||||
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
var config = require('../config');
|
||||
var gulp = require('gulp');
|
||||
|
||||
var _ = require('lodash');
|
||||
var MergeStream = require('merge-stream');
|
||||
|
||||
var processJs = require('../util/processJs');
|
||||
|
||||
var watch = require('gulp-watch');
|
||||
|
||||
gulp.task('watch', function () {
|
||||
|
||||
var stream = new MergeStream();
|
||||
var watchInterval = 500;
|
||||
|
||||
//Setup a watcher for all groups of javascript files
|
||||
_.forEach(config.sources.js, function (group) {
|
||||
|
||||
if(group.watch !== false){
|
||||
|
||||
stream.add(
|
||||
|
||||
watch(group.files, { ignoreInitial: true, interval: watchInterval }, function (file) {
|
||||
|
||||
console.info(file.path + " has changed, added to: " + group.out);
|
||||
processJs(group.files, group.out);
|
||||
|
||||
})
|
||||
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
stream.add(
|
||||
//watch all less files and trigger the less task
|
||||
watch(config.sources.globs.less, { ignoreInitial: true, interval: watchInterval }, function () {
|
||||
gulp.run(['less']);
|
||||
})
|
||||
);
|
||||
|
||||
//watch all views - copy single file changes
|
||||
stream.add(
|
||||
watch(config.sources.globs.views, { interval: watchInterval })
|
||||
.pipe(gulp.dest(config.root + config.targets.views))
|
||||
);
|
||||
|
||||
//watch all app js files that will not be merged - copy single file changes
|
||||
stream.add(
|
||||
watch(config.sources.globs.js, { interval: watchInterval })
|
||||
.pipe(gulp.dest(config.root + config.targets.js))
|
||||
);
|
||||
|
||||
return stream;
|
||||
});
|
||||
@@ -0,0 +1,49 @@
|
||||
'use strict';
|
||||
|
||||
const config = require('../config');
|
||||
const {watch, parallel, dest, src} = require('gulp');
|
||||
|
||||
var _ = require('lodash');
|
||||
var MergeStream = require('merge-stream');
|
||||
|
||||
var processJs = require('../util/processJs');
|
||||
var processLess = require('../util/processLess');
|
||||
|
||||
//const { less } = require('./less');
|
||||
//const { views } = require('./views');
|
||||
|
||||
|
||||
function watchTask(cb) {
|
||||
|
||||
var watchInterval = 500;
|
||||
|
||||
//Setup a watcher for all groups of JS files
|
||||
_.forEach(config.sources.js, function (group) {
|
||||
if(group.watch !== false) {
|
||||
watch(group.files, { ignoreInitial: true, interval: watchInterval }, function JS_Group_Compile() { return processJs(group.files, group.out);});
|
||||
}
|
||||
});
|
||||
|
||||
//Setup a watcher for all groups of LESS files
|
||||
_.forEach(config.sources.less, function (group) {
|
||||
if(group.watch !== false) {
|
||||
watch(group.watch, { ignoreInitial: true, interval: watchInterval }, function Less_Group_Compile() { return processLess(group.files, group.out); });
|
||||
}
|
||||
});
|
||||
|
||||
//Setup a watcher for all groups of view files
|
||||
var viewWatcher;
|
||||
_.forEach(config.sources.views, function (group) {
|
||||
if(group.watch !== false) {
|
||||
viewWatcher = watch(group.files, { ignoreInitial: true, interval: watchInterval });
|
||||
viewWatcher.on('change', function(path, stats) {
|
||||
console.log("copying " + group.files + " to " + config.root + config.targets.views + group.folder);
|
||||
src(group.files).pipe( dest(config.root + config.targets.views + group.folder) );
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return cb();
|
||||
};
|
||||
|
||||
module.exports = { watchTask: watchTask };
|
||||
@@ -11,6 +11,8 @@ var embedTemplates = require('gulp-angular-embed-templates');
|
||||
|
||||
module.exports = function (files, out) {
|
||||
|
||||
console.log("JS: ", files, " -> ", config.root + config.targets.js + out)
|
||||
|
||||
var task = gulp.src(files);
|
||||
|
||||
// check for js errors
|
||||
|
||||
@@ -15,7 +15,9 @@ module.exports = function(files, out) {
|
||||
autoprefixer,
|
||||
cssnano({zindex: false})
|
||||
];
|
||||
|
||||
|
||||
console.log("LESS: ", files, " -> ", config.root + config.targets.css + out)
|
||||
|
||||
var task = gulp.src(files)
|
||||
.pipe(less())
|
||||
.pipe(cleanCss())
|
||||
|
||||
@@ -1,16 +1,49 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
/*
|
||||
* gulpfile.js
|
||||
* ===========
|
||||
* Rather than manage one giant configuration file responsible
|
||||
* for creating multiple tasks, each task has been broken out into
|
||||
* its own file in gulp/tasks. Any file in that folder gets automatically
|
||||
* required by the loop in ./gulp/index.js (required below).
|
||||
*
|
||||
* To add a new task, simply add a new task file to gulp/tasks.
|
||||
*/
|
||||
* gulpfile.js
|
||||
* ===========
|
||||
* This is now using Gulp 4, each child task is now a child function in its own corresponding file.
|
||||
*
|
||||
* To add a new task, simply add a new task file to gulp/tasks folder, add a require statement below to include the one or more methods
|
||||
* and then add the exports command to add the new item into the task menu.
|
||||
*/
|
||||
|
||||
global.isProd = true;
|
||||
|
||||
require('./gulp');
|
||||
const { src, dest, series, parallel, lastRun } = require('gulp');
|
||||
|
||||
const { dependencies } = require('./gulp/tasks/dependencies');
|
||||
const { js } = require('./gulp/tasks/js');
|
||||
const { less } = require('./gulp/tasks/less');
|
||||
const { testE2e, testUnit } = require('./gulp/tasks/test');
|
||||
const { views } = require('./gulp/tasks/views');
|
||||
const { watchTask } = require('./gulp/tasks/watchTask');
|
||||
const { removeProductionMode } = require('./gulp/tasks/removeProductionMode');
|
||||
|
||||
// Load local overwrites, can be used to overwrite paths in your local setup.
|
||||
var fs = require('fs');
|
||||
var onlyScripts = require('./gulp/util/scriptFilter');
|
||||
try {
|
||||
if (fs.existsSync('./gulp/overwrites/')) {
|
||||
var overwrites = fs.readdirSync('./gulp/overwrites/').filter(onlyScripts);
|
||||
overwrites.forEach(function(overwrite) {
|
||||
require('./gulp/overwrites/' + overwrite);
|
||||
});
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
|
||||
// ***********************************************************
|
||||
// These Exports are the new way of defining Tasks in Gulp 4.x
|
||||
// ***********************************************************
|
||||
exports.build = series(parallel(dependencies, js, less, views), testUnit);
|
||||
exports.dev = series(parallel(dependencies, js, less, views), watchTask);
|
||||
exports.fastdev = series(removeProductionMode, parallel(dependencies, js, less, views), watchTask);
|
||||
exports.watch = series(watchTask);
|
||||
//
|
||||
exports.runTests = series(js, testUnit);
|
||||
exports.testUnit = series(testUnit);
|
||||
exports.testE2e = series(testE2e);
|
||||
|
||||
+2572
-2774
File diff suppressed because it is too large
Load Diff
@@ -1,80 +1,84 @@
|
||||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"test": "karma start test/config/karma.conf.js --singlerun",
|
||||
"build": "gulp build",
|
||||
"dev": "gulp dev",
|
||||
"fastdev": "gulp fastdev"
|
||||
},
|
||||
"dependencies": {
|
||||
"ace-builds": "1.4.2",
|
||||
"angular": "1.7.5",
|
||||
"angular-animate": "1.7.5",
|
||||
"angular-aria": "1.7.5",
|
||||
"angular-chart.js": "^1.1.1",
|
||||
"angular-cookies": "1.7.5",
|
||||
"angular-dynamic-locale": "0.1.37",
|
||||
"angular-i18n": "1.7.5",
|
||||
"angular-local-storage": "0.7.1",
|
||||
"angular-messages": "1.7.5",
|
||||
"angular-mocks": "1.7.5",
|
||||
"angular-route": "1.7.5",
|
||||
"angular-sanitize": "1.7.5",
|
||||
"angular-touch": "1.7.5",
|
||||
"angular-ui-sortable": "0.19.0",
|
||||
"animejs": "2.2.0",
|
||||
"bootstrap-social": "5.1.1",
|
||||
"chart.js": "^2.7.3",
|
||||
"clipboard": "2.0.4",
|
||||
"diff": "3.5.0",
|
||||
"flatpickr": "4.5.2",
|
||||
"font-awesome": "4.7.0",
|
||||
"jquery": "^3.4.0",
|
||||
"jquery-ui-dist": "1.12.1",
|
||||
"jquery-ui-touch-punch": "0.2.3",
|
||||
"lazyload-js": "1.0.0",
|
||||
"moment": "2.22.2",
|
||||
"ng-file-upload": "12.2.13",
|
||||
"nouislider": "14.0.2",
|
||||
"npm": "^6.4.1",
|
||||
"signalr": "2.4.0",
|
||||
"spectrum-colorpicker": "1.8.0",
|
||||
"tinymce": "4.9.2",
|
||||
"typeahead.js": "0.11.1",
|
||||
"underscore": "1.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.1.6",
|
||||
"@babel/preset-env": "7.1.6",
|
||||
"autoprefixer": "9.3.1",
|
||||
"cssnano": "4.1.7",
|
||||
"fs": "0.0.2",
|
||||
"gulp": "^3.9.1",
|
||||
"gulp-angular-embed-templates": "^2.3.0",
|
||||
"gulp-babel": "8.0.0",
|
||||
"gulp-clean-css": "4.0.0",
|
||||
"gulp-cli": "^2.0.1",
|
||||
"gulp-concat": "2.6.1",
|
||||
"gulp-eslint": "^5.0.0",
|
||||
"gulp-imagemin": "^4.1.0",
|
||||
"gulp-less": "4.0.1",
|
||||
"gulp-notify": "^3.0.0",
|
||||
"gulp-postcss": "8.0.0",
|
||||
"gulp-rename": "1.4.0",
|
||||
"gulp-sort": "2.0.0",
|
||||
"gulp-watch": "5.0.1",
|
||||
"gulp-wrap": "0.14.0",
|
||||
"gulp-wrap-js": "0.4.1",
|
||||
"jasmine-core": "3.3.0",
|
||||
"karma": "3.1.1",
|
||||
"karma-jasmine": "2.0.1",
|
||||
"karma-junit-reporter": "^1.2.0",
|
||||
"karma-phantomjs-launcher": "1.0.4",
|
||||
"less": "3.9.0",
|
||||
"lodash": "4.17.13",
|
||||
"marked": "^0.6.1",
|
||||
"merge-stream": "1.0.1",
|
||||
"run-sequence": "2.2.1",
|
||||
"caniuse-lite": "^1.0.30000966"
|
||||
}
|
||||
}
|
||||
{
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"test": "gulp runTests",
|
||||
"unit": "gulp testUnit",
|
||||
"e2e": "gulp testE2e",
|
||||
"build": "gulp build",
|
||||
"dev": "gulp dev",
|
||||
"fastdev": "gulp fastdev",
|
||||
"watch": "gulp watch"
|
||||
},
|
||||
"dependencies": {
|
||||
"ace-builds": "1.4.2",
|
||||
"angular": "1.7.5",
|
||||
"angular-animate": "1.7.5",
|
||||
"angular-aria": "1.7.5",
|
||||
"angular-chart.js": "^1.1.1",
|
||||
"angular-cookies": "1.7.5",
|
||||
"angular-dynamic-locale": "0.1.37",
|
||||
"angular-i18n": "1.7.5",
|
||||
"angular-local-storage": "0.7.1",
|
||||
"angular-messages": "1.7.5",
|
||||
"angular-mocks": "1.7.5",
|
||||
"angular-route": "1.7.5",
|
||||
"angular-sanitize": "1.7.5",
|
||||
"angular-touch": "1.7.5",
|
||||
"angular-ui-sortable": "0.19.0",
|
||||
"animejs": "2.2.0",
|
||||
"bootstrap-social": "5.1.1",
|
||||
"chart.js": "^2.8.0",
|
||||
"clipboard": "2.0.4",
|
||||
"diff": "3.5.0",
|
||||
"flatpickr": "4.5.2",
|
||||
"font-awesome": "4.7.0",
|
||||
"jquery": "^3.4.1",
|
||||
"jquery-ui-dist": "1.12.1",
|
||||
"jquery-ui-touch-punch": "0.2.3",
|
||||
"lazyload-js": "1.0.0",
|
||||
"moment": "2.22.2",
|
||||
"ng-file-upload": "12.2.13",
|
||||
"nouislider": "14.0.2",
|
||||
"npm": "6.12.0",
|
||||
"signalr": "2.4.0",
|
||||
"spectrum-colorpicker": "1.8.0",
|
||||
"tinymce": "4.9.2",
|
||||
"typeahead.js": "0.11.1",
|
||||
"underscore": "1.9.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "7.6.4",
|
||||
"@babel/preset-env": "7.6.3",
|
||||
"autoprefixer": "9.6.5",
|
||||
"caniuse-lite": "^1.0.30001002",
|
||||
"cssnano": "4.1.10",
|
||||
"fs": "0.0.2",
|
||||
"gulp": "4.0.2",
|
||||
"gulp-angular-embed-templates": "^2.3.0",
|
||||
"gulp-babel": "8.0.0",
|
||||
"gulp-clean-css": "4.2.0",
|
||||
"gulp-cli": "^2.2.0",
|
||||
"gulp-concat": "2.6.1",
|
||||
"gulp-eslint": "6.0.0",
|
||||
"gulp-imagemin": "6.1.1",
|
||||
"gulp-less": "4.0.1",
|
||||
"gulp-notify": "^3.0.0",
|
||||
"gulp-postcss": "8.0.0",
|
||||
"gulp-rename": "1.4.0",
|
||||
"gulp-sort": "2.0.0",
|
||||
"gulp-watch": "5.0.1",
|
||||
"gulp-wrap": "0.15.0",
|
||||
"gulp-wrap-js": "0.4.1",
|
||||
"jasmine-core": "3.5.0",
|
||||
"karma": "4.4.1",
|
||||
"karma-jasmine": "2.0.1",
|
||||
"karma-junit-reporter": "2.0.1",
|
||||
"karma-phantomjs-launcher": "1.0.4",
|
||||
"karma-spec-reporter": "0.0.32",
|
||||
"less": "3.10.3",
|
||||
"lodash": "4.17.15",
|
||||
"marked": "^0.7.0",
|
||||
"merge-stream": "2.0.0",
|
||||
"run-sequence": "2.2.1"
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 3.4 KiB |
+1
-2
@@ -271,8 +271,7 @@
|
||||
function createButtons(content) {
|
||||
|
||||
// for trashed and element type items, the save button is the primary action - otherwise it's a secondary action
|
||||
$scope.page.saveButtonStyle = content.trashed || content.isElement ? "primary" : "info";
|
||||
|
||||
$scope.page.saveButtonStyle = content.trashed || content.isElement || content.isBlueprint ? "primary" : "info";
|
||||
// only create the save/publish/preview buttons if the
|
||||
// content app is "Conent"
|
||||
if ($scope.app && $scope.app.alias !== "umbContent" && $scope.app.alias !== "umbInfo" && $scope.app.alias !== "umbListView") {
|
||||
|
||||
+92
-6
@@ -195,23 +195,57 @@ Use this directive to construct a header inside the main editor window.
|
||||
@param {string=} icon Show and edit the content icon. Opens an overlay to change the icon.
|
||||
@param {boolean=} hideIcon Set to <code>true</code> to hide icon.
|
||||
@param {string=} alias show and edit the content alias.
|
||||
@param {boolean=} aliasLocked Set to <code>true</code> to lock the alias.
|
||||
@param {boolean=} hideAlias Set to <code>true</code> to hide alias.
|
||||
@param {string=} description Add a description to the content.
|
||||
@param {boolean=} hideDescription Set to <code>true</code> to hide description.
|
||||
|
||||
@param {boolean=} setpagetitle If true the page title will be set to reflect the type of data the header is working with
|
||||
@param {string=} editorfor The localization to use to aid accessibility on the edit and create screen
|
||||
**/
|
||||
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function EditorHeaderDirective(editorService) {
|
||||
function EditorHeaderDirective(editorService, localizationService, editorState) {
|
||||
|
||||
function link(scope, $injector) {
|
||||
|
||||
function link(scope) {
|
||||
scope.vm = {};
|
||||
scope.vm.dropdownOpen = false;
|
||||
scope.vm.currentVariant = "";
|
||||
scope.loading = true;
|
||||
scope.accessibility = {};
|
||||
scope.accessibility.a11yMessage = "";
|
||||
scope.accessibility.a11yName = "";
|
||||
scope.accessibility.a11yMessageVisible = false;
|
||||
scope.accessibility.a11yNameVisible = false;
|
||||
|
||||
// need to call localizationService service outside of routine to set a11y due to promise requirements
|
||||
if (editorState.current) {
|
||||
//to do make work for user create/edit
|
||||
// to do make it work for user group create/ edit
|
||||
// to make it work for language edit/create
|
||||
scope.isNew = editorState.current.id === 0 ||
|
||||
editorState.current.id === "0" ||
|
||||
editorState.current.id === -1 ||
|
||||
editorState.current.id === 0 ||
|
||||
editorState.current.id === "-1";
|
||||
|
||||
var localizeVars = [
|
||||
scope.isNew ? "placeholders_a11yCreateItem" : "placeholders_a11yEdit",
|
||||
"placeholders_a11yName",
|
||||
scope.isNew ? "general_new" : "general_edit"
|
||||
];
|
||||
|
||||
if (scope.editorfor) {
|
||||
localizeVars.push(scope.editorfor);
|
||||
}
|
||||
localizationService.localizeMany(localizeVars).then(function(data) {
|
||||
setAccessibilityForEditor(data);
|
||||
scope.loading = false;
|
||||
});
|
||||
} else {
|
||||
scope.loading = false;
|
||||
}
|
||||
scope.goBack = function () {
|
||||
if (scope.onBack) {
|
||||
scope.onBack();
|
||||
@@ -247,6 +281,57 @@ Use this directive to construct a header inside the main editor window.
|
||||
editorService.iconPicker(iconPicker);
|
||||
};
|
||||
|
||||
function setAccessibilityForEditor(data) {
|
||||
|
||||
if (editorState.current) {
|
||||
if (scope.nameLocked) {
|
||||
scope.accessibility.a11yName = scope.name;
|
||||
SetPageTitle(scope.name);
|
||||
} else {
|
||||
|
||||
scope.accessibility.a11yMessage = data[0];
|
||||
scope.accessibility.a11yName = data[1];
|
||||
var title = data[2] + ":";
|
||||
if (!scope.isNew) {
|
||||
scope.accessibility.a11yMessage += " " + scope.name;
|
||||
title += " " + scope.name;
|
||||
} else {
|
||||
var name = "";
|
||||
if (editorState.current.contentTypeName) {
|
||||
name = editorState.current.contentTypeName;
|
||||
} else if (scope.editorfor) {
|
||||
name = data[3];
|
||||
}
|
||||
if (name !== "") {
|
||||
scope.accessibility.a11yMessage += " " + name;
|
||||
scope.accessibility.a11yName = name + " " + scope.accessibility.a11yName;
|
||||
title += " " + name;
|
||||
}
|
||||
}
|
||||
if (title !== data[2] + ":") {
|
||||
SetPageTitle(title);
|
||||
}
|
||||
|
||||
}
|
||||
scope.accessibility.a11yMessageVisible = !isEmptyOrSpaces(scope.accessibility.a11yMessage);
|
||||
scope.accessibility.a11yNameVisible = !isEmptyOrSpaces(scope.accessibility.a11yName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function isEmptyOrSpaces(str) {
|
||||
return str === null || str===undefined || str.trim ==='';
|
||||
}
|
||||
|
||||
function SetPageTitle(title) {
|
||||
var setTitle = false;
|
||||
if (scope.setpagetitle !== undefined) {
|
||||
setTitle = scope.setpagetitle;
|
||||
}
|
||||
if (setTitle) {
|
||||
scope.$emit("$changeTitle", title);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var directive = {
|
||||
@@ -262,7 +347,6 @@ Use this directive to construct a header inside the main editor window.
|
||||
icon: "=",
|
||||
hideIcon: "@",
|
||||
alias: "=",
|
||||
aliasLocked: "<",
|
||||
hideAlias: "=",
|
||||
description: "=",
|
||||
hideDescription: "@",
|
||||
@@ -271,7 +355,9 @@ Use this directive to construct a header inside the main editor window.
|
||||
onSelectNavigationItem: "&?",
|
||||
key: "=",
|
||||
onBack: "&?",
|
||||
showBackButton: "<?"
|
||||
showBackButton: "<?",
|
||||
editorfor: "=",
|
||||
setpagetitle:"="
|
||||
},
|
||||
link: link
|
||||
};
|
||||
|
||||
+3
-1
@@ -31,6 +31,7 @@
|
||||
@param {boolean} disabled Set the checkbox to be disabled.
|
||||
@param {boolean} required Set the checkbox to be required.
|
||||
@param {callback} onChange Callback when the value of the checkbox change by interaction.
|
||||
@param {string} cssClass Set a css class modifier
|
||||
|
||||
**/
|
||||
|
||||
@@ -78,7 +79,8 @@
|
||||
serverValidationField: "@",
|
||||
disabled: "<",
|
||||
required: "<",
|
||||
onChange: "&?"
|
||||
onChange: "&?",
|
||||
cssClass: "@?"
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
+15
-1
@@ -26,6 +26,7 @@
|
||||
@param {string} value Set the value of the radiobutton.
|
||||
@param {string} name Set the name of the radiobutton.
|
||||
@param {string} text Set the text for the radiobutton label.
|
||||
@param {string} labelKey Set a dictinary/localization string for the checkbox label
|
||||
@param {boolean} disabled Set the radiobutton to be disabled.
|
||||
@param {boolean} required Set the radiobutton to be required.
|
||||
@param {callback} onChange Callback when the value of the radiobutton change by interaction.
|
||||
@@ -39,15 +40,27 @@
|
||||
|
||||
var vm = this;
|
||||
|
||||
vm.$onInit = onInit;
|
||||
vm.change = change;
|
||||
|
||||
function onInit() {
|
||||
// If a labelKey is passed let's update the returned text if it's does not contain an opening square bracket [
|
||||
if (vm.labelKey) {
|
||||
localizationService.localize(vm.labelKey).then(function (data) {
|
||||
if(data.indexOf('[') === -1){
|
||||
vm.text = data;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function change() {
|
||||
if (vm.onChange) {
|
||||
$timeout(function () {
|
||||
vm.onChange({ model: vm.model, value: vm.value });
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var component = {
|
||||
@@ -60,6 +73,7 @@
|
||||
value: "@",
|
||||
name: "@",
|
||||
text: "@",
|
||||
labelKey: "@?",
|
||||
disabled: "<",
|
||||
required: "<",
|
||||
onChange: "&?"
|
||||
|
||||
-1
@@ -1,5 +1,4 @@
|
||||
/**
|
||||
@ngdoc directive
|
||||
@name umbraco.directives.directive:umbOverlay*
|
||||
@deprecated
|
||||
@restrict E
|
||||
|
||||
+16
@@ -16,6 +16,9 @@ angular.module("umbraco.directives")
|
||||
replace: true,
|
||||
templateUrl: 'views/components/property/umb-property.html',
|
||||
link: function (scope) {
|
||||
|
||||
scope.propertyEditorAPI = {};
|
||||
|
||||
userService.getCurrentUser().then(function (u) {
|
||||
var isAdmin = u.userGroups.indexOf('admin') !== -1;
|
||||
scope.propertyAlias = (Umbraco.Sys.ServerVariables.isDebuggingEnabled === true || isAdmin) ? scope.property.alias : null;
|
||||
@@ -32,6 +35,19 @@ angular.module("umbraco.directives")
|
||||
self.setPropertyError = function (errorMsg) {
|
||||
$scope.property.propertyErrorMessage = errorMsg;
|
||||
};
|
||||
|
||||
var unsubscribe = $scope.$on("ExposePropertyEditorAPI", function(event, api) {
|
||||
|
||||
//avoid eventual parent properties to capture this.
|
||||
event.stopPropagation();
|
||||
|
||||
$scope.propertyEditorAPI = api;
|
||||
});
|
||||
|
||||
$scope.$on("$destroy", function () {
|
||||
unsubscribe();
|
||||
});
|
||||
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
+5
-4
@@ -18,6 +18,7 @@
|
||||
config: "<",
|
||||
validation: "<",
|
||||
culture: "<?",
|
||||
inputId: "@?",
|
||||
onValueChanged: "&"
|
||||
}
|
||||
});
|
||||
@@ -43,13 +44,13 @@
|
||||
vm.hidePrompt = hidePrompt;
|
||||
vm.onKeyUpOnTag = onKeyUpOnTag;
|
||||
|
||||
vm.htmlId = "t" + String.CreateGuid();
|
||||
vm.isLoading = true;
|
||||
vm.tagToAdd = "";
|
||||
vm.promptIsVisible = "-1";
|
||||
vm.viewModel = [];
|
||||
|
||||
function onInit() {
|
||||
vm.inputId = vm.inputId || "t" + String.CreateGuid();
|
||||
|
||||
assetsService.loadJs("lib/typeahead.js/typeahead.bundle.min.js").then(function () {
|
||||
|
||||
@@ -106,7 +107,7 @@
|
||||
minLength: 1
|
||||
};
|
||||
|
||||
typeahead = $element.find('.tags-' + vm.htmlId).typeahead(opts, sources)
|
||||
typeahead = $element.find('.tags-' + vm.inputId).typeahead(opts, sources)
|
||||
.bind("typeahead:selected", function (obj, datum, name) {
|
||||
angularHelper.safeApply($rootScope, function () {
|
||||
addTagInternal(datum["text"]);
|
||||
@@ -153,7 +154,7 @@
|
||||
tagsHound.clearRemoteCache();
|
||||
tagsHound = null;
|
||||
}
|
||||
$element.find('.tags-' + vm.htmlId).typeahead('destroy');
|
||||
$element.find('.tags-' + vm.inputId).typeahead('destroy');
|
||||
}
|
||||
|
||||
function configureViewModel(isInitLoad) {
|
||||
@@ -228,7 +229,7 @@
|
||||
function addTagOnEnter(e) {
|
||||
var code = e.keyCode || e.which;
|
||||
if (code == 13) { //Enter keycode
|
||||
if ($element.find('.tags-' + vm.htmlId).parent().find(".tt-menu .tt-cursor").length === 0) {
|
||||
if ($element.find('.tags-' + vm.inputId).parent().find(".tt-menu .tt-cursor").length === 0) {
|
||||
//this is required, otherwise the html form will attempt to submit.
|
||||
e.preventDefault();
|
||||
addTag();
|
||||
|
||||
+3
-2
@@ -34,8 +34,9 @@ angular.module("umbraco.directives")
|
||||
},
|
||||
|
||||
link: function (scope, element, attrs, umbTreeCtrl) {
|
||||
localizationService.localize("general_search").then(function (value) {
|
||||
scope.searchAltText = value;
|
||||
localizationService.localizeMany(["general_search", "visuallyHiddenTexts_openContextMenu"]).then(function (value) {
|
||||
scope.searchAltText = value[0];
|
||||
scope.optionsText = value[1];
|
||||
});
|
||||
|
||||
// updates the node's DOM/styles
|
||||
|
||||
+12
-1
@@ -131,13 +131,24 @@ Use this directive to render a date time picker
|
||||
return console.warn('Unable to find any flatpickr installation');
|
||||
}
|
||||
|
||||
var fpInstance;
|
||||
|
||||
setUpCallbacks();
|
||||
|
||||
if (!ctrl.options.locale) {
|
||||
ctrl.options.locale = userLocale;
|
||||
}
|
||||
|
||||
var fpInstance = new fpLib(element, ctrl.options);
|
||||
// handle special keydown events
|
||||
ctrl.options.onKeyDown = function (selectedDates, dateStr, instance, event) {
|
||||
var code = event.keyCode || event.which;
|
||||
if (code === 13) {
|
||||
// close the datepicker on enter (this happens when entering time)
|
||||
fpInstance.close()
|
||||
}
|
||||
};
|
||||
|
||||
fpInstance = new fpLib(element, ctrl.options);
|
||||
|
||||
if (ctrl.onSetup) {
|
||||
ctrl.onSetup({
|
||||
|
||||
+11
-3
@@ -1,7 +1,7 @@
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function GridSelector($location, overlayService) {
|
||||
function GridSelector($location, overlayService, editorService) {
|
||||
|
||||
function link(scope, el, attr, ctrl) {
|
||||
|
||||
@@ -56,8 +56,16 @@
|
||||
};
|
||||
|
||||
scope.openTemplate = function (selectedItem) {
|
||||
var url = "/settings/templates/edit/" + selectedItem.id;
|
||||
$location.url(url);
|
||||
const editor = {
|
||||
id: selectedItem.id,
|
||||
submit: function () {
|
||||
editorService.close();
|
||||
},
|
||||
close: function () {
|
||||
editorService.close();
|
||||
}
|
||||
};
|
||||
editorService.templateEditor(editor);
|
||||
}
|
||||
|
||||
scope.setAsDefaultItem = function (selectedItem) {
|
||||
|
||||
+18
-1
@@ -419,7 +419,7 @@
|
||||
};
|
||||
|
||||
scope.canRemoveGroup = function(group){
|
||||
return _.find(group.properties, function(property) { return property.locked === true; }) == null;
|
||||
return group.inherited !== true && _.find(group.properties, function(property) { return property.locked === true; }) == null;
|
||||
}
|
||||
|
||||
scope.removeGroup = function(groupIndex) {
|
||||
@@ -475,6 +475,23 @@
|
||||
|
||||
/* ---------- PROPERTIES ---------- */
|
||||
|
||||
scope.addPropertyToActiveGroup = function () {
|
||||
var group = _.find(scope.model.groups, group => group.tabState === "active");
|
||||
if (!group && scope.model.groups.length) {
|
||||
group = scope.model.groups[0];
|
||||
}
|
||||
|
||||
if (!group || !group.name) {
|
||||
return;
|
||||
}
|
||||
|
||||
var property = _.find(group.properties, property => property.propertyState === "init");
|
||||
if (!property) {
|
||||
return;
|
||||
}
|
||||
scope.addProperty(property, group);
|
||||
}
|
||||
|
||||
scope.addProperty = function(property, group) {
|
||||
|
||||
// set property sort order
|
||||
|
||||
+125
-143
@@ -1,161 +1,143 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
(function () {
|
||||
'use strict';
|
||||
|
||||
function ListViewSettingsDirective(dataTypeResource, dataTypeHelper, listViewPrevalueHelper) {
|
||||
function ListViewSettingsDirective(dataTypeResource, dataTypeHelper, editorService, listViewPrevalueHelper) {
|
||||
|
||||
function link(scope) {
|
||||
function link(scope) {
|
||||
|
||||
scope.dataType = {};
|
||||
scope.editDataTypeSettings = false;
|
||||
scope.customListViewCreated = false;
|
||||
scope.dataType = {};
|
||||
scope.customListViewCreated = false;
|
||||
|
||||
const checkForCustomListView = () => scope.dataType.name === "List View - " + scope.modelAlias;
|
||||
|
||||
/* ---------- INIT ---------- */
|
||||
/* ---------- INIT ---------- */
|
||||
|
||||
function activate() {
|
||||
const activate = () => {
|
||||
|
||||
if(scope.enableListView) {
|
||||
if (scope.enableListView) {
|
||||
|
||||
dataTypeResource.getByName(scope.listViewName)
|
||||
.then(function(dataType) {
|
||||
dataTypeResource.getByName(scope.listViewName)
|
||||
.then(dataType => {
|
||||
|
||||
scope.dataType = dataType;
|
||||
scope.dataType = dataType;
|
||||
|
||||
listViewPrevalueHelper.setPrevalues(dataType.preValues);
|
||||
scope.customListViewCreated = checkForCustomListView();
|
||||
});
|
||||
|
||||
} else {
|
||||
scope.dataType = {};
|
||||
}
|
||||
}
|
||||
|
||||
/* ----------- LIST VIEW SETTINGS --------- */
|
||||
const showSettingsOverlay = () => {
|
||||
const overlay = {
|
||||
view: 'views/components/umb-list-view-settings-overlay.html',
|
||||
hideDescription: true,
|
||||
hideIcon: true,
|
||||
size: 'medium',
|
||||
dataType: scope.dataType,
|
||||
title: 'List view settings',
|
||||
submit: model => {
|
||||
const preValues = dataTypeHelper.createPreValueProps(model.dataType.preValues);
|
||||
|
||||
// store data type
|
||||
dataTypeResource.save(model.dataType, preValues, false)
|
||||
.then(dataType => scope.dataType = dataType);
|
||||
|
||||
editorService.close();
|
||||
},
|
||||
close: () => editorService.close()
|
||||
};
|
||||
|
||||
editorService.open(overlay);
|
||||
};
|
||||
|
||||
|
||||
/* ---------- CUSTOM LIST VIEW ---------- */
|
||||
|
||||
scope.createCustomListViewDataType = () => {
|
||||
|
||||
scope.loading = true;
|
||||
|
||||
dataTypeResource.createCustomListView(scope.modelAlias).then(dataType => {
|
||||
|
||||
// store data type
|
||||
scope.dataType = dataType;
|
||||
|
||||
// set list view name on scope
|
||||
scope.listViewName = dataType.name;
|
||||
|
||||
// change state to custom list view
|
||||
scope.customListViewCreated = true;
|
||||
|
||||
// show settings overlay
|
||||
showSettingsOverlay();
|
||||
|
||||
scope.loading = false;
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
scope.removeCustomListDataType = () => {
|
||||
|
||||
scope.loading = true;
|
||||
|
||||
// delete custom list view data type
|
||||
dataTypeResource.deleteById(scope.dataType.id).then(dataType => {
|
||||
|
||||
// set list view name on scope
|
||||
scope.listViewName = `List View - ${scope.contentType === 'documentType' ? 'Content' : 'Media'}`;
|
||||
|
||||
// get default data type
|
||||
dataTypeResource.getByName(scope.listViewName)
|
||||
.then(defaultDataType => {
|
||||
|
||||
// store data type
|
||||
scope.dataType = defaultDataType;
|
||||
|
||||
// change state to default list view
|
||||
scope.customListViewCreated = false;
|
||||
|
||||
scope.loading = false;
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
scope.toggle = () => scope.enableListView = !scope.enableListView;
|
||||
scope.showSettingsOverlay = () => showSettingsOverlay();
|
||||
|
||||
|
||||
/* ----------- SCOPE WATCHERS ----------- */
|
||||
const unbindEnableListViewWatcher = scope.$watch('enableListView', newValue => {
|
||||
|
||||
if (newValue !== undefined) {
|
||||
activate();
|
||||
}
|
||||
|
||||
listViewPrevalueHelper.setPrevalues(dataType.preValues);
|
||||
scope.customListViewCreated = checkForCustomListView();
|
||||
});
|
||||
|
||||
} else {
|
||||
|
||||
scope.dataType = {};
|
||||
|
||||
// clean up
|
||||
scope.$on('$destroy', () => unbindEnableListViewWatcher());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* ----------- LIST VIEW SETTINGS --------- */
|
||||
|
||||
scope.toggleEditListViewDataTypeSettings = function() {
|
||||
scope.editDataTypeSettings = !scope.editDataTypeSettings;
|
||||
};
|
||||
|
||||
scope.saveListViewDataType = function() {
|
||||
|
||||
var preValues = dataTypeHelper.createPreValueProps(scope.dataType.preValues);
|
||||
|
||||
dataTypeResource.save(scope.dataType, preValues, false).then(function(dataType) {
|
||||
|
||||
// store data type
|
||||
scope.dataType = dataType;
|
||||
|
||||
// hide settings panel
|
||||
scope.editDataTypeSettings = false;
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
|
||||
/* ---------- CUSTOM LIST VIEW ---------- */
|
||||
|
||||
scope.createCustomListViewDataType = function() {
|
||||
|
||||
dataTypeResource.createCustomListView(scope.modelAlias).then(function(dataType) {
|
||||
|
||||
// store data type
|
||||
scope.dataType = dataType;
|
||||
|
||||
// set list view name on scope
|
||||
scope.listViewName = dataType.name;
|
||||
|
||||
// change state to custom list view
|
||||
scope.customListViewCreated = true;
|
||||
|
||||
// show settings panel
|
||||
scope.editDataTypeSettings = true;
|
||||
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
scope.removeCustomListDataType = function() {
|
||||
|
||||
scope.editDataTypeSettings = false;
|
||||
|
||||
// delete custom list view data type
|
||||
dataTypeResource.deleteById(scope.dataType.id).then(function(dataType) {
|
||||
|
||||
// set list view name on scope
|
||||
if(scope.contentType === "documentType") {
|
||||
|
||||
scope.listViewName = "List View - Content";
|
||||
|
||||
} else if(scope.contentType === "mediaType") {
|
||||
|
||||
scope.listViewName = "List View - Media";
|
||||
|
||||
}
|
||||
|
||||
// get default data type
|
||||
dataTypeResource.getByName(scope.listViewName)
|
||||
.then(function(dataType) {
|
||||
|
||||
// store data type
|
||||
scope.dataType = dataType;
|
||||
|
||||
// change state to default list view
|
||||
scope.customListViewCreated = false;
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
scope.toggle = function(){
|
||||
if(scope.enableListView){
|
||||
scope.enableListView = false;
|
||||
return;
|
||||
}
|
||||
scope.enableListView = true;
|
||||
};
|
||||
|
||||
/* ----------- SCOPE WATCHERS ----------- */
|
||||
var unbindEnableListViewWatcher = scope.$watch('enableListView', function(newValue){
|
||||
|
||||
if(newValue !== undefined) {
|
||||
activate();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// clean up
|
||||
scope.$on('$destroy', function(){
|
||||
unbindEnableListViewWatcher();
|
||||
});
|
||||
|
||||
/* ----------- METHODS ---------- */
|
||||
|
||||
function checkForCustomListView() {
|
||||
return scope.dataType.name === "List View - " + scope.modelAlias;
|
||||
}
|
||||
var directive = {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'views/components/umb-list-view-settings.html',
|
||||
scope: {
|
||||
enableListView: "=",
|
||||
listViewName: "=",
|
||||
modelAlias: "=",
|
||||
contentType: "@"
|
||||
},
|
||||
link: link
|
||||
};
|
||||
|
||||
return directive;
|
||||
}
|
||||
|
||||
var directive = {
|
||||
restrict: 'E',
|
||||
replace: true,
|
||||
templateUrl: 'views/components/umb-list-view-settings.html',
|
||||
scope: {
|
||||
enableListView: "=",
|
||||
listViewName: "=",
|
||||
modelAlias: "=",
|
||||
contentType: "@"
|
||||
},
|
||||
link: link
|
||||
};
|
||||
|
||||
return directive;
|
||||
}
|
||||
|
||||
angular.module('umbraco.directives').directive('umbListViewSettings', ListViewSettingsDirective);
|
||||
angular.module('umbraco.directives').directive('umbListViewSettings', ListViewSettingsDirective);
|
||||
|
||||
})();
|
||||
|
||||
+1
-1
@@ -299,7 +299,7 @@
|
||||
*/
|
||||
onFilesChanged: "&",
|
||||
onInit: "&",
|
||||
required: "@"
|
||||
required: "="
|
||||
},
|
||||
transclude: true,
|
||||
controllerAs: 'vm',
|
||||
|
||||
@@ -17,9 +17,9 @@ angular.module("umbraco.directives")
|
||||
var observer = new MutationObserver(domChange);
|
||||
|
||||
// Options for the observer (which mutations to observe)
|
||||
var config = { attributes: true, childList: true, subtree: false };
|
||||
var config = { attributes: true, childList: true, subtree: true };
|
||||
|
||||
function domChange(mutationsList, observer){
|
||||
function domChange(mutationsList, observer) {
|
||||
for(var mutation of mutationsList) {
|
||||
|
||||
//DOM items have been added or removed
|
||||
@@ -43,4 +43,4 @@ angular.module("umbraco.directives")
|
||||
|
||||
}
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
@@ -389,7 +389,7 @@ function dataTypeResource($q, $http, umbDataFormatter, umbRequestHelper) {
|
||||
(umbRequestHelper.getApiUrl(
|
||||
"dataTypeApiBaseUrl",
|
||||
"PostRenameContainer",
|
||||
{ id: id, name: name })),
|
||||
{ id: id, name: encodeURIComponent(name) })),
|
||||
"Failed to rename the folder with id " + id);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -250,9 +250,10 @@ angular.module('umbraco.services')
|
||||
*
|
||||
* @param {Array} pathArray string array of paths to the files to load
|
||||
* @param {Scope} scope optional scope to pass into the loader
|
||||
* @param {string} defaultAssetType optional default asset type used to load assets with no extension
|
||||
* @returns {Promise} Promise object which resolves when all the files has loaded
|
||||
*/
|
||||
load: function (pathArray, scope) {
|
||||
load: function (pathArray, scope, defaultAssetType) {
|
||||
var promise;
|
||||
|
||||
if (!angular.isArray(pathArray)) {
|
||||
@@ -294,14 +295,29 @@ angular.module('umbraco.services')
|
||||
promise = $q.all(promises);
|
||||
|
||||
// Split into css and js asset arrays, and use LazyLoad on each array
|
||||
var cssAssets = _.filter(assets,
|
||||
function (asset) {
|
||||
return asset.path.match(/(\.css$|\.css\?)/ig);
|
||||
});
|
||||
var jsAssets = _.filter(assets,
|
||||
function (asset) {
|
||||
return asset.path.match(/(\.js$|\.js\?)/ig);
|
||||
});
|
||||
var cssAssets = [];
|
||||
var jsAssets = [];
|
||||
|
||||
for (var i = 0; i < assets.length; i++) {
|
||||
var asset = assets[i];
|
||||
if (asset.path.match(/(\.css$|\.css\?)/ig)) {
|
||||
cssAssets.push(asset);
|
||||
} else if (asset.path.match(/(\.js$|\.js\?)/ig)) {
|
||||
jsAssets.push(asset);
|
||||
} else {
|
||||
// Handle unknown assets
|
||||
switch (defaultAssetType) {
|
||||
case "css":
|
||||
cssAssets.push(asset);
|
||||
break;
|
||||
case "js":
|
||||
jsAssets.push(asset);
|
||||
break;
|
||||
default:
|
||||
throw "Found unknown asset without a valid defaultAssetType specified";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function assetLoaded(asset) {
|
||||
asset.state = "loaded";
|
||||
|
||||
@@ -1,203 +1,264 @@
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name umbraco.services.clipboardService
|
||||
*
|
||||
* @requires notificationsService
|
||||
* @requires eventsService
|
||||
*
|
||||
* @description
|
||||
* Service to handle clipboard in general across the application. Responsible for handling the data both storing and retrive.
|
||||
* The service has a set way for defining a data-set by a entryType and alias, which later will be used to retrive the posible entries for a paste scenario.
|
||||
*
|
||||
*/
|
||||
function clipboardService(notificationsService, eventsService, localStorageService) {
|
||||
|
||||
|
||||
var STORAGE_KEY = "umbClipboardService";
|
||||
|
||||
var retriveStorage = function() {
|
||||
if (localStorageService.isSupported === false) {
|
||||
return null;
|
||||
}
|
||||
var dataJSON;
|
||||
var dataString = localStorageService.get(STORAGE_KEY);
|
||||
if (dataString != null) {
|
||||
dataJSON = JSON.parse(dataString);
|
||||
}
|
||||
|
||||
if(dataJSON == null) {
|
||||
dataJSON = new Object();
|
||||
}
|
||||
|
||||
if(dataJSON.entries === undefined) {
|
||||
dataJSON.entries = [];
|
||||
}
|
||||
|
||||
return dataJSON;
|
||||
}
|
||||
|
||||
var saveStorage = function(storage) {
|
||||
var storageString = JSON.stringify(storage);
|
||||
|
||||
try {
|
||||
var storageJSON = JSON.parse(storageString);
|
||||
localStorageService.set(STORAGE_KEY, storageString);
|
||||
|
||||
eventsService.emit("clipboardService.storageUpdate");
|
||||
|
||||
return true;
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
var service = {};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.clipboardService#copy
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @param {string} type A string defining the type of data to storing, example: 'elementType', 'contentNode'
|
||||
* @param {string} alias A string defining the alias of the data to store, example: 'product'
|
||||
* @param {object} data A object containing the properties to be saved.
|
||||
*
|
||||
* @description
|
||||
* Saves a single JS-object with a type and alias to the clipboard.
|
||||
*/
|
||||
service.copy = function(type, alias, data) {
|
||||
|
||||
var storage = retriveStorage();
|
||||
|
||||
var shallowCloneData = Object.assign({}, data);// Notice only a shallow copy, since we dont need to deep copy. (that will happen when storing the data)
|
||||
delete shallowCloneData.key;
|
||||
delete shallowCloneData.$$hashKey;
|
||||
|
||||
var key = data.key || data.$$hashKey || console.error("missing unique key for this content");
|
||||
|
||||
// remove previous copies of this entry:
|
||||
storage.entries = storage.entries.filter(
|
||||
(entry) => {
|
||||
return entry.unique !== key;
|
||||
}
|
||||
);
|
||||
|
||||
var entry = {unique:key, type:type, alias:alias, data:shallowCloneData};
|
||||
storage.entries.push(entry);
|
||||
|
||||
if (saveStorage(storage) === true) {
|
||||
notificationsService.success("Clipboard", "Copied to clipboard.");
|
||||
} else {
|
||||
notificationsService.success("Clipboard", "Couldnt copy this data to clipboard.");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.supportsCopy#supported
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @description
|
||||
* Determins wether the current browser is able to performe its actions.
|
||||
*/
|
||||
service.isSupported = function() {
|
||||
return localStorageService.isSupported;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.supportsCopy#hasEntriesOfType
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @param {string} type A string defining the type of data test for.
|
||||
* @param {string} aliases A array of strings providing the alias of the data you want to test for.
|
||||
*
|
||||
* @description
|
||||
* Determines whether the current clipboard has entries that match a given type and one of the aliases.
|
||||
*/
|
||||
service.hasEntriesOfType = function(type, aliases) {
|
||||
|
||||
if(service.retriveEntriesOfType(type, aliases).length > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.supportsCopy#retriveEntriesOfType
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @param {string} type A string defining the type of data to recive.
|
||||
* @param {string} aliases A array of strings providing the alias of the data you want to recive.
|
||||
*
|
||||
* @description
|
||||
* Returns an array of entries matching the given type and one of the provided aliases.
|
||||
*/
|
||||
service.retriveEntriesOfType = function(type, aliases) {
|
||||
|
||||
var storage = retriveStorage();
|
||||
|
||||
// Find entries that are fulfilling the criteria for this nodeType and nodeTypesAliases.
|
||||
var filteretEntries = storage.entries.filter(
|
||||
(entry) => {
|
||||
return (entry.type === type && aliases.filter(alias => alias === entry.alias).length > 0);
|
||||
}
|
||||
);
|
||||
|
||||
return filteretEntries;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.supportsCopy#retriveEntriesOfType
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @param {string} type A string defining the type of data to recive.
|
||||
* @param {string} aliases A array of strings providing the alias of the data you want to recive.
|
||||
*
|
||||
* @description
|
||||
* Returns an array of data of entries matching the given type and one of the provided aliases.
|
||||
*/
|
||||
service.retriveDataOfType = function(type, aliases) {
|
||||
return service.retriveEntriesOfType(type, aliases).map((x) => x.data);
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.supportsCopy#retriveEntriesOfType
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @param {string} type A string defining the type of data to remove.
|
||||
* @param {string} aliases A array of strings providing the alias of the data you want to remove.
|
||||
*
|
||||
* @description
|
||||
* Removes entries matching the given type and one of the provided aliases.
|
||||
*/
|
||||
service.clearEntriesOfType = function(type, aliases) {
|
||||
|
||||
var storage = retriveStorage();
|
||||
|
||||
// Find entries that are NOT fulfilling the criteria for this nodeType and nodeTypesAliases.
|
||||
var filteretEntries = storage.entries.filter(
|
||||
(entry) => {
|
||||
return !(entry.type === type && aliases.filter(alias => alias === entry.alias).length > 0);
|
||||
}
|
||||
);
|
||||
|
||||
storage.entries = filteretEntries;
|
||||
|
||||
saveStorage(storage);
|
||||
};
|
||||
|
||||
|
||||
|
||||
return service;
|
||||
}
|
||||
|
||||
/**
|
||||
* @ngdoc service
|
||||
* @name umbraco.services.clipboardService
|
||||
*
|
||||
* @requires notificationsService
|
||||
* @requires eventsService
|
||||
*
|
||||
* @description
|
||||
* Service to handle clipboard in general across the application. Responsible for handling the data both storing and retrive.
|
||||
* The service has a set way for defining a data-set by a entryType and alias, which later will be used to retrive the posible entries for a paste scenario.
|
||||
*
|
||||
*/
|
||||
function clipboardService(notificationsService, eventsService, localStorageService, iconHelper) {
|
||||
|
||||
|
||||
var STORAGE_KEY = "umbClipboardService";
|
||||
|
||||
var retriveStorage = function() {
|
||||
if (localStorageService.isSupported === false) {
|
||||
return null;
|
||||
}
|
||||
var dataJSON;
|
||||
var dataString = localStorageService.get(STORAGE_KEY);
|
||||
if (dataString != null) {
|
||||
dataJSON = JSON.parse(dataString);
|
||||
}
|
||||
|
||||
if(dataJSON == null) {
|
||||
dataJSON = new Object();
|
||||
}
|
||||
|
||||
if(dataJSON.entries === undefined) {
|
||||
dataJSON.entries = [];
|
||||
}
|
||||
|
||||
return dataJSON;
|
||||
}
|
||||
|
||||
var saveStorage = function(storage) {
|
||||
var storageString = JSON.stringify(storage);
|
||||
|
||||
try {
|
||||
var storageJSON = JSON.parse(storageString);
|
||||
localStorageService.set(STORAGE_KEY, storageString);
|
||||
|
||||
eventsService.emit("clipboardService.storageUpdate");
|
||||
|
||||
return true;
|
||||
} catch(e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
var prepareEntryForStorage = function(entryData) {
|
||||
|
||||
var shallowCloneData = Object.assign({}, entryData);// Notice only a shallow copy, since we dont need to deep copy. (that will happen when storing the data)
|
||||
delete shallowCloneData.key;
|
||||
delete shallowCloneData.$$hashKey;
|
||||
|
||||
return shallowCloneData;
|
||||
}
|
||||
|
||||
var isEntryCompatible = function(entry, type, allowedAliases) {
|
||||
return entry.type === type
|
||||
&&
|
||||
(
|
||||
(entry.alias && allowedAliases.filter(allowedAlias => allowedAlias === entry.alias).length > 0)
|
||||
||
|
||||
(entry.aliases && entry.aliases.filter(entryAlias => allowedAliases.filter(allowedAlias => allowedAlias === entryAlias).length > 0).length === entry.aliases.length)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
var service = {};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.clipboardService#copy
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @param {string} type A string defining the type of data to storing, example: 'elementType', 'contentNode'
|
||||
* @param {string} alias A string defining the alias of the data to store, example: 'product'
|
||||
* @param {object} entry A object containing the properties to be saved, this could be the object of a ElementType, ContentNode, ...
|
||||
* @param {string} displayLabel (optional) A string swetting the label to display when showing paste entries.
|
||||
*
|
||||
* @description
|
||||
* Saves a single JS-object with a type and alias to the clipboard.
|
||||
*/
|
||||
service.copy = function(type, alias, data, displayLabel) {
|
||||
|
||||
var storage = retriveStorage();
|
||||
|
||||
var uniqueKey = data.key || data.$$hashKey || console.error("missing unique key for this content");
|
||||
|
||||
// remove previous copies of this entry:
|
||||
storage.entries = storage.entries.filter(
|
||||
(entry) => {
|
||||
return entry.unique !== uniqueKey;
|
||||
}
|
||||
);
|
||||
|
||||
var entry = {unique:uniqueKey, type:type, alias:alias, data:prepareEntryForStorage(data), label:displayLabel || data.name, icon:iconHelper.convertFromLegacyIcon(data.icon)};
|
||||
storage.entries.push(entry);
|
||||
|
||||
if (saveStorage(storage) === true) {
|
||||
notificationsService.success("Clipboard", "Copied to clipboard.");
|
||||
} else {
|
||||
notificationsService.error("Clipboard", "Couldnt copy this data to clipboard.");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.clipboardService#copyArray
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @param {string} type A string defining the type of data to storing, example: 'elementTypeArray', 'contentNodeArray'
|
||||
* @param {string} aliases An array of strings defining the alias of the data to store, example: ['banana', 'apple']
|
||||
* @param {object} datas An array of objects containing the properties to be saved, example: [ElementType, ElementType, ...]
|
||||
* @param {string} displayLabel A string setting the label to display when showing paste entries.
|
||||
* @param {string} displayIcon A string setting the icon to display when showing paste entries.
|
||||
* @param {string} uniqueKey A string prodiving an identifier for this entry, existing entries with this key will be removed to ensure that you only have the latest copy of this data.
|
||||
*
|
||||
* @description
|
||||
* Saves a single JS-object with a type and alias to the clipboard.
|
||||
*/
|
||||
service.copyArray = function(type, aliases, datas, displayLabel, displayIcon, uniqueKey) {
|
||||
|
||||
var storage = retriveStorage();
|
||||
|
||||
// Clean up each entry
|
||||
var copiedDatas = datas.map(data => prepareEntryForStorage(data));
|
||||
|
||||
// remove previous copies of this entry:
|
||||
storage.entries = storage.entries.filter(
|
||||
(entry) => {
|
||||
return entry.unique !== uniqueKey;
|
||||
}
|
||||
);
|
||||
|
||||
var entry = {unique:uniqueKey, type:type, aliases:aliases, data:copiedDatas, label:displayLabel, icon:displayIcon};
|
||||
|
||||
storage.entries.push(entry);
|
||||
|
||||
if (saveStorage(storage) === true) {
|
||||
notificationsService.success("Clipboard", "Copied to clipboard.");
|
||||
} else {
|
||||
notificationsService.error("Clipboard", "Couldnt copy this data to clipboard.");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.supportsCopy#supported
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @description
|
||||
* Determins wether the current browser is able to performe its actions.
|
||||
*/
|
||||
service.isSupported = function() {
|
||||
return localStorageService.isSupported;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.supportsCopy#hasEntriesOfType
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @param {string} type A string defining the type of data test for.
|
||||
* @param {string} aliases A array of strings providing the alias of the data you want to test for.
|
||||
*
|
||||
* @description
|
||||
* Determines whether the current clipboard has entries that match a given type and one of the aliases.
|
||||
*/
|
||||
service.hasEntriesOfType = function(type, aliases) {
|
||||
|
||||
if(service.retriveEntriesOfType(type, aliases).length > 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.supportsCopy#retriveEntriesOfType
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @param {string} type A string defining the type of data to recive.
|
||||
* @param {string} aliases A array of strings providing the alias of the data you want to recive.
|
||||
*
|
||||
* @description
|
||||
* Returns an array of entries matching the given type and one of the provided aliases.
|
||||
*/
|
||||
service.retriveEntriesOfType = function(type, allowedAliases) {
|
||||
|
||||
var storage = retriveStorage();
|
||||
|
||||
// Find entries that are fulfilling the criteria for this nodeType and nodeTypesAliases.
|
||||
var filteretEntries = storage.entries.filter(
|
||||
(entry) => {
|
||||
return isEntryCompatible(entry, type, allowedAliases);
|
||||
}
|
||||
);
|
||||
|
||||
return filteretEntries;
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.supportsCopy#retriveEntriesOfType
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @param {string} type A string defining the type of data to recive.
|
||||
* @param {string} aliases A array of strings providing the alias of the data you want to recive.
|
||||
*
|
||||
* @description
|
||||
* Returns an array of data of entries matching the given type and one of the provided aliases.
|
||||
*/
|
||||
service.retriveDataOfType = function(type, aliases) {
|
||||
return service.retriveEntriesOfType(type, aliases).map((x) => x.data);
|
||||
};
|
||||
|
||||
/**
|
||||
* @ngdoc method
|
||||
* @name umbraco.services.supportsCopy#retriveEntriesOfType
|
||||
* @methodOf umbraco.services.clipboardService
|
||||
*
|
||||
* @param {string} type A string defining the type of data to remove.
|
||||
* @param {string} aliases A array of strings providing the alias of the data you want to remove.
|
||||
*
|
||||
* @description
|
||||
* Removes entries matching the given type and one of the provided aliases.
|
||||
*/
|
||||
service.clearEntriesOfType = function(type, allowedAliases) {
|
||||
|
||||
var storage = retriveStorage();
|
||||
|
||||
// Find entries that are NOT fulfilling the criteria for this nodeType and nodeTypesAliases.
|
||||
var filteretEntries = storage.entries.filter(
|
||||
(entry) => {
|
||||
return !isEntryCompatible(entry, type, allowedAliases);
|
||||
}
|
||||
);
|
||||
|
||||
storage.entries = filteretEntries;
|
||||
|
||||
saveStorage(storage);
|
||||
};
|
||||
|
||||
|
||||
|
||||
return service;
|
||||
}
|
||||
|
||||
|
||||
angular.module("umbraco.services").factory("clipboardService", clipboardService);
|
||||
|
||||
|
||||
@@ -251,7 +251,7 @@ When building a custom infinite editor view you can use the same components as a
|
||||
*
|
||||
* @param {Object} editor rendering options
|
||||
* @param {String} editor.view Path to view
|
||||
* @param {String} editor.size Sets the size of the editor ("small"). If nothing is set it will use full width.
|
||||
* @param {String} editor.size Sets the size of the editor ("small" || "medium"). If nothing is set it will use full width.
|
||||
*/
|
||||
function open(editor) {
|
||||
|
||||
@@ -567,6 +567,7 @@ When building a custom infinite editor view you can use the same components as a
|
||||
* @param {Boolean} editor.multiPicker Pick one or multiple items
|
||||
* @param {Boolean} editor.onlyImages Only display files that have an image file-extension
|
||||
* @param {Boolean} editor.disableFolderSelect Disable folder selection
|
||||
* @param {Boolean} editor.disableFocalPoint Disable focal point editor for selected media
|
||||
* @param {Array} editor.updatedMediaNodes A list of ids for media items that have been updated through the media picker
|
||||
* @param {Callback} editor.submit Submits the editor
|
||||
* @param {Callback} editor.close Closes the editor
|
||||
@@ -605,10 +606,12 @@ When building a custom infinite editor view you can use the same components as a
|
||||
* @methodOf umbraco.services.editorService
|
||||
*
|
||||
* @description
|
||||
* Opens the document type editor in infinite editing, the submit callback returns the saved document type
|
||||
* Opens the document type editor in infinite editing, the submit callback returns the alias of the saved document type.
|
||||
* @param {Object} editor rendering options
|
||||
* @param {Callback} editor.submit Submits the editor
|
||||
* @param {Callback} editor.close Closes the editor
|
||||
* @param {Callback} editor.id Indicates the ID of the document type to be edited. Alternatively the ID may be set to `-1` in combination with `create` being set to `true` to open the document type editor for creating a new document type.
|
||||
* @param {Callback} editor.create Set to `true` to open the document type editor for creating a new document type.
|
||||
* @param {Callback} editor.submit Submits the editor.
|
||||
* @param {Callback} editor.close Closes the editor.
|
||||
* @returns {Object} editor object
|
||||
*/
|
||||
function documentTypeEditor(editor) {
|
||||
|
||||
@@ -225,8 +225,10 @@ function navigationService($routeParams, $location, $q, $injector, eventsService
|
||||
retainQueryStrings: function (currRouteParams, nextRouteParams) {
|
||||
var toRetain = angular.copy(nextRouteParams);
|
||||
var updated = false;
|
||||
|
||||
_.each(retainedQueryStrings, function (r) {
|
||||
if (currRouteParams[r] && !nextRouteParams[r]) {
|
||||
// if mculture is set to null in nextRouteParams, the value will be undefined and we will not retain any query string that has a value of "null"
|
||||
if (currRouteParams[r] && nextRouteParams[r] !== undefined && !nextRouteParams[r]) {
|
||||
toRetain[r] = currRouteParams[r];
|
||||
updated = true;
|
||||
}
|
||||
@@ -463,6 +465,8 @@ function navigationService($routeParams, $location, $q, $injector, eventsService
|
||||
throw "section cannot be null";
|
||||
}
|
||||
|
||||
appState.setMenuState("currentNode", node);
|
||||
|
||||
if (action.metaData && action.metaData["actionRoute"] && angular.isString(action.metaData["actionRoute"])) {
|
||||
//first check if the menu item simply navigates to a route
|
||||
var parts = action.metaData["actionRoute"].split("?");
|
||||
|
||||
@@ -65,10 +65,39 @@
|
||||
open(overlay);
|
||||
}
|
||||
|
||||
function confirm(overlay) {
|
||||
|
||||
if (!overlay.closeButtonLabelKey) overlay.closeButtonLabelKey = "general_cancel";
|
||||
if (!overlay.view) overlay.view = "views/common/overlays/confirm/confirm.html";
|
||||
if (!overlay.close) overlay.close = function () { close(); };
|
||||
|
||||
switch (overlay.confirmType) {
|
||||
|
||||
case "delete":
|
||||
if (!overlay.confirmMessageStyle) overlay.confirmMessageStyle = "danger";
|
||||
if (!overlay.submitButtonStyle) overlay.submitButtonStyle = "danger";
|
||||
if (!overlay.submitButtonLabelKey) overlay.submitButtonLabelKey = "contentTypeEditor_yesDelete";
|
||||
break;
|
||||
|
||||
default:
|
||||
if (!overlay.submitButtonLabelKey) overlay.submitButtonLabelKey = "general_confirm";
|
||||
|
||||
}
|
||||
|
||||
open(overlay);
|
||||
|
||||
}
|
||||
|
||||
function confirmDelete(overlay) {
|
||||
confirm(overlay);
|
||||
}
|
||||
|
||||
var service = {
|
||||
open: open,
|
||||
close: close,
|
||||
ysod: ysod
|
||||
ysod: ysod,
|
||||
confirm: confirm,
|
||||
confirmDelete: confirmDelete
|
||||
};
|
||||
|
||||
return service;
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
function propertyEditorService() {
|
||||
/**
|
||||
* @ngdoc function
|
||||
* @name umbraco.services.propertyEditorService#expose
|
||||
* @methodOf umbraco.services.propertyEditorService
|
||||
* @function
|
||||
*
|
||||
* @param {object} scope An object containing API for the PropertyEditor
|
||||
*/
|
||||
function exposeAPI(scope, api) {
|
||||
if (!scope) {
|
||||
throw "scope cannot be null";
|
||||
}
|
||||
if (!api) {
|
||||
throw "api cannot be null";
|
||||
}
|
||||
scope.$emit("ExposePropertyEditorAPI", api);
|
||||
}
|
||||
|
||||
return {
|
||||
exposeAPI: exposeAPI
|
||||
};
|
||||
}
|
||||
|
||||
angular.module('umbraco.services').factory('propertyEditorService', propertyEditorService);
|
||||
})();
|
||||
@@ -15,7 +15,8 @@
|
||||
'[tabindex]',
|
||||
'audio[controls]',
|
||||
'video[controls]',
|
||||
'[contenteditable]:not([contenteditable="false"])'
|
||||
'[contenteditable]:not([contenteditable="false"])',
|
||||
'iframe[data-mce-style]'
|
||||
];
|
||||
var candidateSelector = candidateSelectors.join(',');
|
||||
|
||||
|
||||
@@ -735,7 +735,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
|
||||
//get all macro divs and load their content
|
||||
$(editor.dom.select(".umb-macro-holder.mceNonEditable")).each(function () {
|
||||
self.loadMacroContent($(this), null);
|
||||
self.loadMacroContent($(this), null, editor);
|
||||
});
|
||||
|
||||
});
|
||||
@@ -850,14 +850,15 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
}
|
||||
|
||||
var $macroDiv = $(editor.dom.select("div.umb-macro-holder." + uniqueId));
|
||||
editor.setDirty(true);
|
||||
|
||||
//async load the macro content
|
||||
this.loadMacroContent($macroDiv, macroObject);
|
||||
this.loadMacroContent($macroDiv, macroObject, editor);
|
||||
|
||||
},
|
||||
|
||||
/** loads in the macro content async from the server */
|
||||
loadMacroContent: function ($macroDiv, macroData) {
|
||||
loadMacroContent: function ($macroDiv, macroData, editor) {
|
||||
|
||||
//if we don't have the macroData, then we'll need to parse it from the macro div
|
||||
if (!macroData) {
|
||||
@@ -893,7 +894,11 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
$macroDiv.removeClass("loading");
|
||||
htmlResult = htmlResult.trim();
|
||||
if (htmlResult !== "") {
|
||||
var wasDirty = editor.isDirty();
|
||||
$ins.html(htmlResult);
|
||||
if (!wasDirty) {
|
||||
editor.undoManager.clear();
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -1489,6 +1494,7 @@ function tinyMceService($rootScope, $q, imageHelper, $locale, $http, $timeout, s
|
||||
onlyImages: true,
|
||||
showDetails: true,
|
||||
disableFolderSelect: true,
|
||||
disableFocalPoint: true,
|
||||
startNodeId: startNodeId,
|
||||
startNodeIsVirtual: startNodeIsVirtual,
|
||||
dataTypeKey: args.model.dataTypeKey,
|
||||
|
||||
@@ -77,6 +77,7 @@
|
||||
@import "listview.less";
|
||||
@import "gridview.less";
|
||||
@import "footer.less";
|
||||
@import "filter-toggle.less";
|
||||
|
||||
@import "forms/umb-validation-label.less";
|
||||
|
||||
@@ -129,6 +130,7 @@
|
||||
@import "components/umb-media-grid.less";
|
||||
@import "components/umb-folder-grid.less";
|
||||
@import "components/umb-content-grid.less";
|
||||
@import "components/umb-contextmenu.less";
|
||||
@import "components/umb-layout-selector.less";
|
||||
@import "components/tooltip/umb-tooltip.less";
|
||||
@import "components/tooltip/umb-tooltip-list.less";
|
||||
@@ -137,6 +139,7 @@
|
||||
@import "components/umb-grid.less";
|
||||
@import "components/umb-empty-state.less";
|
||||
@import "components/umb-property-editor.less";
|
||||
@import "components/umb-property-actions.less";
|
||||
@import "components/umb-color-swatches.less";
|
||||
@import "components/check-circle.less";
|
||||
@import "components/umb-file-icon.less";
|
||||
@@ -187,6 +190,8 @@
|
||||
@import "components/users/umb-user-preview.less";
|
||||
@import "components/users/umb-user-picker-list.less";
|
||||
|
||||
@import "components/contextdialogs/umb-dialog-datatype-delete.less";
|
||||
|
||||
|
||||
// Utilities
|
||||
@import "utilities/layout/_display.less";
|
||||
@@ -217,6 +222,7 @@
|
||||
@import "dashboards/umbraco-forms.less";
|
||||
@import "dashboards/examine-management.less";
|
||||
@import "dashboards/healthcheck.less";
|
||||
@import "dashboards/nucache.less";
|
||||
|
||||
@import "typeahead.less";
|
||||
@import "hacks.less";
|
||||
|
||||
@@ -338,3 +338,31 @@ input[type="submit"].btn {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
// Icon buttons
|
||||
// ------------------------------
|
||||
|
||||
// 31 July 19, Nathan Woulfe says: Reset styles for cases where button shows an icon only (eg edit/remove property on document type)
|
||||
// This is lifted from umb-group-builder.less
|
||||
|
||||
.btn-icon {
|
||||
border: none;
|
||||
|
||||
font-size: 18px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
color: @ui-icon;
|
||||
|
||||
margin: 0;
|
||||
padding: 5px 10px;
|
||||
width: auto;
|
||||
overflow: visible;
|
||||
background: transparent;
|
||||
line-height: normal;
|
||||
outline: 0;
|
||||
-webkit-appearance: none;
|
||||
|
||||
&:hover, &:focus {
|
||||
color: @ui-icon-hover;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -280,7 +280,7 @@ ul.sections {
|
||||
margin:0;
|
||||
padding:0;
|
||||
margin-left: -80px;
|
||||
overflow: scroll;
|
||||
overflow: auto;
|
||||
overflow-x: hidden;
|
||||
height: calc(100% - 91px);
|
||||
|
||||
@@ -316,35 +316,40 @@ ul.sections li a {
|
||||
&:hover {
|
||||
span, i {
|
||||
opacity: 1;
|
||||
color:#fff;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ul.sections li a i {
|
||||
font-size: 30px;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
ul.sections li a span {
|
||||
display:block;
|
||||
display: block;
|
||||
font-size: 10px;
|
||||
line-height: 1.4em;
|
||||
opacity: 0.4;
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
ul.sections li.current {
|
||||
background-color: #2E2246;
|
||||
}
|
||||
|
||||
ul.sections li.current a i {
|
||||
color: #ffffff;
|
||||
}
|
||||
|
||||
ul.sections li.current, ul.sections li:hover {
|
||||
border-left: 4px #f5c1bc solid;
|
||||
}
|
||||
|
||||
.fix-left-menu:hover ul.sections li a span,
|
||||
.fix-left-menu:hover ul.sections li a i,
|
||||
ul.sections li.current a i {
|
||||
color: #f5c1bc;
|
||||
}
|
||||
|
||||
ul.sections li.current {
|
||||
border-left: 4px #f5c1bc solid;
|
||||
}
|
||||
|
||||
ul.sections li:hover a i,
|
||||
ul.sections li:hover a span {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.fix-left-menu:hover .help {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
.umb-dialog-datatype-delete {
|
||||
|
||||
|
||||
.umb-dialog-datatype-delete__table-head-column-name {
|
||||
width: 140px;
|
||||
}
|
||||
|
||||
.umb-table-body__icon {
|
||||
margin-right: 5px;
|
||||
vertical-align: top;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.table tbody td {
|
||||
vertical-align: top;
|
||||
}
|
||||
.table tbody td > span {
|
||||
margin: 5px 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.table tbody p {
|
||||
line-height: 12px;
|
||||
margin: 5px 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.table tbody .icon {
|
||||
vertical-align: top;
|
||||
margin-right: 5px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,82 +1,86 @@
|
||||
.umb-editors {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
overflow: hidden;
|
||||
.absolute();
|
||||
overflow: hidden;
|
||||
|
||||
.umb-editor {
|
||||
box-shadow: 0px 0 30px 0 rgba(0,0,0,.3);
|
||||
}
|
||||
}
|
||||
|
||||
.umb-editor {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
.absolute();
|
||||
background: @brownGrayLight;
|
||||
z-index: @zIndexEditor;
|
||||
}
|
||||
|
||||
.umb-editor--infiniteMode {
|
||||
transform: none;
|
||||
will-change: transform;
|
||||
transition: transform 400ms ease-in-out;
|
||||
&.moveRight {
|
||||
transform: translateX(110%);
|
||||
&--infiniteMode {
|
||||
transform: none;
|
||||
will-change: transform;
|
||||
transition: transform 400ms ease-in-out;
|
||||
|
||||
&.umb-editor--moveRight {
|
||||
transform: translateX(110%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.umb-editor--outOfRange {
|
||||
transform: none;
|
||||
display: none;
|
||||
will-change: auto;
|
||||
transition: display 0s 320ms;
|
||||
}
|
||||
.umb-editor--level0 {
|
||||
transform: none;
|
||||
}
|
||||
.umb-editor--level1 {
|
||||
transform: translateX(60px);
|
||||
}
|
||||
.umb-editor--level2 {
|
||||
transform: translateX(120px);
|
||||
}
|
||||
.umb-editor--level3 {
|
||||
transform: translateX(180px);
|
||||
}
|
||||
|
||||
.umb-editor--n1 {
|
||||
right:60px;
|
||||
}
|
||||
.umb-editor--n2 {
|
||||
right:120px;
|
||||
}
|
||||
.umb-editor--n3 {
|
||||
right:180px;
|
||||
}
|
||||
|
||||
// hide all infinite editors by default
|
||||
// will be shown through animation
|
||||
.umb-editors .umb-editor {
|
||||
box-shadow: 0px 0 30px 0 rgba(0,0,0,.3);
|
||||
}
|
||||
|
||||
.umb-editor--small {
|
||||
width: 500px;
|
||||
will-change: transform;
|
||||
left: auto;
|
||||
&--outOfRange {
|
||||
transform: none;
|
||||
display: none;
|
||||
will-change: auto;
|
||||
transition: display 0s 320ms;
|
||||
}
|
||||
|
||||
.umb-editor-container {
|
||||
max-width: 500px;
|
||||
&--level0 {
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
|
||||
// use a loop to build the editor levels
|
||||
@iterations: 3;
|
||||
@step: 60px;
|
||||
|
||||
.level-loop (@i) when (@i > 0) {
|
||||
@x: @i * @step;
|
||||
.umb-editor--level@{i} {
|
||||
transform: translateX(@x);
|
||||
}
|
||||
|
||||
.umb-editor--n@{i} {
|
||||
right:@x;
|
||||
}
|
||||
|
||||
.level-loop(@i - 1);
|
||||
}
|
||||
|
||||
.level-loop(@iterations);
|
||||
|
||||
// and also use a loop to build editor sizes - easily extended with new sizes by adding to the map
|
||||
@editorSizes:
|
||||
small 500px,
|
||||
medium 800px;
|
||||
|
||||
.create-editor-sizes(@iterator:1) when(@iterator <= length(@editorSizes)) {
|
||||
.umb-editor {
|
||||
@size: extract(extract(@editorSizes, @iterator), 1);
|
||||
@value: extract(extract(@editorSizes, @iterator), 2);
|
||||
|
||||
&--@{size} {
|
||||
width: @value;
|
||||
will-change: transform;
|
||||
left: auto;
|
||||
|
||||
.umb-editor--container {
|
||||
max-width: @value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.create-editor-sizes(@iterator + 1);
|
||||
}
|
||||
|
||||
.create-editor-sizes();
|
||||
|
||||
.umb-editor__overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
.absolute();
|
||||
background: rgba(0,0,0,0.4);
|
||||
z-index: @zIndexEditor;
|
||||
visibility: hidden;
|
||||
@@ -85,7 +89,7 @@
|
||||
}
|
||||
|
||||
#contentcolumn > .umb-editor__overlay,
|
||||
.--notInFront .umb-editor__overlay {
|
||||
.umb-editor--notInFront .umb-editor__overlay {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
transition: opacity 320ms 20ms, visibility 0s;
|
||||
|
||||
@@ -39,3 +39,8 @@
|
||||
padding-top: 20px;
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
|
||||
|
||||
.emptySection .umb-notifications{
|
||||
left:0;
|
||||
}
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
}
|
||||
|
||||
.umb-overlay .umb-overlay-header {
|
||||
border-bottom: 1px solid @purple-l3;
|
||||
border-bottom: 1px solid @gray-9;
|
||||
margin-top: 0;
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
padding: 20px 30px 0;
|
||||
padding: 20px 20px 0;
|
||||
}
|
||||
|
||||
.umb-overlay__section-header {
|
||||
@@ -48,11 +48,11 @@
|
||||
}
|
||||
|
||||
.umb-overlay__title {
|
||||
font-size: @fontSizeLarge;
|
||||
font-size: 16px;
|
||||
color: @black;
|
||||
line-height: 20px;
|
||||
line-height: 16px;
|
||||
font-weight: bold;
|
||||
margin: 7px 0;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.umb-overlay__subtitle {
|
||||
@@ -66,8 +66,8 @@
|
||||
flex-shrink: 1;
|
||||
flex-basis: auto;
|
||||
position: relative;
|
||||
padding: 0 30px;
|
||||
margin-bottom: 10px;
|
||||
padding: 20px;
|
||||
background: @white;
|
||||
max-height: calc(100vh - 170px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
@@ -75,11 +75,11 @@
|
||||
.umb-overlay-drawer {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
flex-basis: 31px;
|
||||
padding: 10px 20px;
|
||||
flex-basis: 33px;
|
||||
padding: 8px 20px;
|
||||
margin: 0;
|
||||
background: @gray-10;
|
||||
border-top: 1px solid @purple-l3;
|
||||
background: @white;
|
||||
border-top: 1px solid @gray-9;
|
||||
}
|
||||
|
||||
.umb-overlay-drawer.-auto-height {
|
||||
@@ -117,7 +117,7 @@
|
||||
.umb-overlay.umb-overlay-center .umb-overlay-drawer {
|
||||
border: none;
|
||||
background: transparent;
|
||||
padding: 0 30px 20px;
|
||||
padding: 0 20px 20px;
|
||||
}
|
||||
|
||||
/* ---------- OVERLAY TARGET ---------- */
|
||||
@@ -140,7 +140,6 @@
|
||||
.umb-overlay.umb-overlay-target .umb-overlay-drawer {
|
||||
border: none;
|
||||
background: transparent;
|
||||
padding: 0 30px 20px;
|
||||
}
|
||||
|
||||
/* ---------- OVERLAY RIGHT ---------- */
|
||||
@@ -158,7 +157,7 @@
|
||||
}
|
||||
|
||||
.umb-overlay.umb-overlay-right .umb-overlay-header {
|
||||
flex-basis: 100px;
|
||||
flex-basis: 70px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,14 @@
|
||||
|
||||
.umb-breadcrumbs__ancestor {
|
||||
display: flex;
|
||||
min-height: 25px;
|
||||
}
|
||||
|
||||
.umb-breadcrumbs__action {
|
||||
background: transparent;
|
||||
border: 0 none;
|
||||
padding: 0;
|
||||
margin-top: -4px;
|
||||
}
|
||||
|
||||
.umb-breadcrumbs__ancestor-link,
|
||||
@@ -38,7 +46,6 @@
|
||||
|
||||
input.umb-breadcrumbs__add-ancestor {
|
||||
height: 25px;
|
||||
margin-top: -2px;
|
||||
margin-left: 3px;
|
||||
margin: 0 0 0 3px;
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
.umb-contextmenu {
|
||||
margin: 0;
|
||||
list-style: none;
|
||||
user-select: none;
|
||||
|
||||
overflow: hidden;
|
||||
border-radius: 3px;
|
||||
border: 1px solid @dropdownBorder;
|
||||
.box-shadow(0 5px 20px rgba(0,0,0,.3));
|
||||
border-bottom: 1px solid rgba(0,0,0,.2);
|
||||
|
||||
.sep {
|
||||
display: block;
|
||||
border-top: 1px solid @gray-9;
|
||||
|
||||
&:first-child {
|
||||
border-top: none;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.umb-contextmenu-item {
|
||||
|
||||
.icon {
|
||||
font-size: 18px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.menu-label {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
button {
|
||||
|
||||
position: relative;
|
||||
|
||||
display: block;
|
||||
font-weight: normal;
|
||||
line-height: @baseLineHeight;
|
||||
white-space: nowrap;
|
||||
|
||||
background-color: @ui-option;
|
||||
border: 0;
|
||||
padding: 7px 12px;
|
||||
color: @ui-option-type;
|
||||
width: 100%;
|
||||
|
||||
font-size: 14px;
|
||||
text-align: left;
|
||||
|
||||
&:hover {
|
||||
text-decoration: none;
|
||||
color: @ui-option-type-hover;
|
||||
background-color: @ui-option-hover;
|
||||
}
|
||||
}
|
||||
|
||||
&.-opens-dialog {
|
||||
.menu-label:after {
|
||||
// adds an ellipsis (...) after the menu label for actions that open a dialog
|
||||
content: '\2026';
|
||||
}
|
||||
}
|
||||
button:disabled {
|
||||
cursor: not-allowed;
|
||||
color: @ui-option-disabled-type;
|
||||
&:hover {
|
||||
color: @ui-option-disabled-type-hover;
|
||||
background-color: @ui-option;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,10 +12,18 @@
|
||||
line-height: 22px;
|
||||
cursor: pointer !important;
|
||||
|
||||
&.-small-text{
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
&.-bold{
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
&__text {
|
||||
margin: 0 0 0 26px;
|
||||
position: relative;
|
||||
top: 0;
|
||||
top: 1px;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
@@ -24,7 +32,7 @@
|
||||
top: 0;
|
||||
left: 0;
|
||||
opacity: 0;
|
||||
|
||||
|
||||
&:hover ~ .umb-form-check__state .umb-form-check__check {
|
||||
border-color: @inputBorderFocus;
|
||||
}
|
||||
@@ -36,7 +44,7 @@
|
||||
background: @ui-option-type-hover;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&:checked ~ .umb-form-check__state {
|
||||
.umb-form-check__check {
|
||||
// This only happens if the state has a radiobutton modifier
|
||||
@@ -62,8 +70,7 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
.tabbing-active &.umb-form-check--radiobutton &__input:focus ~ .umb-form-check__state .umb-form-check__check {
|
||||
//outline: 2px solid @inputBorderTabFocus;
|
||||
border: 2px solid @inputBorderTabFocus;
|
||||
@@ -76,6 +83,11 @@
|
||||
border-color: white;
|
||||
}
|
||||
|
||||
// add spacing between when flexed/inline, equal to the width of the input
|
||||
.flex & + & {
|
||||
margin-left:@checkboxWidth;
|
||||
}
|
||||
|
||||
&__state {
|
||||
display: flex;
|
||||
height: 18px;
|
||||
|
||||
@@ -367,7 +367,6 @@ input.umb-group-builder__group-title-input:disabled:hover {
|
||||
overflow: visible;
|
||||
background: transparent;
|
||||
line-height: normal;
|
||||
outline: 0;
|
||||
-webkit-appearance: none;
|
||||
|
||||
&:hover, &:focus {
|
||||
|
||||
@@ -1,54 +1,76 @@
|
||||
.umb-list-view-settings__box {
|
||||
background: @gray-10;
|
||||
border: 1px solid @gray-7;
|
||||
display: flex;
|
||||
animation: fadeIn 0.5s;
|
||||
padding: 15px;
|
||||
position: relative;
|
||||
background: @gray-10;
|
||||
display: flex;
|
||||
flex: 1;
|
||||
padding: 15px;
|
||||
position: relative;
|
||||
border-radius: @baseBorderRadius;
|
||||
|
||||
.btn-link {
|
||||
font-size: 13px;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-list-view-settings__trigger {
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.umb-list-view-settings__box.-open {
|
||||
border-bottom: transparent;
|
||||
}
|
||||
|
||||
.umb-list-view-settings__content {
|
||||
display: flex;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.umb-list-view-settings__list-view-icon {
|
||||
font-size: 20px;
|
||||
color: @gray-7;
|
||||
margin-right: 10px;
|
||||
font-size: 20px;
|
||||
color: @gray-7;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.umb-list-view-settings__name {
|
||||
margin-right: 5px;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
float: left;
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.umb-list-view-settings__create-new {
|
||||
font-size: 13px;
|
||||
color: @ui-action-type;
|
||||
}
|
||||
|
||||
.umb-list-view-settings__create-new:hover {
|
||||
color: @ui-action-type-hover;
|
||||
border-color: @ui-action-type-hover;
|
||||
color: @ui-action-type;
|
||||
}
|
||||
|
||||
.umb-list-view-settings__remove-new {
|
||||
font-size: 13px;
|
||||
color: @red;
|
||||
color: @red;
|
||||
}
|
||||
|
||||
.umb-list-view-settings__settings {
|
||||
border: 1px dashed @gray-7;
|
||||
border-top: none;
|
||||
padding: 20px;
|
||||
// display `columns displayed` table as a list-view layout
|
||||
.umb-list-view-settings__overlay {
|
||||
|
||||
.btn {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.btn-icon {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
tbody tr {
|
||||
background: @gray-10;
|
||||
border-bottom: 1px solid #fff;
|
||||
}
|
||||
|
||||
th {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
td {
|
||||
padding: 10px 15px 10px 0;
|
||||
|
||||
&:first-child {
|
||||
padding-left: 15px;
|
||||
}
|
||||
|
||||
.ui-sortable-handle {
|
||||
min-height: 37px;
|
||||
display: flex;
|
||||
width:0;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
/* PACKAGE DETAILS */
|
||||
|
||||
.umb-logviewer {
|
||||
display: flex;
|
||||
flex-flow: row wrap;
|
||||
@@ -41,7 +39,7 @@
|
||||
flex: 1 1 auto;
|
||||
width: 100%;
|
||||
margin-bottom: 30px;
|
||||
margin-right: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.umb-logviewer__sidebar {
|
||||
@@ -49,3 +47,99 @@
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-logviewer-search {
|
||||
.filter-name {
|
||||
margin-left: 5px;
|
||||
margin-right: 3px;
|
||||
max-width: 150px;
|
||||
}
|
||||
|
||||
.dropdown-item {
|
||||
padding: 8px 20px 8px 16px;
|
||||
}
|
||||
|
||||
.filter {
|
||||
position: relative;
|
||||
|
||||
a.btn-link {
|
||||
padding-left: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
.search-box {
|
||||
width: 100%;
|
||||
|
||||
.flex-auto {
|
||||
position: relative;
|
||||
|
||||
.search-input {
|
||||
width: 100%;
|
||||
padding-right: 160px;
|
||||
}
|
||||
|
||||
.icon-rate {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
line-height: 32px;
|
||||
right: 140px;
|
||||
color: #fdb45c;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.icon-wrong {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
line-height: 32px;
|
||||
right: 120px;
|
||||
color: #bbbabf;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.umb-variant-switcher__toggle {
|
||||
top: 1px;
|
||||
right: 0;
|
||||
position: absolute;
|
||||
|
||||
.icon-navigation-down {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.saved-searches {
|
||||
width: 100%;
|
||||
max-height: 250px;
|
||||
overflow-y: scroll;
|
||||
margin-top: -10px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.log-items {
|
||||
.table {
|
||||
table-layout: fixed;
|
||||
|
||||
thead th:first-child, thead th:nth-child(3) {
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
thead th:nth-child(2) {
|
||||
width: 15%;
|
||||
}
|
||||
|
||||
tr td:nth-child(3) {
|
||||
word-break: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
.exception {
|
||||
border-left: 4px solid #D42054;
|
||||
padding: 0 10px 10px 10px;
|
||||
box-shadow: rgba(0,0,0,0.07) 2px 2px 10px;
|
||||
|
||||
.exception-message {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
.umb-nested-content {
|
||||
text-align: center;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@@ -170,6 +169,7 @@
|
||||
|
||||
.umb-nested-content__add-content {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border: 1px dashed @ui-action-discreet-border;
|
||||
@@ -234,8 +234,46 @@
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.form-horizontal .umb-nested-content--narrow .controls-row
|
||||
{
|
||||
.umb-nested-content__placeholder {
|
||||
height: 22px;
|
||||
padding: 4px 6px;
|
||||
border: 1px dashed #d8d7d9;
|
||||
background: 0 0;
|
||||
cursor: pointer;
|
||||
color: #1b264f;
|
||||
-webkit-animation: fadeIn .5s;
|
||||
animation: fadeIn .5s;
|
||||
text-align: center;
|
||||
|
||||
&--selected {
|
||||
border: 1px solid #d8d7d9;
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-nested-content__placeholder-name{
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.umb-nested-content__placeholder:hover {
|
||||
color: #2152a3;
|
||||
border-color: #2152a3;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.umb-nested-content__placeholder-icon-holder {
|
||||
width: 20px;
|
||||
text-align: center;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.umb-nested-content__placeholder-icon {
|
||||
font-size: 18px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
|
||||
.form-horizontal .umb-nested-content--narrow .controls-row {
|
||||
margin-left: 40% !important;
|
||||
}
|
||||
|
||||
|
||||
@@ -107,5 +107,5 @@
|
||||
.umb-panel-group__details-status-action-description {
|
||||
margin-top: 5px;
|
||||
font-size: 12px;
|
||||
padding-left: 165px;
|
||||
padding-left:165px;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
.umb-property-actions {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.umb-property-actions__toggle,
|
||||
.umb-property-actions__menu-open-toggle {
|
||||
position: relative;
|
||||
display: flex;
|
||||
flex: 0 0 auto;
|
||||
padding: 6px 6px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
border-radius: 3px;
|
||||
|
||||
background-color: @ui-action-hover;
|
||||
|
||||
i {
|
||||
height: 3px !important;
|
||||
width: 3px !important;
|
||||
border-radius: 3px;
|
||||
background: @ui-action-type;
|
||||
display: inline-block;
|
||||
margin: 0 2px 0 0;
|
||||
|
||||
&:last-child {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
&:hover {
|
||||
i {
|
||||
background: @ui-action-type-hover;
|
||||
}
|
||||
}
|
||||
}
|
||||
.umb-property-actions__menu-open-toggle {
|
||||
position: absolute;
|
||||
z-index:1;
|
||||
outline: none;// this is not acceccible by keyboard, since we use the .umb-property-actions__toggle for that.
|
||||
|
||||
top: -15px;
|
||||
border-radius: 3px 3px 0 0;
|
||||
|
||||
border-top-left-radius: 3px;
|
||||
border-top-right-radius: 3px;
|
||||
|
||||
border: 1px solid @dropdownBorder;
|
||||
|
||||
border-bottom: 1px solid @gray-9;
|
||||
|
||||
.box-shadow(0 5px 20px rgba(0,0,0,.3));
|
||||
|
||||
background-color: white;
|
||||
|
||||
}
|
||||
|
||||
.umb-property .umb-property-actions {
|
||||
float: left;
|
||||
}
|
||||
.umb-property .umb-property-actions__toggle {
|
||||
margin-top: 2px;
|
||||
opacity: 0;
|
||||
transition: opacity 120ms;
|
||||
}
|
||||
.umb-property:hover .umb-property-actions__toggle,
|
||||
.umb-property .umb-property-actions__toggle:focus {
|
||||
opacity: 1;
|
||||
}
|
||||
// Revert-style-hack that ensures that we only show property-actions on properties that are directly begin hovered.
|
||||
.umb-property:hover .umb-property:not(:hover) .umb-property-actions__toggle {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.umb-property-actions__menu {
|
||||
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
|
||||
display: block;
|
||||
|
||||
float: left;
|
||||
min-width: 160px;
|
||||
list-style: none;
|
||||
|
||||
.umb-contextmenu {
|
||||
|
||||
border-top-left-radius: 0;
|
||||
margin-top:1px;
|
||||
|
||||
}
|
||||
|
||||
.umb-contextmenu-item > button {
|
||||
|
||||
z-index:2;// need to stay on top of menu-toggle-open shadow.
|
||||
|
||||
}
|
||||
}
|
||||
@@ -63,6 +63,10 @@ a.umb-user-details-details__back-link {
|
||||
|
||||
.umb-user-details-details__sidebar {
|
||||
flex: 0 0 @sidebarwidth;
|
||||
|
||||
.umb-button{
|
||||
margin-left:0px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
@@ -101,6 +105,7 @@ a.umb-user-details-details__back-link {
|
||||
.umb-user-details-details__information-item {
|
||||
margin-bottom: 10px;
|
||||
font-size: 13px;
|
||||
margin-top:10px;
|
||||
}
|
||||
|
||||
.umb-user-details-details__information-item-label {
|
||||
|
||||
@@ -12,4 +12,9 @@
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.umb-panel-group__details-status-action{
|
||||
background-color:transparent;
|
||||
padding-left:0;
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user