Compare commits

...

138 Commits

Author SHA1 Message Date
Shannon 89c376f77a adds ValueTuple reference to nuspec 2018-03-26 20:08:11 +11:00
Claus 7c264b4da0 adding using statement to preview file to prevent missing htmlhelper error. 2018-03-23 11:57:29 +01:00
Sebastiaan Janssen 81d380a47e Merge branch 'dev-v7' into master-v7 2018-03-22 14:55:52 +01:00
Sebastiaan Janssen 19e5715a84 Whoops, that was not supposed to say beta 2018-03-22 14:55:02 +01:00
Sebastiaan Janssen 2e2dce170a Merge branch 'dev-v7.10' into master-v7 2018-03-22 11:28:48 +01:00
Sebastiaan Janssen 59f9a64e81 Merge branch 'dev-v7' into dev-v7.10
# Conflicts:
#	src/SolutionInfo.cs
#	src/Umbraco.Core/Configuration/UmbracoVersion.cs
2018-03-22 11:27:26 +01:00
Sebastiaan Janssen 98b7467306 Merge branch 'dev-v7' into master-v7 2018-03-22 10:53:24 +01:00
Sebastiaan Janssen 4bb75d73dd Bump version to 7.9.3 2018-03-22 10:50:12 +01:00
Shannon Deminick dd8e43d80a Fixes U4-10472 Cannot upgrade to 7.7+ when using MySql (#2493)
* Fixes U4-10472 Cannot upgrade to 7.7+ when using MySql

* Fixes dropping the FK for the AddUserGroupTables migration
2018-03-22 10:35:41 +01:00
Claus c9c9e8352a Merge pull request #2532 from umbraco/temp-U4-11134
redirects preview to login when not authorized
2018-03-22 10:22:32 +01:00
Shannon c4e5ab54d2 redirects preview to login when not authorized 2018-03-22 19:55:55 +11:00
Shannon 53bfec8a04 Merge branch 'dev-v7' into dev-v7.10 2018-03-22 19:22:34 +11:00
Sebastiaan Janssen b4a0dadee9 Re-apply the nice C# syntax James provided 2018-03-21 19:53:20 +01:00
Lee Kelleher 014ac98d0b U4-11052 - Enabled IntegerValueConverter to handle Int64 source values (#2500)
* Enabled IntegerValueConverter to handle `Int64` source values
2018-03-21 19:08:24 +01:00
Robert 35a79a8598 Merge pull request #2525 from umbraco/temp-U4-11020
U4-11020 Deleting a member group that is part of a Public Access feat…
2018-03-21 13:47:02 +01:00
Robert 3c4f052a27 Moved some code around based on feedback 2018-03-21 13:45:44 +01:00
Robert 97d7e3db84 Forgot add the new namespace 2018-03-21 10:46:42 +01:00
Robert 0d2df4de81 Some cleanup 2018-03-21 10:22:08 +01:00
Shannon b361cfebb7 updates npm build dependencies 2018-03-21 13:55:01 +11:00
Shannon ebea5e8170 fixes boolean pre-value editor Html Id 2018-03-21 13:53:54 +11:00
Shannon 995f3f38a3 Fixes upgrade issue with copying the preview.old directory and updates the link to the the correct public one 2018-03-21 12:52:17 +11:00
Shannon 2ad79956d9 Re-apply Drop Down Flexible "Merge pull request #2502 from umbraco/temp-U4-11032"" 2018-03-21 12:37:26 +11:00
Shannon 96c6a17d03 Merge branch 'dev-v7' into dev-v7.10 2018-03-21 12:36:55 +11:00
Shannon e2e0dd0c73 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2018-03-21 12:34:15 +11:00
Shannon 1a590664e7 Revert "Merge pull request #2502 from umbraco/temp-U4-11032"
This reverts commit 2aa0dfb2c5, reversing
changes made to 2c6e7e46c2.
2018-03-21 12:32:27 +11:00
Shannon Deminick 64fd6ee7c5 Merge pull request #2477 from Shazwazza/U4-10992
U4-10992 (UDUF) TourController Object reference not set to an instance of an…
2018-03-21 12:24:50 +11:00
Shannon Deminick 2ed5b6c1ee Merge pull request #2436 from umbraco/temp-U4-10957_2
U4-10957 If RequiredSection is not defined in a tour - backoffice wil…
2018-03-21 12:24:10 +11:00
Shannon Deminick 41c4e024de Merge pull request #2505 from umbraco/temp-u4-10756
U4-10756 - id/guid cache
2018-03-21 11:42:04 +11:00
Shannon b46add81f0 Merge branch 'dev-v7.10' into temp-u4-10756 2018-03-21 11:39:28 +11:00
Shannon ff31cd9f72 Changes Set to Populate, changes Fetch to Query and makes GetById public 2018-03-21 11:31:30 +11:00
Shannon 084af43dab Merge remote-tracking branch 'origin/dev-v7' into dev-v7.10 2018-03-21 10:20:20 +11:00
Sebastiaan Janssen edf7038848 U4-11020 Deleting a member group that is part of a Public Access feature, from the system, does not also remove the corresponding rows from the umbracoAccessRule table. 2018-03-20 15:00:09 +01:00
Niels Hartvig bcac02861d Merge pull request #2524 from davidwandar/patch-2
Fixed typo in Readme.
2018-03-20 11:18:57 +01:00
Sebastiaan Janssen 79ecaecc9e Merge pull request #2503 from umbraco/temp-U4-11070
Adds support for *not* closing an overlay on enter
2018-03-20 11:14:57 +01:00
Sebastiaan Janssen f604117c6d Merge pull request #2504 from umbraco/temp-U4-11071
U4-11071 Prevalue editor for multiple values TLC
2018-03-20 11:14:42 +01:00
David Wandar dcf7f35078 Fixed typo.
Xloud -> Cloud 

Xloud sounds awsome though :)
2018-03-20 10:00:53 +01:00
Robert 2aa0dfb2c5 Merge pull request #2502 from umbraco/temp-U4-11032
U4-11032 Consolidate the number of dropdown property editors into one
2018-03-19 14:37:47 +01:00
Robert e4b77416a6 Fixed typo 2018-03-19 14:28:24 +01:00
Robert 3aed889e2a Merge branch 'dev-v7' into temp-U4-11032 2018-03-19 14:14:51 +01:00
Robert 2c6e7e46c2 Merge pull request #2517 from dawoe/patch-1
Fixed documentation of umb-overlay directive
2018-03-19 08:58:23 +01:00
Mikulas Tomanka 0a71a09d21 Merge pull request #2518 from dawoe/patch-2
Remove console.log from slider property editor
2018-03-19 08:32:40 +01:00
Dave Woestenborghs 0c868fb72d Remove console.log from slider property editor
removed console.log statement from slider property editor controller
2018-03-16 18:43:54 +01:00
Dave Woestenborghs a96cbce9b1 Fixed documentation of umb-overlay directive
- Removed lorem ipsum text 
- Fixed casing of subtitle
2018-03-16 18:12:46 +01:00
Sebastiaan Janssen e3e425695f U4-8724 tinyMceConfig.config customConfig bool not correct deserialized 2018-03-16 16:34:58 +01:00
Sebastiaan Janssen b539c6ec27 Merge pull request #1445 from KevinJump/dev-v7-ConnectionStringConfigSource
U4-8890 - Honour ConfigSource when setting ConnectionString
2018-03-16 15:45:21 +01:00
Shannon 69f7623fb7 Doh! we had test code checked in .. oops! 2018-03-16 14:40:26 +11:00
Shannon 82820284f3 Merge remote-tracking branch 'origin/dev-v7' into dev-v7.10
# Conflicts:
#	src/Umbraco.Web/Features/DisabledFeatures.cs
#	src/Umbraco.Web/Features/EnabledFeatures.cs
2018-03-16 14:30:55 +11:00
Sebastiaan Janssen 5f3090c81e grunt was discontinued in 7.7 and shouldn't exist here any more to avoid confusion 2018-03-15 10:40:40 +01:00
Sebastiaan Janssen f66e239584 PhantomJs doesn't understand fancy ES6 notation 2018-03-15 10:32:25 +01:00
Sebastiaan Janssen a465ed415d Rename to javascriptLibraryService 2018-03-15 10:08:00 +01:00
Sebastiaan Janssen 5161fd0cef Remove trailing space from filename and clean up code a little 2018-03-15 10:07:04 +01:00
Sebastiaan Janssen eac9785c45 Apply PR #2507 2018-03-15 10:02:20 +01:00
Sebastiaan Janssen 054a8b48fa Revert PR #2507 - needs to go in 7.10 2018-03-15 09:59:04 +01:00
Stephan af0a03a3e0 U4-10756 - cleanup 2018-03-15 09:51:12 +01:00
Stephan fb5e6c22ce Merge remote-tracking branch 'origin/dev-v7' into temp-u4-10756 2018-03-15 09:46:52 +01:00
Stephan 6bc68005f4 U4-10756 - id/guid cache, new version 2018-03-15 09:46:39 +01:00
Sebastiaan Janssen dfbc3c477a Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into pr/2507 2018-03-15 09:38:44 +01:00
Shannon 05c38db54c updates naming of the extending preview property and fixes the angular rendering on ng-init 2018-03-14 15:24:30 +11:00
Shannon 00fdace570 fixes preview view web.config and makes sure we pass the preview model to the view 2018-03-14 14:38:21 +11:00
Shannon 4e531976e9 missing file 2018-03-14 14:24:11 +11:00
Shannon 0feb1b6cc0 fixes build since we don't have preview files 2018-03-14 14:02:35 +11:00
Shannon 830f460b7e bumps version 2018-03-14 13:58:48 +11:00
Shannon 3e2fa64820 Changes the Preview Index.cshtml to use a real model instead of viewdata, adds the correct razor web.config for these preview views, changes the enabled feature to be able to inject a razor view instead of strings 2018-03-14 13:56:49 +11:00
Shannon Deminick 7db4f841e3 Merge pull request #2485 from umbraco/temp-UAASSCRUM-1405
UAASSCRUM-1405 Clean up preview for Headless
2018-03-14 13:39:28 +11:00
Shannon 509d27f93b Merge branch 'dev-v7.10' into temp-UAASSCRUM-1405
# Conflicts:
#	src/Umbraco.Web/Features/EnabledFeatures.cs
2018-03-14 13:38:25 +11:00
Shannon f42b122e73 adding missing files 2018-03-14 13:35:51 +11:00
Shannon b4aad19573 Revert "Merge pull request #2508 from umbraco/temp-U4-11076"
This reverts commit 4161d244c1, reversing
changes made to eea87e411f.
2018-03-14 13:23:33 +11:00
Shannon 1b6c070752 Merge remote-tracking branch 'origin/dev-v7' into temp-UAASSCRUM-1405 2018-03-14 12:56:07 +11:00
Shannon bedce100d2 Fixes merge and the preview views path 2018-03-14 12:55:34 +11:00
Shannon 0e08a56ada Merge branch 'dev-v7' into temp-UAASSCRUM-1405
# Conflicts:
#	src/Umbraco.Web/Features/DisabledFeatures.cs
#	src/Umbraco.Web/Features/EnabledFeatures.cs
2018-03-14 12:25:37 +11:00
Sebastiaan Janssen 03012cf54d Merge pull request #1435 from neilgaietto/U4-8822
U4-8822- Fixes Unpublish error with empty RTE
2018-03-14 00:10:49 +01:00
Sebastiaan Janssen 7ff339e18a Merge pull request #1306 from shiroganee/Fix-8533
removes a overflow: hidden which decrease update-tree-layer performance
2018-03-13 23:34:59 +01:00
Sebastiaan Janssen 0048b9c4c8 Merge pull request #2516 from bjarnef/dev-v7-U4-11093
U4-11093 - Update Danish translations
2018-03-13 23:03:48 +01:00
Bjarne Fyrstenborg 47f5e6bf17 Remove duplicate key in user area 2018-03-13 22:23:38 +01:00
Bjarne Fyrstenborg a8908c90bc Add better translations to Danish 2018-03-13 22:21:44 +01:00
Sebastiaan Janssen 9e5e8b539a Merge branch 'bjarnef-dev-v7-U4-6616' into dev-v7 2018-03-13 22:19:15 +01:00
Sebastiaan Janssen 45d292e196 Merge branch 'dev-v7-U4-6616' of https://github.com/bjarnef/Umbraco-CMS into bjarnef-dev-v7-U4-6616
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/less/variables.less
#	src/Umbraco.Web.UI.Client/src/views/common/dialogs/iconpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/dialogs/iconpicker.html
2018-03-13 22:18:28 +01:00
Shannon Deminick 4161d244c1 Merge pull request #2508 from umbraco/temp-U4-11076
Fix - U4-11076 Remove all references to templates from the backoffice
2018-03-12 20:32:29 -07:00
Shannon 171e0d87db Updates some of the variable names, removes the EnabledFeatures since we don't really need that 2018-03-13 14:31:30 +11:00
Shannon Deminick eea87e411f Merge pull request #2514 from umbraco/temp-U4-11065
Fix - U4-11065 Sensitive data is shown in listviews
2018-03-12 17:25:49 -07:00
Shannon 89edfe5782 refactors a bit - merges the 2 new resolvers into one and renames with code comments. Updates the ContentPropertyBasic to include a new IsSensitive property for mapping, updates the UI to check for this, updats the mapping to map with UmbracoContext, 2018-03-13 11:23:44 +11:00
Shannon Deminick cbd5071eed Merge pull request #2510 from umbraco/temp-UAASSCRUM-1441
fixes UAASSCRUM-1441: fix token identity breaking RestAPI and others
2018-03-12 06:27:50 -07:00
Robert 3dbc2944aa Translations 2018-03-12 12:06:57 +01:00
Robert 709dab6afd Hooked sensitive data checks on member list view 2018-03-12 12:06:23 +01:00
Robert 8749b030cf Added custom resolver to deal with sensitive values on member list view, some cleanup 2018-03-12 12:04:54 +01:00
Sebastiaan Janssen 62fd15d54b Update CONTRIBUTING.md 2018-03-10 12:24:13 +01:00
Sebastiaan Janssen 66e71db85c Update CONTRIBUTING.md 2018-03-10 12:20:56 +01:00
Sebastiaan Janssen 469527da0a Update CONTRIBUTING.md 2018-03-10 12:20:24 +01:00
Robert 304e574bbc Merge pull request #2509 from umbraco/temp-U4-11058
fixes: U4-11058 Add guidance to the multinode treepicker UI for min. …
2018-03-08 14:01:14 +01:00
Robert 723644ace5 Merge pull request #2475 from barryokane/U4-7484-markdown
(uDuf) Prevent "unsaved" warning when no changes on MarkDown Editor
2018-03-08 13:23:46 +01:00
Stephan 2b936a6d31 UAASSCRUM-1441 - fix token identity 2018-03-08 13:18:53 +01:00
Sebastiaan Jansssen 3121635e07 Clarify upgrade readme 2018-03-08 13:15:04 +01:00
Mads Rasmussen f2a3a269ba fixes: U4-11058 Add guidance to the multinode treepicker UI for min. and max. allowed items 2018-03-08 11:22:31 +01:00
Robert 557fc1bcdd Removed hardcoded value for disabletemplate 2018-03-07 21:43:19 +01:00
Robert 1a5fe63638 Switching to ng-if to hide the template dropdown in the info tab 2018-03-07 14:51:24 +01:00
Robert dfb0efbc98 Removed option to assign templates from the info tab 2018-03-07 14:43:30 +01:00
Robert d399ad6e51 Removed option to assign templates from the document type 2018-03-07 14:13:53 +01:00
Robert eb06e62937 Removing the option to create document type with a template 2018-03-07 14:10:25 +01:00
Robert 728bf8b52d Adding disableFeatures server variable and new DisableTemplate property in DisabledFeatures.cs 2018-03-07 14:03:35 +01:00
Niels Hartvig ca74100e12 TLC for multiple pre values editor 2018-03-06 16:11:44 +01:00
Stephan cd63806895 U4-10756 - id/guid cache 2018-03-06 16:11:27 +01:00
Niels Hartvig 3061dc4e6f Adds support for *not* closing an overlay on enter 2018-03-06 15:37:52 +01:00
Niels Hartvig 5166dc08d6 Missing null check 2018-03-06 12:44:39 +01:00
Niels Hartvig 05a9c44e9e Needs to check if single value is an array and then pick first value 2018-03-06 11:51:32 +01:00
Niels Hartvig 8e0565e030 Fixes spacing in description :) 2018-03-06 11:16:51 +01:00
Niels Hartvig ceb3ae361a Adds flexible dropdown editor to replace the four current ones 2018-03-06 11:07:08 +01:00
Niels Hartvig 4cee7b831a Merge branch 'dev-v7' into temp-U4-11032 2018-03-06 10:08:04 +01:00
Sebastiaan Jansssen 4a8730b925 U4-10891 Color Picker Cannot read property 'hasOwnProperty' of null 2018-03-01 16:45:38 +01:00
Sebastiaan Jansssen d94e7cd906 Merge branch 'dev-v7' into master-v7 2018-03-01 15:09:45 +01:00
Sebastiaan Jansssen dde8ba5617 Merge branch 'dev-v7' into master-v7 2018-03-01 14:57:11 +01:00
Niels Hartvig d06b7edd84 Change default value label to "true" 2018-03-01 14:46:36 +01:00
Niels Hartvig 466de5ee0b Adds a label to the boolean pre value editor 2018-03-01 14:41:44 +01:00
Niels Hartvig 976e1e8a35 Mark existing dropdown property editors as obsolete 2018-03-01 14:25:07 +01:00
Claus 23638702c8 adding missing views... 2018-03-01 12:57:43 +01:00
Sebastiaan Jansssen a633e45b44 Merge branch 'dev-v7' into master-v7 2018-03-01 10:27:57 +01:00
Sebastiaan Jansssen 63b58dcd09 Merge remote-tracking branch 'origin/dev-v7' into master-v7 2018-03-01 07:51:07 +01:00
Claus 52684b6189 allowing to extend html used in preview view. 2018-02-28 13:41:49 +01:00
Sebastiaan Jansssen 76a0c6c39f Merge branch 'dev-v7' into master-v7 2018-02-28 13:28:39 +01:00
Claus 13c675d718 updating route to use the old url.
removing leftover index.html.
adding migration for renaming preview folder on disk.
2018-02-28 12:04:39 +01:00
Claus 0ee3ebd180 adding the preview controller to project.
removing old static html files from src (they're now cshtml files in Views).
copy task should not copy static canvasdesigner files anymore.
2018-02-28 08:58:16 +01:00
Claus 9c8c9d8a39 UAASSCRUM-1405 Clean up preview for Headless 2018-02-27 15:47:47 +01:00
Sebastiaan Jansssen 37d2203de1 Merge branch 'dev-v7' into master-v7 2018-02-27 15:45:16 +01:00
Barry 732d3ef326 Prevent "unsaved" warning when no changes on MarkDown Editor
http://issues.umbraco.org/issue/U4-7484#
2018-02-25 03:18:00 +00:00
Sebastiaan Jansssen 858156bab2 Merge branch 'dev-v7' into master-v7 2018-02-23 22:23:43 +01:00
Sebastiaan Jansssen 2ae96f3810 Merge branch 'dev-v7' into master-v7 2018-02-23 14:23:49 +01:00
Shannon 7019c9433b U4-10991 TourController Object reference not set to an instance of an object - when loading an invalid tour 2018-02-23 16:40:29 +10:00
Sebastiaan Jansssen a5f689385a Merge branch 'dev-v7' into master-v7 2018-02-19 17:13:35 +01:00
Sebastiaan Jansssen 1607e51270 Merge branch 'dev-v7' into master-v7 2018-02-19 14:21:16 +01:00
Sebastiaan Jansssen 044b43f6e1 Merge branch 'dev-v7' into master-v7 2018-02-19 14:10:09 +01:00
Claus b2004057a5 U4-10957 If RequiredSection is not defined in a tour - backoffice will throw errors 2018-02-09 11:55:34 +01:00
Sebastiaan Jansssen c59a226d56 Merge remote-tracking branch 'origin/dev-v7' into master-v7 2018-02-09 09:51:39 +01:00
Sebastiaan Jansssen 0c25c36af0 Bump version to 7.7.11 2018-02-09 09:46:05 +01:00
Kevin Jump ae110c1cae Honour ConfigSource when setting ConnectionString
Lets umbraco honour the configSource attribute on a connectionstrings
section, meaning you can install the connectionstring into a file other
than web.config.
2016-08-23 08:45:30 +01:00
Neil Gaietto 3f1f67e323 U4-8822- Fixes Unpublish error with empty RTE by passing an empty value instead of null 2016-08-16 09:30:05 -04:00
Kamil Jakubczak f1d37a5072 removes a overflow: hidden which decrease update-tree-layer performance
removes a overflow: hidden which decrease update-tree-layer performance.
If it is required it should be solved differently due to the possibility
of having plenty items in div that has this class.
2016-06-09 15:01:26 +02:00
bjarnef 2dc6e395a8 Add more colors to icon-picker dialog 2015-11-16 01:15:51 +01:00
bjarnef eedeb90673 Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7-U4-6616 2015-11-16 01:12:49 +01:00
bjarnef 977c390a95 Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7-U4-6616 2015-11-09 23:52:00 +01:00
109 changed files with 1605 additions and 1212 deletions
+1
View File
@@ -113,6 +113,7 @@ build/ApiDocs/*
build/ApiDocs/Output/*
src/Umbraco.Web.UI.Client/bower_components/*
/src/Umbraco.Web.UI/Umbraco/preview
/src/Umbraco.Web.UI/Umbraco/preview.old
#Ignore Rule for output of generated documentation files from Grunt docserve
src/Umbraco.Web.UI.Client/docs/api
+24
View File
@@ -24,6 +24,7 @@ Remember, we're a friendly bunch and are happy with whatever contribution you mi
* [Working with the source code](#working-with-the-source-code)
* [What branch should I target for my contributions?](#what-branch-should-i-target-for-my-contributions)
* [Building Umbraco from source code](#building-umbraco-from-source-code)
* [Keeping your Umbraco fork in sync with the main repository](#keeping-your-umbraco-fork-in-sync-with-the-main-repository)
[How do I even begin?](#how-do-i-even-begin)
@@ -146,6 +147,29 @@ Alternatively, you can open `src\umbraco.sln` in Visual Studio 2017 ([the commun
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.
### 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.
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.
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
```
Then when you want to get the changes from the main repository:
```
git fetch upstream
git rebase upstream/dev-v7
```
In this command we're syncing with the `dev-v7` 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))
## How do I even begin?
Great question! The short version goes like this:
+1 -1
View File
@@ -30,7 +30,7 @@ As an Open Source platform, Umbraco is more than just a CMS. We are transparent
[Umbraco Cloud](https://umbraco.com) is the easiest and fastest way to use Umbraco yet with full support for all your custom .NET code and intergrations. 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.org/download) either as a ZIP file or via NuGet. It's the same version of Umbraco CMS that powers Umbraco Xloud, but you'll need to find a place to host yourself and handling deployments and upgrades is all down to you.
If you want to DIY you can [download Umbraco](https://our.umbraco.org/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 yourself and handling deployments and upgrades is all down to you.
## Community
@@ -376,7 +376,7 @@ function Prepare-Packages
Copy-Files "$src\Umbraco.Web.UI\umbraco\js" "*" "$tmp\WebApp\umbraco\js"
Copy-Files "$src\Umbraco.Web.UI\umbraco\lib" "*" "$tmp\WebApp\umbraco\lib"
Copy-Files "$src\Umbraco.Web.UI\umbraco\views" "*" "$tmp\WebApp\umbraco\views"
Copy-Files "$src\Umbraco.Web.UI\umbraco\preview" "*" "$tmp\WebApp\umbraco\preview"
}
#
+1
View File
@@ -39,6 +39,7 @@
<!-- Markdown can not be updated due to: https://github.com/hey-red/markdownsharp/issues/71#issuecomment-233585487 -->
<dependency id="Markdown" version="[1.14.7, 2.0.0)" />
<dependency id="System.Threading.Tasks.Dataflow" version="[4.7.0, 5.0.0)" />
<dependency id="System.ValueTuple" version="[4.4.0, 5.0.0)" />
</dependencies>
</metadata>
<files>
+1 -1
View File
@@ -8,7 +8,7 @@
----------------------------------------------------
*** IMPORTANT NOTICE FOR 7.7 UPGRADES ***
*** IMPORTANT NOTICE FOR UPGRADES FROM VERSIONS BELOW 7.7.0 ***
Be sure to read the version specific upgrade information before proceeding:
https://our.umbraco.org/documentation/Getting-Started/Setup/Upgrading/version-specific#version-7-7-0
+2 -2
View File
@@ -11,5 +11,5 @@ using System.Resources;
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("7.9.2")]
[assembly: AssemblyInformationalVersion("7.9.2")]
[assembly: AssemblyFileVersion("7.10.0")]
[assembly: AssemblyInformationalVersion("7.10.0")]
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration
{
public class UmbracoVersion
{
private static readonly Version Version = new Version("7.9.2");
private static readonly Version Version = new Version("7.10.0");
/// <summary>
/// Gets the current version of Umbraco.
@@ -122,6 +122,11 @@ namespace Umbraco.Core
/// Alias for the Dropdown list, publishing keys datatype.
/// </summary>
public const string DropdownlistPublishingKeysAlias = "Umbraco.DropdownlistPublishingKeys";
/// <summary>
/// Alias for the "new" Dropdown list, that replaces the old four deprecated ones and works as other list based property editors
/// </summary>
public const string DropDownListFlexibleAlias = "Umbraco.DropDown.Flexible";
/// <summary>
/// Guid for the Folder browser datatype.
@@ -452,4 +457,4 @@ namespace Umbraco.Core
}
}
}
}
}
+16
View File
@@ -459,6 +459,22 @@ namespace Umbraco.Core
var xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
var connectionstrings = xml.Root.DescendantsAndSelf("connectionStrings").Single();
// honour configSource, if its set, change the xml file we are saving the configuration
// to the one set in the configSource attribute
if (connectionstrings.Attribute("configSource") != null)
{
var source = connectionstrings.Attribute("configSource").Value;
var configFile = IOHelper.MapPath(string.Format("{0}/{1}", SystemDirectories.Root, source));
LogHelper.Info<DatabaseContext>("storing ConnectionString in {0}", () => configFile);
if (System.IO.File.Exists(configFile))
{
xml = XDocument.Load(fileName, LoadOptions.PreserveWhitespace);
fileName = configFile;
}
connectionstrings = xml.Root.DescendantsAndSelf("connectionStrings").Single();
}
// Update connectionString if it exists, or else create a new appSetting for the given key and value
var setting = connectionstrings.Descendants("add").FirstOrDefault(s => s.Attribute("name").Value == Constants.System.UmbracoConnectionName);
if (setting == null)
-1
View File
@@ -203,7 +203,6 @@ namespace Umbraco.Core.IO
{
get
{
//by default the packages folder should exist in the data folder
return IOHelper.ReturnPath("umbracoPreviewPath", Data + IOHelper.DirSepChar + "preview");
}
}
+28 -56
View File
@@ -140,8 +140,7 @@ namespace Umbraco.Core
if (underlying != null)
{
// Special case for empty strings for bools/dates which should return null if an empty string.
var inputString = input as string;
if (inputString != null)
if (input is string inputString)
{
//TODO: Why the check against only bool/date when a string is null/empty? In what scenario can we convert to another type when the string is null or empty other than just being null?
if (string.IsNullOrEmpty(inputString) && (underlying == typeof(DateTime) || underlying == typeof(bool)))
@@ -168,8 +167,7 @@ namespace Umbraco.Core
{
// target is not a generic type
var inputString = input as string;
if (inputString != null)
if (input is string inputString)
{
// Try convert from string, returns an Attempt if the string could be
// processed (either succeeded or failed), else null if we need to try
@@ -218,8 +216,7 @@ namespace Umbraco.Core
}
// Re-check convertables since we altered the input through recursion
var convertible2 = input as IConvertible;
if (convertible2 != null)
if (input is IConvertible convertible2)
{
return Attempt.Succeed(Convert.ChangeType(convertible2, target));
}
@@ -277,8 +274,7 @@ namespace Umbraco.Core
{
if (target == typeof(int))
{
int value;
if (int.TryParse(input, out value))
if (int.TryParse(input, out var value))
{
return Attempt<object>.Succeed(value);
}
@@ -286,30 +282,26 @@ namespace Umbraco.Core
// Because decimal 100.01m will happily convert to integer 100, it
// makes sense that string "100.01" *also* converts to integer 100.
var input2 = NormalizeNumberDecimalSeparator(input);
decimal value2;
return Attempt<object>.SucceedIf(decimal.TryParse(input2, out value2), Convert.ToInt32(value2));
return Attempt<object>.SucceedIf(decimal.TryParse(input2, out var value2), Convert.ToInt32(value2));
}
if (target == typeof(long))
{
long value;
if (long.TryParse(input, out value))
if (long.TryParse(input, out var value))
{
return Attempt<object>.Succeed(value);
}
// Same as int
var input2 = NormalizeNumberDecimalSeparator(input);
decimal value2;
return Attempt<object>.SucceedIf(decimal.TryParse(input2, out value2), Convert.ToInt64(value2));
return Attempt<object>.SucceedIf(decimal.TryParse(input2, out var value2), Convert.ToInt64(value2));
}
// TODO: Should we do the decimal trick for short, byte, unsigned?
if (target == typeof(bool))
{
bool value;
if (bool.TryParse(input, out value))
if (bool.TryParse(input, out var value))
{
return Attempt<object>.Succeed(value);
}
@@ -322,53 +314,42 @@ namespace Umbraco.Core
switch (Type.GetTypeCode(target))
{
case TypeCode.Int16:
short value;
return Attempt<object>.SucceedIf(short.TryParse(input, out value), value);
return Attempt<object>.SucceedIf(short.TryParse(input, out var value), value);
case TypeCode.Double:
var input2 = NormalizeNumberDecimalSeparator(input);
double valueD;
return Attempt<object>.SucceedIf(double.TryParse(input2, out valueD), valueD);
return Attempt<object>.SucceedIf(double.TryParse(input2, out var valueD), valueD);
case TypeCode.Single:
var input3 = NormalizeNumberDecimalSeparator(input);
float valueF;
return Attempt<object>.SucceedIf(float.TryParse(input3, out valueF), valueF);
return Attempt<object>.SucceedIf(float.TryParse(input3, out var valueF), valueF);
case TypeCode.Char:
char valueC;
return Attempt<object>.SucceedIf(char.TryParse(input, out valueC), valueC);
return Attempt<object>.SucceedIf(char.TryParse(input, out var valueC), valueC);
case TypeCode.Byte:
byte valueB;
return Attempt<object>.SucceedIf(byte.TryParse(input, out valueB), valueB);
return Attempt<object>.SucceedIf(byte.TryParse(input, out var valueB), valueB);
case TypeCode.SByte:
sbyte valueSb;
return Attempt<object>.SucceedIf(sbyte.TryParse(input, out valueSb), valueSb);
return Attempt<object>.SucceedIf(sbyte.TryParse(input, out var valueSb), valueSb);
case TypeCode.UInt32:
uint valueU;
return Attempt<object>.SucceedIf(uint.TryParse(input, out valueU), valueU);
return Attempt<object>.SucceedIf(uint.TryParse(input, out var valueU), valueU);
case TypeCode.UInt16:
ushort valueUs;
return Attempt<object>.SucceedIf(ushort.TryParse(input, out valueUs), valueUs);
return Attempt<object>.SucceedIf(ushort.TryParse(input, out var valueUs), valueUs);
case TypeCode.UInt64:
ulong valueUl;
return Attempt<object>.SucceedIf(ulong.TryParse(input, out valueUl), valueUl);
return Attempt<object>.SucceedIf(ulong.TryParse(input, out var valueUl), valueUl);
}
}
else if (target == typeof(Guid))
{
Guid value;
return Attempt<object>.SucceedIf(Guid.TryParse(input, out value), value);
return Attempt<object>.SucceedIf(Guid.TryParse(input, out var value), value);
}
else if (target == typeof(DateTime))
{
DateTime value;
if (DateTime.TryParse(input, out value))
if (DateTime.TryParse(input, out var value))
{
switch (value.Kind)
{
@@ -388,24 +369,20 @@ namespace Umbraco.Core
}
else if (target == typeof(DateTimeOffset))
{
DateTimeOffset value;
return Attempt<object>.SucceedIf(DateTimeOffset.TryParse(input, out value), value);
return Attempt<object>.SucceedIf(DateTimeOffset.TryParse(input, out var value), value);
}
else if (target == typeof(TimeSpan))
{
TimeSpan value;
return Attempt<object>.SucceedIf(TimeSpan.TryParse(input, out value), value);
return Attempt<object>.SucceedIf(TimeSpan.TryParse(input, out var value), value);
}
else if (target == typeof(decimal))
{
var input2 = NormalizeNumberDecimalSeparator(input);
decimal value;
return Attempt<object>.SucceedIf(decimal.TryParse(input2, out value), value);
return Attempt<object>.SucceedIf(decimal.TryParse(input2, out var value), value);
}
else if (input != null && target == typeof(Version))
{
Version value;
return Attempt<object>.SucceedIf(Version.TryParse(input, out value), value);
return Attempt<object>.SucceedIf(Version.TryParse(input, out var value), value);
}
// E_NOTIMPL IPAddress, BigInteger
@@ -690,8 +667,7 @@ namespace Umbraco.Core
{
var key = new CompositeTypeTypeKey(source, target);
TypeConverter typeConverter;
if (InputTypeConverterCache.TryGetValue(key, out typeConverter))
if (InputTypeConverterCache.TryGetValue(key, out TypeConverter typeConverter))
{
return typeConverter;
}
@@ -711,8 +687,7 @@ namespace Umbraco.Core
{
var key = new CompositeTypeTypeKey(source, target);
TypeConverter typeConverter;
if (DestinationTypeConverterCache.TryGetValue(key, out typeConverter))
if (DestinationTypeConverterCache.TryGetValue(key, out TypeConverter typeConverter))
{
return typeConverter;
}
@@ -730,8 +705,7 @@ namespace Umbraco.Core
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Type GetCachedGenericNullableType(Type type)
{
Type underlyingType;
if (NullableGenericCache.TryGetValue(type, out underlyingType))
if (NullableGenericCache.TryGetValue(type, out Type underlyingType))
{
return underlyingType;
}
@@ -750,8 +724,7 @@ namespace Umbraco.Core
private static bool GetCachedCanAssign(object input, Type source, Type target)
{
var key = new CompositeTypeTypeKey(source, target);
bool canConvert;
if (AssignableTypeCache.TryGetValue(key, out canConvert))
if (AssignableTypeCache.TryGetValue(key, out bool canConvert))
{
return canConvert;
}
@@ -770,8 +743,7 @@ namespace Umbraco.Core
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool GetCachedCanConvertToBoolean(Type type)
{
bool result;
if (BoolConvertCache.TryGetValue(type, out result))
if (BoolConvertCache.TryGetValue(type, out bool result))
{
return result;
}
@@ -6,6 +6,7 @@ using Umbraco.Core.Configuration;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.SqlSyntax;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSevenZero
@@ -343,15 +344,24 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSevenZe
if (tables.InvariantContains("umbracoUserType") && tables.InvariantContains("umbracoUser"))
{
if (constraints.Any(x => x.Item1.InvariantEquals("umbracoUser") && x.Item3.InvariantEquals("FK_umbracoUser_umbracoUserType_id")))
if (Context.CurrentDatabaseProvider == DatabaseProviders.MySql)
{
Delete.ForeignKey("FK_umbracoUser_umbracoUserType_id").OnTable("umbracoUser");
//In MySql, this will drop the FK according to it's special naming rules
Delete.ForeignKey().FromTable("umbracoUser").ForeignColumn("userType").ToTable("umbracoUserType").PrimaryColumn("id");
}
//This is the super old constraint name of the FK for user type so check this one too
if (constraints.Any(x => x.Item1.InvariantEquals("umbracoUser") && x.Item3.InvariantEquals("FK_user_userType")))
else
{
Delete.ForeignKey("FK_user_userType").OnTable("umbracoUser");
}
//Delete the FK if it exists before dropping the column
if (constraints.Any(x => x.Item1.InvariantEquals("umbracoUser") && x.Item3.InvariantEquals("FK_umbracoUser_umbracoUserType_id")))
{
Delete.ForeignKey("FK_umbracoUser_umbracoUserType_id").OnTable("umbracoUser");
}
//This is the super old constraint name of the FK for user type so check this one too
if (constraints.Any(x => x.Item1.InvariantEquals("umbracoUser") && x.Item3.InvariantEquals("FK_user_userType")))
{
Delete.ForeignKey("FK_user_userType").OnTable("umbracoUser");
}
}
Delete.Column("userType").FromTable("umbracoUser");
Delete.Table("umbracoUserType");
@@ -361,4 +371,4 @@ namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenSevenZe
public override void Down()
{ }
}
}
}
@@ -0,0 +1,44 @@
using System.IO;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence.SqlSyntax;
using File = System.IO.File;
namespace Umbraco.Core.Persistence.Migrations.Upgrades.TargetVersionSevenTenZero
{
/// <summary>
/// Renames the preview folder containing static html files to ensure it does not interfere with the MVC route
/// that is now supposed to render these views dynamically. We don't want to delete as people may have made
/// customizations to these files that would need to be migrated to the new .cshtml view files.
/// </summary>
[Migration("7.10.0", 1, Constants.System.UmbracoMigrationName)]
public class RenamePreviewFolder : MigrationBase
{
public RenamePreviewFolder(ISqlSyntaxProvider sqlSyntax, ILogger logger)
: base(sqlSyntax, logger)
{
}
public override void Up()
{
var previewFolderPath = IOHelper.MapPath(SystemDirectories.Umbraco + "/preview");
if (Directory.Exists(previewFolderPath))
{
var newPath = previewFolderPath.Replace("preview", "preview.old");
if (Directory.Exists(newPath) == false)
{
Directory.Move(previewFolderPath, newPath);
var readmeText =
$"Static html files used for preview and canvas editing functionality no longer live in this directory.\r\n" +
$"Instead they have been recreated as MVC views and can now be found in '~/Umbraco/Views/Preview'.\r\n" +
$"See issue: http://issues.umbraco.org/issue/U4-11090";
File.WriteAllText(Path.Combine(newPath, "readme.txt"), readmeText);
}
}
}
public override void Down()
{
}
}
}
@@ -1,4 +1,5 @@
using Umbraco.Core.Models.PublishedContent;
using System;
using Umbraco.Core.Models.PublishedContent;
namespace Umbraco.Core.PropertyEditors.ValueConverters
{
@@ -14,19 +15,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
{
if (source == null) return 0;
// in XML an integer is a string
var sourceString = source as string;
if (sourceString != null)
{
int i;
return (int.TryParse(sourceString, out i)) ? i : 0;
}
// in the database an integer is an integer
// default value is zero
return (source is int) ? source : 0;
return source.TryConvertTo<int>().Result;
}
}
}
@@ -37,15 +37,15 @@ namespace Umbraco.Core.Security
var username = identity.GetUserName();
var session = identity.FindFirstValue(Constants.Security.SessionIdClaimType);
var securityStamp = identity.FindFirstValue(Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType);
var startContentId = identity.FindFirstValue(Constants.Security.StartContentNodeIdClaimType);
var startContentId = identity.FindFirstValue(Constants.Security.StartContentNodeIdClaimType);
var startMediaId = identity.FindFirstValue(Constants.Security.StartMediaNodeIdClaimType);
var culture = identity.FindFirstValue(ClaimTypes.Locality);
var id = identity.FindFirstValue(ClaimTypes.NameIdentifier);
var id = identity.FindFirstValue(ClaimTypes.NameIdentifier);
var realName = identity.FindFirstValue(ClaimTypes.GivenName);
if (username == null || startContentId == null || startMediaId == null
|| culture == null || id == null
if (username == null || startContentId == null || startMediaId == null
|| culture == null || id == null
|| realName == null || session == null)
throw new InvalidOperationException("Cannot create a " + typeof(UmbracoBackOfficeIdentity) + " from " + typeof(ClaimsIdentity) + " since there are missing required claims");
@@ -62,7 +62,7 @@ namespace Umbraco.Core.Security
catch (Exception e)
{
throw new InvalidOperationException("Cannot create a " + typeof(UmbracoBackOfficeIdentity) + " from " + typeof(ClaimsIdentity) + " since the data is not formatted correctly - either content or media start Ids could not be parsed as JSON", e);
}
}
var roles = identity.FindAll(x => x.Type == DefaultRoleClaimType).Select(role => role.Value).ToList();
var allowedApps = identity.FindAll(x => x.Type == Constants.Security.AllowedApplicationsClaimType).Select(app => app.Value).ToList();
@@ -165,7 +165,7 @@ namespace Umbraco.Core.Security
{
foreach (var claim in claimsIdentity.Claims)
{
//In one special case we will replace a claim if it exists already and that is the
//In one special case we will replace a claim if it exists already and that is the
// Forms auth claim for name which automatically gets added
TryRemoveClaim(FindFirst(x => x.Type == claim.Type && x.Issuer == "Forms"));
@@ -187,15 +187,15 @@ namespace Umbraco.Core.Security
{
ClaimTypes.NameIdentifier, //id
ClaimTypes.Name, //username
ClaimTypes.GivenName,
ClaimTypes.GivenName,
Constants.Security.StartContentNodeIdClaimType,
Constants.Security.StartMediaNodeIdClaimType,
ClaimTypes.Locality,
Constants.Security.StartMediaNodeIdClaimType,
ClaimTypes.Locality,
Constants.Security.SessionIdClaimType,
Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType
};
}
}
}
/// <summary>
/// Adds claims based on the UserData data
@@ -222,23 +222,19 @@ namespace Umbraco.Core.Security
AddClaim(new Claim(ClaimTypes.Locality, Culture, ClaimValueTypes.String, Issuer, Issuer, this));
if (HasClaim(x => x.Type == Constants.Security.SessionIdClaimType) == false && SessionId.IsNullOrWhiteSpace() == false)
{
AddClaim(new Claim(Constants.Security.SessionIdClaimType, SessionId, ClaimValueTypes.String, Issuer, Issuer, this));
//The security stamp claim is also required... this is because this claim type is hard coded
// by the SecurityStampValidator, see: https://katanaproject.codeplex.com/workitem/444
if (HasClaim(x => x.Type == Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType) == false)
{
AddClaim(new Claim(Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType, SecurityStamp, ClaimValueTypes.String, Issuer, Issuer, this));
}
}
//The security stamp claim is also required... this is because this claim type is hard coded
// by the SecurityStampValidator, see: https://katanaproject.codeplex.com/workitem/444
if (HasClaim(x => x.Type == Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType) == false)
AddClaim(new Claim(Microsoft.AspNet.Identity.Constants.DefaultSecurityStampClaimType, SecurityStamp, ClaimValueTypes.String, Issuer, Issuer, this));
//Add each app as a separate claim
if (HasClaim(x => x.Type == Constants.Security.AllowedApplicationsClaimType) == false)
{
foreach (var application in AllowedApplications)
{
AddClaim(new Claim(Constants.Security.AllowedApplicationsClaimType, application, ClaimValueTypes.String, Issuer, Issuer, this));
AddClaim(new Claim(Constants.Security.AllowedApplicationsClaimType, application, ClaimValueTypes.String, Issuer, Issuer, this));
}
}
@@ -253,8 +249,8 @@ namespace Umbraco.Core.Security
}
}
}
protected internal UserData UserData { get; private set; }
@@ -332,4 +328,4 @@ namespace Umbraco.Core.Security
}
}
}
}
+219 -46
View File
@@ -1,4 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using Umbraco.Core.Models;
@@ -22,13 +23,139 @@ namespace Umbraco.Core.Services
// note - no need for uow, scope would be enough, but a pain to wire
// note - for pure read-only we might want to *not* enforce a transaction?
// notes
//
// - this class assumes that the id/guid map is unique; that is, if an id and a guid map
// to each other, then the id will never map to another guid, and the guid will never map
// to another id
//
// - LeeK's solution in 7.7 was to look for the id/guid in the content cache "on demand" via
// XPath, which is probably fast enough but cannot deal with media ids + it maintains a
// separate, duplicate cache
// see https://github.com/umbraco/Umbraco-CMS/pull/2398
//
// - Andy's solution in a package was to prefetch all by sql; it cannot prefecth reserved ids
// as we don't know the corresponding object type, but that's not a big issue - but then we
// have a full database query on startup
// see https://github.com/AndyButland/UmbracoUdiToIdCache
//
// - the original IdkMap implementation that was used by services, did a database lookup on
// each cache miss, which is fine enough for services, but would be really slow at content
// cache level
//
// - cache is cleared by MediaCacheRefresher, UnpublishedPageCacheRefresher, and other
// refreshers - because id/guid map is unique, we only clear to avoid leaking memory, 'cos
// we don't risk caching obsolete values - and only when actually deleting
//
// so...
//
// - there's a single caching point, and it's idkMap
// - there are no "helper methods" - the published content cache itself knows about Guids
// - when the published content cache is instanciated, it populates the idkMap with what it knows
// and it registers a way for the idkMap to look for id/keys in the published content cache
// - we do NOT prefetch anything from database
// - when a request comes in:
// the published content cache uses the idkMap to map id/key
// if the idkMap already knows about the map, it returns the value
// else it tries the published cache via XPath
// else it hits the database
private readonly ConcurrentDictionary<UmbracoObjectTypes, (Func<int, Guid> id2key, Func<Guid, int> key2id)> _dictionary
= new ConcurrentDictionary<UmbracoObjectTypes, (Func<int, Guid> id2key, Func<Guid, int> key2id)>();
internal void SetMapper(UmbracoObjectTypes umbracoObjectType, Func<int, Guid> id2key, Func<Guid, int> key2id)
{
_dictionary[umbracoObjectType] = (id2key, key2id);
}
internal void Populate(IEnumerable<(int id, Guid key)> pairs, UmbracoObjectTypes umbracoObjectType)
{
try
{
_locker.EnterWriteLock();
foreach (var pair in pairs)
{
_id2Key.Add(pair.id, new TypedId<Guid>(pair.key, umbracoObjectType));
_key2Id.Add(pair.key, new TypedId<int>(pair.id, umbracoObjectType));
}
}
finally
{
if (_locker.IsWriteLockHeld)
_locker.ExitWriteLock();
}
}
#if POPULATE_FROM_DATABASE
private void PopulateLocked()
{
// don't if not empty
if (_key2Id.Count > 0) return;
using (var uow = _uowProvider.GetUnitOfWork())
{
// populate content and media items
var types = new[] { Constants.ObjectTypes.Document, Constants.ObjectTypes.Media };
var values = uow.Database.Query<TypedIdDto>("SELECT id, uniqueId, nodeObjectType FROM umbracoNode WHERE nodeObjectType IN @types", new { types });
foreach (var value in values)
{
var umbracoObjectType = UmbracoObjectTypesExtensions.GetUmbracoObjectType(value.NodeObjectType);
_id2Key.Add(value.Id, new TypedId<Guid>(value.UniqueId, umbracoObjectType));
_key2Id.Add(value.UniqueId, new TypedId<int>(value.Id, umbracoObjectType));
}
}
}
private Attempt<int> PopulateAndGetIdForKey(Guid key, UmbracoObjectTypes umbracoObjectType)
{
try
{
_locker.EnterWriteLock();
PopulateLocked();
return _key2Id.TryGetValue(key, out var id) && id.UmbracoObjectType == umbracoObjectType
? Attempt.Succeed(id.Id)
: Attempt<int>.Fail();
}
finally
{
if (_locker.IsReadLockHeld)
_locker.ExitReadLock();
}
}
private Attempt<Guid> PopulateAndGetKeyForId(int id, UmbracoObjectTypes umbracoObjectType)
{
try
{
_locker.EnterWriteLock();
PopulateLocked();
return _id2Key.TryGetValue(id, out var key) && key.UmbracoObjectType == umbracoObjectType
? Attempt.Succeed(key.Id)
: Attempt<Guid>.Fail();
}
finally
{
if (_locker.IsReadLockHeld)
_locker.ExitReadLock();
}
}
#endif
public Attempt<int> GetIdForKey(Guid key, UmbracoObjectTypes umbracoObjectType)
{
TypedId<int> id;
bool empty;
try
{
_locker.EnterReadLock();
if (_key2Id.TryGetValue(key, out id) && id.UmbracoObjectType == umbracoObjectType) return Attempt.Succeed(id.Id);
if (_key2Id.TryGetValue(key, out var id) && id.UmbracoObjectType == umbracoObjectType) return Attempt.Succeed(id.Id);
empty = _key2Id.Count == 0;
}
finally
{
@@ -36,20 +163,37 @@ namespace Umbraco.Core.Services
_locker.ExitReadLock();
}
int? val;
using (var uow = _uowProvider.GetUnitOfWork())
#if POPULATE_FROM_DATABASE
// if cache is empty and looking for a document or a media,
// populate the cache at once and return what we found
if (empty && (umbracoObjectType == UmbracoObjectTypes.Document || umbracoObjectType == UmbracoObjectTypes.Media))
return PopulateAndGetIdForKey(key, umbracoObjectType);
#endif
// optimize for read speed: reading database outside a lock means that we could read
// multiple times, but we don't lock the cache while accessing the database = better
int? val = null;
if (_dictionary.TryGetValue(umbracoObjectType, out var mappers))
if ((val = mappers.key2id(key)) == default(int)) val = null;
if (val == null)
{
//if it's unknown don't include the nodeObjectType in the query
if (umbracoObjectType == UmbracoObjectTypes.Unknown)
using (var uow = _uowProvider.GetUnitOfWork())
{
val = uow.Database.ExecuteScalar<int?>("SELECT id FROM umbracoNode WHERE uniqueId=@id", new { id = key});
//if it's unknown don't include the nodeObjectType in the query
if (umbracoObjectType == UmbracoObjectTypes.Unknown)
{
val = uow.Database.ExecuteScalar<int?>("SELECT id FROM umbracoNode WHERE uniqueId=@id", new { id = key});
}
else
{
val = uow.Database.ExecuteScalar<int?>("SELECT id FROM umbracoNode WHERE uniqueId=@id AND (nodeObjectType=@type OR nodeObjectType=@reservation)",
new { id = key, type = GetNodeObjectTypeGuid(umbracoObjectType), reservation = Constants.ObjectTypes.IdReservationGuid });
}
uow.Commit();
}
else
{
val = uow.Database.ExecuteScalar<int?>("SELECT id FROM umbracoNode WHERE uniqueId=@id AND (nodeObjectType=@type OR nodeObjectType=@reservation)",
new { id = key, type = GetNodeObjectTypeGuid(umbracoObjectType), reservation = Constants.ObjectTypes.IdReservationGuid });
}
uow.Commit();
}
if (val == null) return Attempt<int>.Fail();
@@ -83,13 +227,23 @@ namespace Umbraco.Core.Services
return GetIdForKey(guidUdi.Guid, umbracoType);
}
public Attempt<Udi> GetUdiForId(int id, UmbracoObjectTypes umbracoObjectType)
{
var keyAttempt = GetKeyForId(id, umbracoObjectType);
return keyAttempt
? Attempt.Succeed<Udi>(new GuidUdi(Constants.UdiEntityType.FromUmbracoObjectType(umbracoObjectType), keyAttempt.Result))
: Attempt<Udi>.Fail();
}
public Attempt<Guid> GetKeyForId(int id, UmbracoObjectTypes umbracoObjectType)
{
TypedId<Guid> key;
bool empty;
try
{
_locker.EnterReadLock();
if (_id2Key.TryGetValue(id, out key) && key.UmbracoObjectType == umbracoObjectType) return Attempt.Succeed(key.Id);
if (_id2Key.TryGetValue(id, out var key) && key.UmbracoObjectType == umbracoObjectType) return Attempt.Succeed(key.Id);
empty = _id2Key.Count == 0;
}
finally
{
@@ -97,20 +251,37 @@ namespace Umbraco.Core.Services
_locker.ExitReadLock();
}
Guid? val;
using (var uow = _uowProvider.GetUnitOfWork())
#if POPULATE_FROM_DATABASE
// if cache is empty and looking for a document or a media,
// populate the cache at once and return what we found
if (empty && (umbracoObjectType == UmbracoObjectTypes.Document || umbracoObjectType == UmbracoObjectTypes.Media))
return PopulateAndGetKeyForId(id, umbracoObjectType);
#endif
// optimize for read speed: reading database outside a lock means that we could read
// multiple times, but we don't lock the cache while accessing the database = better
Guid? val = null;
if (_dictionary.TryGetValue(umbracoObjectType, out var mappers))
if ((val = mappers.id2key(id)) == default(Guid)) val = null;
if (val == null)
{
//if it's unknown don't include the nodeObjectType in the query
if (umbracoObjectType == UmbracoObjectTypes.Unknown)
using (var uow = _uowProvider.GetUnitOfWork())
{
val = uow.Database.ExecuteScalar<Guid?>("SELECT uniqueId FROM umbracoNode WHERE id=@id", new { id });
//if it's unknown don't include the nodeObjectType in the query
if (umbracoObjectType == UmbracoObjectTypes.Unknown)
{
val = uow.Database.ExecuteScalar<Guid?>("SELECT uniqueId FROM umbracoNode WHERE id=@id", new { id });
}
else
{
val = uow.Database.ExecuteScalar<Guid?>("SELECT uniqueId FROM umbracoNode WHERE id=@id AND (nodeObjectType=@type OR nodeObjectType=@reservation)",
new { id, type = GetNodeObjectTypeGuid(umbracoObjectType), reservation = Constants.ObjectTypes.IdReservationGuid });
}
uow.Commit();
}
else
{
val = uow.Database.ExecuteScalar<Guid?>("SELECT uniqueId FROM umbracoNode WHERE id=@id AND (nodeObjectType=@type OR nodeObjectType=@reservation)",
new { id, type = GetNodeObjectTypeGuid(umbracoObjectType), reservation = Constants.ObjectTypes.IdReservationGuid });
}
uow.Commit();
}
if (val == null) return Attempt<Guid>.Fail();
@@ -142,6 +313,8 @@ namespace Umbraco.Core.Services
return guid;
}
// invoked on UnpublishedPageCacheRefresher.RefreshAll
// anything else will use the id-specific overloads
public void ClearCache()
{
try
@@ -162,8 +335,7 @@ namespace Umbraco.Core.Services
try
{
_locker.EnterWriteLock();
TypedId<Guid> key;
if (_id2Key.TryGetValue(id, out key) == false) return;
if (_id2Key.TryGetValue(id, out var key) == false) return;
_id2Key.Remove(id);
_key2Id.Remove(key.Id);
}
@@ -179,8 +351,7 @@ namespace Umbraco.Core.Services
try
{
_locker.EnterWriteLock();
TypedId<int> id;
if (_key2Id.TryGetValue(key, out id) == false) return;
if (_key2Id.TryGetValue(key, out var id) == false) return;
_id2Key.Remove(id.Id);
_key2Id.Remove(key);
}
@@ -191,26 +362,28 @@ namespace Umbraco.Core.Services
}
}
// ReSharper disable ClassNeverInstantiated.Local
// ReSharper disable UnusedAutoPropertyAccessor.Local
private class TypedIdDto
{
public int Id { get; set; }
public Guid UniqueId { get; set; }
public Guid NodeObjectType { get; set; }
}
// ReSharper restore ClassNeverInstantiated.Local
// ReSharper restore UnusedAutoPropertyAccessor.Local
private struct TypedId<T>
{
private readonly T _id;
private readonly UmbracoObjectTypes _umbracoObjectType;
public T Id
{
get { return _id; }
}
public UmbracoObjectTypes UmbracoObjectType
{
get { return _umbracoObjectType; }
}
public TypedId(T id, UmbracoObjectTypes umbracoObjectType)
{
_umbracoObjectType = umbracoObjectType;
_id = id;
UmbracoObjectType = umbracoObjectType;
Id = id;
}
public UmbracoObjectTypes UmbracoObjectType { get; }
public T Id { get; }
}
}
}
}
+18 -24
View File
@@ -207,20 +207,17 @@ namespace Umbraco.Core.Services
{
return repository.GetByUsername(username, includeSecurityData: true);
}
catch (Exception ex)
catch (DbException ex)
{
if (ex is SqlException || ex is SqlCeException)
//we need to handle this one specific case which is when we are upgrading to 7.7 since the user group
//tables don't exist yet. This is the 'easiest' way to deal with this without having to create special
//version checks in the BackOfficeSignInManager and calling into other special overloads that we'd need
//like "GetUserById(int id, bool includeSecurityData)" which may cause confusion because the result of
//that method would not be cached.
if (ApplicationContext.Current.IsUpgrading)
{
//we need to handle this one specific case which is when we are upgrading to 7.7 since the user group
//tables don't exist yet. This is the 'easiest' way to deal with this without having to create special
//version checks in the BackOfficeSignInManager and calling into other special overloads that we'd need
//like "GetUserById(int id, bool includeSecurityData)" which may cause confusion because the result of
//that method would not be cached.
if (ApplicationContext.Current.IsUpgrading)
{
//NOTE: this will not be cached
return repository.GetByUsername(username, includeSecurityData: false);
}
//NOTE: this will not be cached
return repository.GetByUsername(username, includeSecurityData: false);
}
throw;
}
@@ -789,20 +786,17 @@ namespace Umbraco.Core.Services
var result = repository.Get(id);
return result;
}
catch (Exception ex)
catch (DbException ex)
{
if (ex is SqlException || ex is SqlCeException)
//we need to handle this one specific case which is when we are upgrading to 7.7 since the user group
//tables don't exist yet. This is the 'easiest' way to deal with this without having to create special
//version checks in the BackOfficeSignInManager and calling into other special overloads that we'd need
//like "GetUserById(int id, bool includeSecurityData)" which may cause confusion because the result of
//that method would not be cached.
if (ApplicationContext.Current.IsUpgrading)
{
//we need to handle this one specific case which is when we are upgrading to 7.7 since the user group
//tables don't exist yet. This is the 'easiest' way to deal with this without having to create special
//version checks in the BackOfficeSignInManager and calling into other special overloads that we'd need
//like "GetUserById(int id, bool includeSecurityData)" which may cause confusion because the result of
//that method would not be cached.
if (ApplicationContext.Current.IsUpgrading)
{
//NOTE: this will not be cached
return repository.Get(id, includeSecurityData: false);
}
//NOTE: this will not be cached
return repository.Get(id, includeSecurityData: false);
}
throw;
}
+4
View File
@@ -115,6 +115,9 @@
<Reference Include="System.Runtime.Caching" />
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Transactions" />
<Reference Include="System.ValueTuple, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.ValueTuple.4.4.0\lib\netstandard1.0\System.ValueTuple.dll</HintPath>
</Reference>
<Reference Include="System.Web" />
<Reference Include="System.Web.ApplicationServices" />
<Reference Include="System.Web.Extensions" />
@@ -603,6 +606,7 @@
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\NormalizeTemplateGuids.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\RemovePropertyDataIdIndex.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenSixZero\RemoveUmbracoDeployTables.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenTenZero\RenamePreviewFolder.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenThreeTwo\EnsureMigrationsTableIdentityIsCorrect.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenFourZero\EnsureContentTypeUniqueIdsAreConsistent.cs" />
<Compile Include="Persistence\Migrations\Upgrades\TargetVersionSevenThreeZero\AddExternalLoginsTable.cs" />
+1
View File
@@ -18,4 +18,5 @@
<package id="Owin" version="1.0" targetFramework="net45" />
<package id="semver" version="1.1.2" targetFramework="net45" />
<package id="SqlServerCE" version="4.0.0.1" targetFramework="net45" />
<package id="System.ValueTuple" version="4.4.0" targetFramework="net45" />
</packages>
@@ -139,8 +139,8 @@
<Reference Include="System.Threading.Thread, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Threading.Thread.4.3.0\lib\net46\System.Threading.Thread.dll</HintPath>
</Reference>
<Reference Include="System.ValueTuple, Version=4.0.1.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.ValueTuple.4.3.0\lib\netstandard1.0\System.ValueTuple.dll</HintPath>
<Reference Include="System.ValueTuple, Version=4.0.2.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.ValueTuple.4.4.0\lib\netstandard1.0\System.ValueTuple.dll</HintPath>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
+4
View File
@@ -62,6 +62,10 @@
<assemblyIdentity name="System.Xml.XPath.XDocument" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.2.0" newVersion="4.0.2.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
+1 -1
View File
@@ -51,7 +51,7 @@
<package id="System.Threading.Tasks.Extensions" version="4.3.0" targetFramework="net46" />
<package id="System.Threading.Tasks.Parallel" version="4.3.0" targetFramework="net46" />
<package id="System.Threading.Thread" version="4.3.0" targetFramework="net46" />
<package id="System.ValueTuple" version="4.3.0" targetFramework="net46" />
<package id="System.ValueTuple" version="4.4.0" targetFramework="net46" />
<package id="System.Xml.ReaderWriter" version="4.3.0" targetFramework="net46" />
<package id="System.Xml.XDocument" version="4.3.0" targetFramework="net46" />
<package id="System.Xml.XmlDocument" version="4.3.0" targetFramework="net46" />
+1 -3
View File
@@ -1,13 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Web.UI;
using umbraco;
using umbraco.BusinessLogic;
using umbraco.interfaces;
using Umbraco.Web.umbraco.presentation.umbraco.create;
namespace Umbraco.Tests.UI
{
-605
View File
@@ -1,605 +0,0 @@
module.exports = function (grunt) {
// Default task.
grunt.registerTask('default', ['jshint:dev', 'build', 'karma:unit']);
grunt.registerTask('dev', ['jshint:dev', 'build-dev', 'webserver', 'open:dev', 'watch']);
grunt.registerTask('docserve', ['docs:api', 'connect:docserver', 'open:docs', 'watch:docs']);
grunt.registerTask('vs', ['jshint:dev', 'build-dev', 'watch']);
//TODO: Too much watching, this brings windows to it's knees when in dev mode
//run by the watch task
grunt.registerTask('watch-js', ['jshint:dev', 'concat', 'copy:app', 'copy:mocks', 'copy:canvasdesigner', 'copy:vs', 'karma:unit']);
grunt.registerTask('watch-less', ['recess:build', 'recess:installer', 'recess:nonodes', 'recess:canvasdesigner', 'postcss', 'copy:canvasdesigner', 'copy:assets', 'copy:vs']);
grunt.registerTask('watch-html', ['copy:views', 'copy:vs']);
grunt.registerTask('watch-installer', ['concat:install', 'concat:installJs', 'copy:installer', 'copy:vs']);
grunt.registerTask('watch-canvasdesigner', ['copy:canvasdesigner', 'concat:canvasdesignerJs', 'copy:vs']);
grunt.registerTask('watch-test', ['jshint:dev', 'karma:unit']);
//triggered from grunt
grunt.registerTask('build', ['concat', 'recess:build', 'recess:installer', 'recess:nonodes', 'recess:canvasdesigner', 'postcss', 'bower-install-simple', 'bower', 'copy', 'clean:post']);
//triggered from grunt dev vs or grunt vs
grunt.registerTask('build-dev', ['clean:pre', 'concat', 'recess:build', 'recess:installer', 'recess:nonodes', 'postcss', 'bower-install-simple', 'bower', 'copy']);
//utillity tasks
grunt.registerTask('docs', ['ngdocs']);
grunt.registerTask('webserver', ['connect:devserver']);
// Print a timestamp (useful for when watching)
grunt.registerTask('timestamp', function () {
grunt.log.subhead(Date());
});
// Project configuration.
grunt.initConfig({
buildVersion: grunt.option('buildversion') || '7',
connect: {
devserver: {
options: {
port: 9990,
hostname: '0.0.0.0',
base: './build',
middleware: function(connect, options) {
return [
//uncomment to enable CSP
// util.csp(),
//util.rewrite(),
connect.favicon('images/favicon.ico'),
connect.static(options.base),
connect.directory(options.base)
];
}
}
},
testserver: {},
docserver: {
options: {
port: 8880,
hostname: '0.0.0.0',
base: './docs/api',
middleware: function(connect, options) {
return [
//uncomment to enable CSP
// util.csp(),
//util.rewrite(),
connect.static(options.base),
connect.directory(options.base)
];
}
}
},
},
open: {
dev: {
path: 'http://localhost:9990/belle/'
},
docs: {
path: 'http://localhost:8880/index.html'
}
},
distdir: 'build/belle',
vsdir: '../Umbraco.Web.UI/umbraco',
pkg: grunt.file.readJSON('package.json'),
banner:
'/*! <%= pkg.title || pkg.name %>\n' +
'<%= pkg.homepage ? " * " + pkg.homepage + "\\n" : "" %>' +
' * Copyright (c) <%= grunt.template.today("yyyy") %> <%= pkg.author %>;\n' +
' * Licensed <%= _.pluck(pkg.licenses, "type").join(", ") %>\n */\n',
src: {
js: ['src/**/*.js', 'src/*.js'],
common: ['src/common/**/*.js'],
controllers: ['src/**/*.controller.js'],
specs: ['test/**/*.spec.js'],
scenarios: ['test/**/*.scenario.js'],
samples: ['sample files/*.js'],
html: ['src/index.html', 'src/install.html'],
everything: ['src/**/*.*', 'test/**/*.*', 'docs/**/*.*'],
tpl: {
app: ['src/views/**/*.html'],
common: ['src/common/**/*.tpl.html']
},
less: ['src/less/belle.less'], // recess:build doesn't accept ** in its file patterns
prod: ['<%= distdir %>/js/*.js']
},
clean: {
pre: ['<%= distdir %>/*'],
post: ['<%= distdir %>/js/*.dev.js']
},
copy: {
assets: {
files: [{ dest: '<%= distdir %>/assets', src: '**', expand: true, cwd: 'src/assets/' }]
},
config: {
files: [{ dest: '<%= distdir %>/../config', src: '**', expand: true, cwd: 'src/config/' }]
},
installer: {
files: [{ dest: '<%= distdir %>/views/install', src: '**/*.html', expand: true, cwd: 'src/installer/steps' }]
},
canvasdesigner: {
files: [
{ dest: '<%= distdir %>/preview', src: '**/*.html', expand: true, cwd: 'src/canvasdesigner' },
{ dest: '<%= distdir %>/preview/editors', src: '**/*.html', expand: true, cwd: 'src/canvasdesigner/editors' },
{ dest: '<%= distdir %>/assets/less', src: '**/*.less', expand: true, cwd: 'src/canvasdesigner/editors' },
{ dest: '<%= distdir %>/js', src: 'canvasdesigner.config.js', expand: true, cwd: 'src/canvasdesigner/config' },
{ dest: '<%= distdir %>/js', src: 'canvasdesigner.palettes.js', expand: true, cwd: 'src/canvasdesigner/config' },
{ dest: '<%= distdir %>/js', src: 'canvasdesigner.front.js', expand: true, cwd: 'src/canvasdesigner' }
]
},
vendor: {
files: [{ dest: '<%= distdir %>/lib', src: '**', expand: true, cwd: 'lib/' }]
},
views: {
files: [{ dest: '<%= distdir %>/views', src: ['**/*.*', '!**/*.controller.js'], expand: true, cwd: 'src/views' }]
},
app: {
files: [
{ dest: '<%= distdir %>/js', src: '*.js', expand: true, cwd: 'src/' }
]
},
mocks: {
files: [{ dest: '<%= distdir %>/js', src: '*.js', expand: true, cwd: 'src/common/mocks/' }]
},
vs: {
files: [
//everything except the index.html root file!
//then we need to figure out how to not copy all the test stuff either!?
{ dest: '<%= vsdir %>/assets', src: '**', expand: true, cwd: '<%= distdir %>/assets' },
{ dest: '<%= vsdir %>/js', src: '**', expand: true, cwd: '<%= distdir %>/js' },
{ dest: '<%= vsdir %>/views', src: '**', expand: true, cwd: '<%= distdir %>/views' },
{ dest: '<%= vsdir %>/preview', src: '**', expand: true, cwd: '<%= distdir %>/preview' },
{ dest: '<%= vsdir %>/lib', src: '**', expand: true, cwd: '<%= distdir %>/lib' }
]
}
},
karma: {
unit: { configFile: 'test/config/karma.conf.js', keepalive: true },
e2e: { configFile: 'test/config/e2e.js', keepalive: true },
watch: { configFile: 'test/config/unit.js', singleRun: false, autoWatch: true, keepalive: true }
},
concat: {
index: {
src: ['src/index.html'],
dest: '<%= distdir %>/index.html',
options: {
process: true
}
},
install: {
src: ['src/installer/installer.html'],
dest: '<%= distdir %>/installer.html',
options: {
process: true
}
},
installJs: {
src: ['src/installer/**/*.js'],
dest: '<%= distdir %>/js/umbraco.installer.js',
options: {
banner: "<%= banner %>\n(function() { \n\n",
footer: "\n\n})();"
}
},
canvasdesignerJs: {
src: ['src/canvasdesigner/canvasdesigner.global.js', 'src/canvasdesigner/canvasdesigner.controller.js', 'src/canvasdesigner/editors/*.js', 'src/canvasdesigner/lib/*.js'],
dest: '<%= distdir %>/js/canvasdesigner.panel.js'
},
controllers: {
src: ['src/controllers/**/*.controller.js', 'src/views/**/*.controller.js'],
dest: '<%= distdir %>/js/umbraco.controllers.js',
options: {
banner: "<%= banner %>\n(function() { \n\n",
footer: "\n\n})();"
}
},
services: {
src: ['src/common/services/*.js'],
dest: '<%= distdir %>/js/umbraco.services.js',
options: {
banner: "<%= banner %>\n(function() { \n\n",
footer: "\n\n})();"
}
},
security: {
src: ['src/common/security/*.js'],
dest: '<%= distdir %>/js/umbraco.security.js',
options: {
banner: "<%= banner %>\n(function() { \n\n",
footer: "\n\n})();"
}
},
resources: {
src: ['src/common/resources/*.js'],
dest: '<%= distdir %>/js/umbraco.resources.js',
options: {
banner: "<%= banner %>\n(function() { \n\n",
footer: "\n\n})();"
}
},
testing: {
src: ['src/common/mocks/*/*.js'],
dest: '<%= distdir %>/js/umbraco.testing.js',
options: {
banner: "<%= banner %>\n(function() { \n\n",
footer: "\n\n})();"
}
},
directives: {
src: ['src/common/directives/**/*.js'],
dest: '<%= distdir %>/js/umbraco.directives.js',
options: {
banner: "<%= banner %>\n(function() { \n\n",
footer: "\n\n})();"
}
},
filters: {
src: ['src/common/filters/*.js'],
dest: '<%= distdir %>/js/umbraco.filters.js',
options: {
banner: "<%= banner %>\n(function() { \n\n",
footer: "\n\n})();"
}
}
},
uglify: {
options: {
mangle: true
},
combine: {
files: {
'<%= distdir %>/js/umbraco.min.js': ['<%= distdir %>/js/umbraco.*.js']
}
}
},
recess: {
build: {
files: {
'<%= distdir %>/assets/css/<%= pkg.name %>.css':
['<%= src.less %>']
},
options: {
compile: true,
compress: true
}
},
nonodes: {
files: {
'<%= distdir %>/assets/css/nonodes.style.min.css':
['src/less/pages/nonodes.less']
},
options: {
compile: true,
compress: true
}
},
installer: {
files: {
'<%= distdir %>/assets/css/installer.css':
['src/less/installer.less']
},
options: {
compile: true,
compress: true
}
},
canvasdesigner: {
files: {
'<%= distdir %>/assets/css/canvasdesigner.css':
['src/less/canvas-designer.less', 'src/less/helveticons.less']
},
options: {
compile: true,
compress: true
}
}
},
postcss: {
options: {
processors: [
// add vendor prefixes
require('autoprefixer-core')({
browsers: 'last 2 versions'
})
]
},
dist: {
src: '<%= distdir %>/assets/css/<%= pkg.name %>.css'
}
},
ngTemplateCache: {
views: {
files: {
'<%= distdir %>/js/umbraco.views.js': 'src/views/**/*.html'
},
options: {
trim: 'src/',
module: 'umbraco.views'
}
}
},
watch: {
docs: {
files: ['docs/src/**/*.md'],
tasks: ['watch-docs', 'timestamp']
},
css: {
files: 'src/**/*.less',
tasks: ['watch-less', 'timestamp'],
options: {
livereload: true,
},
},
js: {
files: ['src/**/*.js', 'src/*.js'],
tasks: ['watch-js', 'timestamp'],
},
test: {
files: ['test/**/*.js'],
tasks: ['watch-test', 'timestamp'],
},
installer: {
files: ['src/installer/**/*.*'],
tasks: ['watch-installer', 'timestamp'],
},
canvasdesigner: {
files: ['src/canvasdesigner/**/*.*'],
tasks: ['watch-canvasdesigner', 'timestamp'],
},
html: {
files: ['src/views/**/*.html', 'src/*.html'],
tasks: ['watch-html', 'timestamp']
},
options: {
interval: 500
}
},
ngdocs: {
options: {
dest: 'docs/api',
startPage: '/api',
title: "Umbraco Backoffice UI API Documentation",
html5Mode: false,
styles: [
'docs/umb-docs.css'
],
image: "https://our.umbraco.org/assets/images/logo.svg"
},
api: {
src: ['src/common/**/*.js', 'docs/src/api/**/*.ngdoc'],
title: 'API Documentation'
},
tutorials: {
src: [],
title: ''
}
},
eslint:{
src: ['<%= src.common %>','<%= src.controllers %>'],
options: {quiet: true}
},
jshint: {
dev: {
files: {
src: ['<%= src.common %>']
},
options: {
curly: true,
eqeqeq: true,
immed: true,
latedef: "nofunc",
newcap: true,
noarg: true,
sub: true,
boss: true,
//NOTE: This is required so it doesn't barf on reserved words like delete when doing $http.delete
es5: true,
eqnull: true,
//NOTE: we need to use eval sometimes so ignore it
evil: true,
//NOTE: we need to check for strings such as "javascript:" so don't throw errors regarding those
scripturl: true,
//NOTE: we ignore tabs vs spaces because enforcing that causes lots of errors depending on the text editor being used
smarttabs: true,
globals: {}
}
},
build: {
files: {
src: ['<%= src.prod %>']
},
options: {
curly: true,
eqeqeq: true,
immed: true,
latedef: "nofunc",
newcap: true,
noarg: true,
sub: true,
boss: true,
//NOTE: This is required so it doesn't barf on reserved words like delete when doing $http.delete
es5: true,
eqnull: true,
//NOTE: we need to use eval sometimes so ignore it
evil: true,
//NOTE: we need to check for strings such as "javascript:" so don't throw errors regarding those
scripturl: true,
//NOTE: we ignore tabs vs spaces because enforcing that causes lots of errors depending on the text editor being used
smarttabs: true,
globalstrict: true,
globals: { $: false, jQuery: false, define: false, require: false, window: false }
}
}
},
bower: {
dev: {
dest: '<%= distdir %>/lib',
options: {
expand: true,
ignorePackages: ['bootstrap'],
packageSpecific: {
'moment': {
keepExpandedHierarchy: false,
files: ['min/moment-with-locales.js']
},
'typeahead.js': {
keepExpandedHierarchy: false,
files: ['dist/typeahead.bundle.min.js']
},
'underscore': {
files: ['underscore-min.js', 'underscore-min.map']
},
'rgrove-lazyload': {
files: ['lazyload.js']
},
'bootstrap-social': {
files: ['bootstrap-social.css']
},
'font-awesome': {
files: ['css/font-awesome.min.css', 'fonts/*']
},
"jquery": {
keepExpandedHierarchy: false,
files: ['dist/jquery.min.js', 'dist/jquery.min.map']
},
'jquery-ui': {
keepExpandedHierarchy: false,
files: ['jquery-ui.min.js']
},
'jquery-migrate': {
keepExpandedHierarchy: false,
files: ['jquery-migrate.min.js']
},
'tinymce': {
files: ['plugins/**', 'themes/**', 'tinymce.min.js']
},
'angular-dynamic-locale': {
files: ['tmhDynamicLocale.min.js', 'tmhDynamicLocale.min.js.map']
},
'ng-file-upload': {
keepExpandedHierarchy: false,
files: ['ng-file-upload.min.js']
},
'angular-local-storage': {
keepExpandedHierarchy: false,
files: ['dist/angular-local-storage.min.js']
},
'codemirror': {
files: [
'lib/codemirror.js',
'lib/codemirror.css',
'mode/css/*',
'mode/javascript/*',
'mode/xml/*',
'mode/htmlmixed/*',
'addon/search/*',
'addon/edit/*',
'addon/selection/*',
'addon/dialog/*'
]
},
'ace-builds': {
files: [
'src-min-noconflict/ace.js',
'src-min-noconflict/ext-language_tools.js',
'src-min-noconflict/ext-searchbox.js',
'src-min-noconflict/ext-settings_menu.js',
'src-min-noconflict/snippets/text.js',
'src-min-noconflict/snippets/javascript.js',
'src-min-noconflict/theme-chrome.js',
'src-min-noconflict/mode-razor.js',
'src-min-noconflict/mode-javascript.js',
'src-min-noconflict/worker-javascript.js',
]
},
'clipboard': {
keepExpandedHierarchy: false,
files: ['dist/clipboard.min.js']
},
'angular-moment': {
keepExpandedHierarchy: false,
files: ['angular-moment.min.js']
}
}
}
},
options: {
expand: true
}
},
"bower-install-simple": {
options: {
color: true
},
"dev": {}
}
});
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-copy');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-recess');
grunt.loadNpmTasks('grunt-postcss');
grunt.loadNpmTasks('grunt-karma');
grunt.loadNpmTasks('grunt-open');
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks("grunt-bower-install-simple");
grunt.loadNpmTasks('grunt-bower');
grunt.loadNpmTasks('grunt-ngdocs');
grunt.loadNpmTasks('grunt-eslint');
grunt.loadNpmTasks('grunt-hustler');
};
+1 -3
View File
@@ -73,7 +73,6 @@ var sources = {
js: {
preview: { files: ["src/canvasdesigner/**/*.js"], out: "umbraco.canvasdesigner.js" },
installer: { files: ["src/installer/**/*.js"], out: "umbraco.installer.js" },
controllers: { files: ["src/{views,controllers}/**/*.controller.js"], out: "umbraco.controllers.js" },
directives: { files: ["src/common/directives/**/*.js"], out: "umbraco.directives.js" },
filters: { files: ["src/common/filters/**/*.js"], out: "umbraco.filters.js" },
@@ -85,8 +84,7 @@ var sources = {
//selectors for copying all views into the build
//processed in the views task
views:{
umbraco: {files: ["src/views/**/*html"], folder: ""},
preview: { files: ["src/canvasdesigner/**/*.html"], folder: "../preview"},
umbraco: {files: ["src/views/**/*.html"], folder: ""},
installer: {files: ["src/installer/steps/*.html"], folder: "install"}
},
+6 -6
View File
@@ -27,9 +27,9 @@
"gulp": "^3.9.1",
"gulp-concat": "^2.6.0",
"gulp-connect": "5.0.0",
"gulp-less": "^3.1.0",
"gulp-less": "^3.5.0",
"gulp-ngdocs": "^0.3.0",
"gulp-open": "^2.0.0",
"gulp-open": "^2.1.0",
"gulp-postcss": "^6.2.0",
"gulp-rename": "^1.2.2",
"gulp-sort": "^2.0.0",
@@ -38,11 +38,11 @@
"gulp-wrap-js": "^0.4.1",
"jasmine-core": "2.5.2",
"karma": "^1.7.0",
"karma-jasmine": "^1.1.0",
"karma-jasmine": "^1.1.1",
"karma-phantomjs-launcher": "^1.0.4",
"less": "^2.6.1",
"lodash": "^4.16.3",
"less": "^2.7.3",
"lodash": "^4.17.5",
"merge-stream": "^1.0.1",
"run-sequence": "^2.1.0"
"run-sequence": "^2.2.1"
}
}
@@ -1,3 +0,0 @@
<div class="box-slider">
<div colorpicker ng-model="item.values.color"></div>
</div>
@@ -255,11 +255,9 @@
else {
$scope.save().then(function (data) {
previewWindow.location.href = redirect;
});
});
}
}
};
$scope.restore = function (content) {
@@ -8,6 +8,8 @@
var evts = [];
var isInfoTab = false;
scope.publishStatus = {};
scope.disableTemplates = Umbraco.Sys.ServerVariables.features.disabledFeatures.disableTemplates;
function onInit() {
@@ -145,6 +145,12 @@ angular.module("umbraco.directives")
}
}
}
if (val === "true") {
tinyMceConfig.customConfig[i] = true;
}
if (val === "false") {
tinyMceConfig.customConfig[i] = false;
}
}
angular.extend(baseLineConfigObj, tinyMceConfig.customConfig);
@@ -59,7 +59,6 @@
</pre>
<h1>General Options</h1>
Lorem ipsum dolor sit amet..
<table>
<thead>
<tr>
@@ -74,7 +73,7 @@ Lorem ipsum dolor sit amet..
<td>Set the title of the overlay.</td>
</tr>
<tr>
<td>model.subTitle</td>
<td>model.subtitle</td>
<td>String</td>
<td>Set the subtitle of the overlay.</td>
</tr>
@@ -496,6 +495,7 @@ Opens an overlay to show a custom YSOD. </br>
var activeElementType = document.activeElement.tagName;
var clickableElements = ["A", "BUTTON"];
var submitOnEnter = document.activeElement.hasAttribute("overlay-submit-on-enter");
var submitOnEnterValue = submitOnEnter ? document.activeElement.getAttribute("overlay-submit-on-enter") : "";
if(clickableElements.indexOf(activeElementType) === 0) {
document.activeElement.click();
@@ -503,7 +503,9 @@ Opens an overlay to show a custom YSOD. </br>
} else if(activeElementType === "TEXTAREA" && !submitOnEnter) {
} else {
} else if (submitOnEnter && submitOnEnterValue === "false") {
// don't do anything
}else {
scope.$apply(function () {
scope.submitForm(scope.model);
});
@@ -1,7 +1,7 @@
(function () {
'use strict';
"use strict";
function javascriptLibraryHelperService($q, $http, umbRequestHelper) {
function javascriptLibraryService($q, $http, umbRequestHelper) {
var existingLocales = [];
@@ -14,7 +14,7 @@
umbRequestHelper.getApiUrl(
"backOfficeAssetsApiBaseUrl",
"GetSupportedMomentLocales")),
'Failed to get cultures').then(function(locales) {
"Failed to get cultures").then(function(locales) {
existingLocales = locales;
deferred.resolve(existingLocales);
});
@@ -30,11 +30,8 @@
};
return service;
}
angular.module('umbraco.services').factory('javascriptLibraryHelperService', javascriptLibraryHelperService);
angular.module("umbraco.services").factory("javascriptLibraryService", javascriptLibraryService);
})();
@@ -1,5 +1,5 @@
angular.module('umbraco.services')
.factory('userService', function ($rootScope, eventsService, $q, $location, $log, securityRetryQueue, authResource, assetsService, dialogService, $timeout, angularHelper, $http, javascriptLibraryHelperService) {
.factory('userService', function ($rootScope, eventsService, $q, $location, $log, securityRetryQueue, authResource, assetsService, dialogService, $timeout, angularHelper, $http, javascriptLibraryService) {
var currentUser = null;
var lastUserId = null;
@@ -304,10 +304,10 @@ angular.module('umbraco.services')
var promises = {
currentUser: this.getCurrentUser(),
supportedLocales: javascriptLibraryHelperService.getSupportedLocalesForMoment()
supportedLocales: javascriptLibraryService.getSupportedLocalesForMoment()
}
$q.all(promises).then((values) => {
$q.all(promises).then(function (values) {
loadLocales(values.currentUser, values.supportedLocales);
});
@@ -168,6 +168,9 @@
//used for property editors
@import "property-editors.less";
//used for prevalue editors
@import "components/prevalues/multivalues.less";
@import "typeahead.less";
@import "hacks.less";
@@ -175,4 +178,4 @@
@import "healthcheck.less";
// cleanup properties.less when it is done
@import "properties.less";
@import "properties.less";
@@ -0,0 +1,53 @@
.umb-prevalues-multivalues {
width: 400px;
}
.umb-prevalues-multivalues__left {
display: flex;
flex: 1 1 auto;
}
.umb-prevalues-multivalues__right {
display: flex;
flex: 0 0 auto;
align-items: center;
}
.umb-prevalues-multivalues__add {
display: flex;
}
.umb-prevalues-multivalues__add input {
width: 320px;
}
.umb-prevalues-multivalues__add input {
display: flex;
}
.umb-prevalues-multivalues__add button {
margin: 0 6px 0 0;
float: right
}
.umb-prevalues-multivalues__listitem {
display: flex;
padding: 6px;
margin: 10px 0px !important;
background: #F3F3F5;
cursor: move;
}
.umb-prevalues-multivalues__listitem i {
display: flex;
align-items: center;
margin-right: 5px
}
.umb-prevalues-multivalues__listitem a {
cursor: pointer;
}
.umb-prevalues-multivalues__listitem input {
width: 295px;
}
@@ -280,7 +280,6 @@
.umb-grid .umb-control {
position: relative;
display: block;
overflow: hidden;
margin-left: 10px;
margin-right: 10px;
margin-bottom: 10px;
@@ -40,6 +40,16 @@
padding: 10px;
}
.umb-contentpicker__min-max-help {
font-size: 13px;
margin-top: 5px;
color: @gray-4;
}
.show-validation .umb-contentpicker__min-max-help {
display: none;
}
.umb-contentpicker small {
&:not(:last-child) {
@@ -109,22 +119,22 @@ ul.color-picker li a {
}
/* pre-value editor */
/*.control-group.color-picker-preval:before {
content: "";
display: inline-block;
vertical-align: middle;
height: 100%;
}*/
/*.control-group.color-picker-preval div.thumbnail {
display: inline-block;
/*.control-group.color-picker-preval:before {
content: "";
display: inline-block;
vertical-align: middle;
}*/
.control-group.color-picker-preval div.color-picker-prediv {
display: inline-block;
height: 100%;
}*/
/*.control-group.color-picker-preval div.thumbnail {
display: inline-block;
vertical-align: middle;
}*/
.control-group.color-picker-preval div.color-picker-prediv {
display: inline-block;
width: 60%;
}
}
.control-group.color-picker-preval pre {
display: inline;
margin-right: 20px;
@@ -136,18 +146,18 @@ ul.color-picker li a {
vertical-align: middle;
}
.control-group.color-picker-preval btn {
.control-group.color-picker-preval btn {
//vertical-align: middle;
}
}
.control-group.color-picker-preval input[type="text"] {
min-width: 40%;
width: 40%;
display: inline-block;
margin-right: 20px;
.control-group.color-picker-preval input[type="text"] {
min-width: 40%;
width: 40%;
display: inline-block;
margin-right: 20px;
margin-top: 1px;
}
}
.control-group.color-picker-preval label {
border: solid @white 1px;
padding: 6px;
@@ -203,10 +213,22 @@ ul.color-picker li a {
.umb-thumbnails{
position: relative;
.umb-thumbnails {
position: relative;
display: flex;
-ms-flex-direction: row;
-webkit-flex-direction: row;
flex-direction: row;
-ms-flex-wrap: wrap;
-webkit-flex-wrap: wrap;
flex-wrap: wrap;
justify-content: flex-start;
}
.umb-thumbnails > li.icon {
width: 14%;
text-align: center;
}
.umb-thumbnails i{margin: auto;}
.umb-thumbnails a{
@@ -100,6 +100,27 @@
.color-green, .color-green i{color: @green-d1 !important;}
.color-yellow, .color-yellow i{color: @yellow-d1 !important;}
/* Colors based on http://zavoloklom.github.io/material-design-color-palette/colors.html */
.color-black, .color-black i { color: #000 !important; }
.color-blue-grey, .color-blue-grey i { color: #607d8b !important; }
.color-grey, .color-grey i { color: #9e9e9e !important; }
.color-brown, .color-brown i { color: #795548 !important; }
.color-blue, .color-blue i { color: #2196f3 !important; }
.color-light-blue, .color-light-blue i {color: #03a9f4 !important; }
.color-cyan, .color-cyan i { color: #00bcd4 !important; }
.color-green, .color-green i { color: #4caf50 !important; }
.color-light-green, .color-light-green i {color: #8bc34a !important; }
.color-lime, .color-lime i { color: #cddc39 !important; }
.color-yellow, .color-yellow i { color: #ffeb3b !important; }
.color-amber, .color-amber i { color: #ffc107 !important; }
.color-orange, .color-orange i { color: #ff9800 !important; }
.color-deep-orange, .color-deep-orange i { color: #ff5722 !important; }
.color-red, .color-red i { color: #f44336 !important; }
.color-pink, .color-pink i { color: #e91e63 !important; }
.color-purple,.color-purple i { color: #9c27b0 !important; }
.color-deep-purple, .color-deep-purple i { color: #673ab7 !important; }
.color-indigo, .color-indigo i { color: #3f51b5 !important; }
// Scaffolding
// -------------------------
@@ -7,14 +7,13 @@ angular.module("umbraco")
$scope.icons = icons;
});
$scope.submitClass = function (icon) {
$scope.submitClass = function(icon){
if($scope.color) {
$scope.submit(icon + " " + $scope.color);
}
else {
$scope.submit(icon);
else {
$scope.submit(icon);
}
};
}
);
@@ -16,24 +16,25 @@
<div class="umb-control-group">
<select ng-model="color" class="input-block-level">
<option value="">
<localize key="colors_black">Black</localize>
</option>
<option value="color-green">
<localize key="colors_green">Green</localize>
</option>
<option value="color-yellow">
<localize key="colors_yellow">Yellow</localize>
</option>
<option value="color-orange">
<localize key="colors_orange">Orange</localize>
</option>
<option value="color-blue">
<localize key="colors_blue">Blue</localize>
</option>
<option value="color-red">
<localize key="colors_red">Red</localize>
</option>
<option value=""><localize key="colors_black">Black</localize></option>
<option value="color-blue-grey"><localize key="colors_bluegrey">Blue Grey</localize></option>
<option value="color-grey"><localize key="colors_grey">Grey</localize></option>
<option value="color-brown"><localize key="colors_brown">Brown</localize></option>
<option value="color-blue"><localize key="colors_blue">Blue</localize></option>
<option value="color-light-blue"><localize key="colors_lightblue">Light Blue</localize></option>
<option value="color-cyan"><localize key="colors_cyan">Cyan</localize></option>
<option value="color-green"><localize key="colors_green">Green</localize></option>
<option value="color-light-green"><localize key="colors_lightgreen">Light Green</localize></option>
<option value="color-yellow"><localize key="colors_yellow">Yellow</localize></option>
<option value="color-lime"><localize key="colors_lime">Lime</localize></option>
<option value="color-amber"><localize key="colors_amber">Amber</localize></option>
<option value="color-orange"><localize key="colors_orange">Orange</localize></option>
<option value="color-deep-orange"><localize key="colors_deeporange">Deep Orange</localize></option>
<option value="color-red"><localize key="colors_red">Red</localize></option>
<option value="color-pink"><localize key="colors_pink">Pink</localize></option>
<option value="color-purple"><localize key="colors_purple">Purple</localize></option>
<option value="color-deep-purple"><localize key="colors_deeppurple">Deep Purple</localize></option>
<option value="color-indigo"><localize key="colors_indigo">Indigo</localize></option>
</select>
</div>
@@ -171,27 +171,25 @@
{{publishStatus.label}}
</umb-badge>
</umb-control-group>
<umb-control-group data-element="node-info-create-date" label="@template_createdDate">
{{node.createDateFormatted}} <localize key="general_by">by</localize> {{ node.owner.name }}
</umb-control-group>
<umb-control-group data-element="node-info-document-type" label="@content_documentType">
<umb-node-preview
style="max-width: 100%; margin-bottom: 0;"
icon="documentType.icon"
name="documentType.name"
allow-open="allowOpen"
on-open="openDocumentType(documentType)">
<umb-node-preview style="max-width: 100%; margin-bottom: 0;"
icon="documentType.icon"
name="documentType.name"
allow-open="allowOpen"
on-open="openDocumentType(documentType)">
</umb-node-preview>
</umb-control-group>
<umb-control-group data-element="node-info-template" label="@template_template">
<select
class="input-block-level"
ng-model="node.template"
ng-options="key as value for (key, value) in availableTemplates"
ng-change="updateTemplate(node.template)">
<umb-control-group ng-if="disableTemplates == false" data-element="node-info-template" label="@template_template">
<select class="input-block-level"
ng-model="node.template"
ng-options="key as value for (key, value) in availableTemplates"
ng-change="updateTemplate(node.template)">
<option value=""><localize key="general_choose">Choose</localize>...</option>
</select>
</umb-control-group>
@@ -200,7 +198,7 @@
<div>{{ node.id }}</div>
<small>{{ node.key }}</small>
</umb-control-group>
</umb-box-content>
</umb-box>
</div>
@@ -47,7 +47,17 @@
</a>
</div>
<div class="umb-table-cell" ng-repeat="column in itemProperties">
<span title="{{column.header}}: {{item[column.alias]}}">{{item[column.alias]}}</span>
<span title="{{column.header}}: {{item[column.alias]}}">
<div ng-if="!column.isSensitive">
{{item[column.alias]}}
</div>
<em ng-show="column.isSensitive" class="muted">
<localize key="content_isSensitiveValue_short"></localize>
</em>
</span>
</div>
</div>
</div>
@@ -14,18 +14,21 @@ function DocumentTypesCreateController($scope, $location, navigationService, con
creatingFolder: false,
};
var disableTemplates = Umbraco.Sys.ServerVariables.features.disabledFeatures.disableTemplates;
$scope.model.disableTemplates = disableTemplates;
var node = $scope.dialogOptions.currentNode,
localizeCreateFolder = localizationService.localize("defaultdialog_createFolder");
$scope.showCreateFolder = function() {
$scope.showCreateFolder = function () {
$scope.model.creatingFolder = true;
};
$scope.createContainer = function() {
$scope.createContainer = function () {
if (formHelper.submitForm({scope: $scope, formCtrl: this.createFolderForm, statusMessage: localizeCreateFolder})) {
if (formHelper.submitForm({ scope: $scope, formCtrl: this.createFolderForm, statusMessage: localizeCreateFolder })) {
contentTypeResource.createContainer(node.id, $scope.model.folderName).then(function(folderId) {
contentTypeResource.createContainer(node.id, $scope.model.folderName).then(function (folderId) {
navigationService.hideMenu();
@@ -44,7 +47,7 @@ function DocumentTypesCreateController($scope, $location, navigationService, con
var section = appState.getSectionState("currentSection");
}, function(err) {
}, function (err) {
$scope.error = err;
@@ -58,14 +61,17 @@ function DocumentTypesCreateController($scope, $location, navigationService, con
}
};
$scope.createDocType = function() {
$location.search('create', null);
$location.search('notemplate', null);
$location.path("/settings/documenttypes/edit/" + node.id).search("create", "true");
navigationService.hideMenu();
};
// Disabling logic for creating document type with template if disableTemplates is set to true
if (!disableTemplates) {
$scope.createDocType = function () {
$location.search('create', null);
$location.search('notemplate', null);
$location.path("/settings/documenttypes/edit/" + node.id).search("create", "true");
navigationService.hideMenu();
};
}
$scope.createComponent = function() {
$scope.createComponent = function () {
$location.search('create', null);
$location.search('notemplate', null);
$location.path("/settings/documenttypes/edit/" + node.id).search("create", "true").search("notemplate", "true");
@@ -4,7 +4,7 @@
<h5><localize key="create_createUnder">Create an item under</localize> {{currentNode.name}}</h5>
<ul class="umb-actions umb-actions-child">
<li data-element="action-documentType">
<li data-element="action-documentType" ng-hide="model.disableTemplates">
<a href="" ng-click="createDocType()" umb-auto-focus>
<i class="large icon-item-arrangement"></i>
@@ -15,10 +15,14 @@
</a>
</li>
<li data-element="action-documentTypeWithoutTemplate">
<a href="" ng-click="createComponent()">
<i class="large icon-item-arrangement"></i>
<span class="menu-label"><localize key="create_documentTypeWithoutTemplate"></localize></span>
</a>
<a href="" ng-click="createComponent()">
<i class="large icon-item-arrangement"></i>
<span class="menu-label">
<localize ng-if="model.disableTemplates == false" key="create_documentTypeWithoutTemplate"></localize>
<localize ng-if="model.disableTemplates == true" key="content_documentType">Document type></localize>
</span>
</a>
</li>
<li data-element="action-folder" ng-if="model.allowCreateFolder">
<a href="" ng-click="showCreateFolder()">
@@ -33,7 +37,7 @@
<form novalidate name="createFolderForm"
ng-submit="createContainer()"
val-form-manager>
<div ng-show="error">
<h5 class="text-error">{{error.errorMsg}}</h5>
<p class="text-error">{{error.data.message}}</p>
@@ -15,6 +15,36 @@
var localizeSaving = localizationService.localize("general_saving");
var evts = [];
var disableTemplates = Umbraco.Sys.ServerVariables.features.disabledFeatures.disableTemplates;
var buttons = [
{
"name": localizationService.localize("general_design"),
"alias": "design",
"icon": "icon-document-dashed-line",
"view": "views/documenttypes/views/design/design.html",
"active": true
},
{
"name": localizationService.localize("general_listView"),
"alias": "listView",
"icon": "icon-list",
"view": "views/documenttypes/views/listview/listview.html"
},
{
"name": localizationService.localize("general_rights"),
"alias": "permissions",
"icon": "icon-keychain",
"view": "views/documenttypes/views/permissions/permissions.html"
},
{
"name": localizationService.localize("treeHeaders_templates"),
"alias": "templates",
"icon": "icon-layout",
"view": "views/documenttypes/views/templates/templates.html"
}
];
vm.save = save;
vm.currentNode = null;
@@ -23,97 +53,73 @@
vm.page = {};
vm.page.loading = false;
vm.page.saveButtonState = "init";
vm.page.navigation = [
{
"name": localizationService.localize("general_design"),
"alias": "design",
"icon": "icon-document-dashed-line",
"view": "views/documenttypes/views/design/design.html",
"active": true
},
{
"name": localizationService.localize("general_listView"),
"alias": "listView",
"icon": "icon-list",
"view": "views/documenttypes/views/listview/listview.html"
},
{
"name": localizationService.localize("general_rights"),
"alias": "permissions",
"icon": "icon-keychain",
"view": "views/documenttypes/views/permissions/permissions.html"
},
{
"name": localizationService.localize("treeHeaders_templates"),
"alias": "templates",
"icon": "icon-layout",
"view": "views/documenttypes/views/templates/templates.html"
}
];
vm.page.navigation = [];
loadButtons();
vm.page.keyboardShortcutsOverview = [
{
"name": localizationService.localize("main_sections"),
"shortcuts": [
{
"description": localizationService.localize("shortcuts_navigateSections"),
"keys": [{ "key": "1" }, { "key": "4" }],
"keyRange": true
}
]
},
{
"name": localizationService.localize("general_design"),
"shortcuts": [
{
"description": localizationService.localize("shortcuts_addTab"),
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "t" }]
},
{
"description": localizationService.localize("shortcuts_addProperty"),
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "p" }]
},
{
"description": localizationService.localize("shortcuts_addEditor"),
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "e" }]
},
{
"description": localizationService.localize("shortcuts_editDataType"),
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "d" }]
}
]
},
{
"name": localizationService.localize("general_listView"),
"shortcuts": [
{
"description": localizationService.localize("shortcuts_toggleListView"),
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "l" }]
}
]
},
{
"name": localizationService.localize("general_rights"),
"shortcuts": [
{
"description": localizationService.localize("shortcuts_toggleAllowAsRoot"),
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "r" }]
},
{
"description": localizationService.localize("shortcuts_addChildNode"),
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "c" }]
}
]
},
{
"name": localizationService.localize("treeHeaders_templates"),
"shortcuts": [
{
"description": localizationService.localize("shortcuts_addTemplate"),
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "t" }]
}
]
}
{
"name": localizationService.localize("main_sections"),
"shortcuts": [
{
"description": localizationService.localize("shortcuts_navigateSections"),
"keys": [{ "key": "1" }, { "key": "4" }],
"keyRange": true
}
]
},
{
"name": localizationService.localize("general_design"),
"shortcuts": [
{
"description": localizationService.localize("shortcuts_addTab"),
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "t" }]
},
{
"description": localizationService.localize("shortcuts_addProperty"),
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "p" }]
},
{
"description": localizationService.localize("shortcuts_addEditor"),
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "e" }]
},
{
"description": localizationService.localize("shortcuts_editDataType"),
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "d" }]
}
]
},
{
"name": localizationService.localize("general_listView"),
"shortcuts": [
{
"description": localizationService.localize("shortcuts_toggleListView"),
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "l" }]
}
]
},
{
"name": localizationService.localize("general_rights"),
"shortcuts": [
{
"description": localizationService.localize("shortcuts_toggleAllowAsRoot"),
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "r" }]
},
{
"description": localizationService.localize("shortcuts_addChildNode"),
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "c" }]
}
]
},
{
"name": localizationService.localize("treeHeaders_templates"),
"shortcuts": [
{
"description": localizationService.localize("shortcuts_addTemplate"),
"keys": [{ "key": "alt" }, { "key": "shift" }, { "key": "t" }]
}
]
}
];
contentTypeHelper.checkModelsBuilderStatus().then(function (result) {
@@ -144,7 +150,7 @@
vm.page.saveButtonState = "busy";
localizationService.localize("modelsBuilder_buildingModels").then(function (headerValue) {
localizationService.localize("modelsBuilder_waitingMessage").then(function(msgValue) {
localizationService.localize("modelsBuilder_waitingMessage").then(function (msgValue) {
notificationsService.info(headerValue, msgValue);
});
});
@@ -155,26 +161,26 @@
if (!result.lastError) {
//re-check model status
contentTypeHelper.checkModelsBuilderStatus().then(function(statusResult) {
contentTypeHelper.checkModelsBuilderStatus().then(function (statusResult) {
vm.page.modelsBuilder = statusResult;
});
//clear and add success
vm.page.saveButtonState = "init";
localizationService.localize("modelsBuilder_modelsGenerated").then(function(value) {
localizationService.localize("modelsBuilder_modelsGenerated").then(function (value) {
notificationsService.success(value);
});
} else {
vm.page.saveButtonState = "error";
localizationService.localize("modelsBuilder_modelsExceptionInUlog").then(function(value) {
localizationService.localize("modelsBuilder_modelsExceptionInUlog").then(function (value) {
notificationsService.error(value);
});
}
}, function () {
vm.page.saveButtonState = "error";
localizationService.localize("modelsBuilder_modelsGeneratedError").then(function(value) {
localizationService.localize("modelsBuilder_modelsGeneratedError").then(function (value) {
notificationsService.error(value);
});
});
@@ -189,7 +195,7 @@
//we are creating so get an empty data type item
contentTypeResource.getScaffold($routeParams.id)
.then(function(dt) {
.then(function (dt) {
init(dt);
vm.page.loading = false;
});
@@ -207,12 +213,26 @@
});
}
function loadButtons() {
angular.forEach(buttons,
function (val, index) {
if (disableTemplates === true && val.alias === "templates") {
buttons.splice(index, 1);
}
});
vm.page.navigation = buttons;
}
/* ---------- SAVE ---------- */
function save() {
// only save if there is no overlays open
if(overlayHelper.getNumberOfOverlays() === 0) {
if (overlayHelper.getNumberOfOverlays() === 0) {
var deferred = $q.defer();
@@ -233,7 +253,7 @@
// we need to rebind... the IDs that have been created!
rebindCallback: function (origContentType, savedContentType) {
vm.contentType.id = savedContentType.id;
vm.contentType.groups.forEach(function(group) {
vm.contentType.groups.forEach(function (group) {
if (!group.name) return;
var k = 0;
while (k < savedContentType.groups.length && savedContentType.groups[k].name != group.name)
@@ -273,7 +293,7 @@
}
else {
localizationService.localize("speechBubbles_validationFailedHeader").then(function (headerValue) {
localizationService.localize("speechBubbles_validationFailedMessage").then(function(msgValue) {
localizationService.localize("speechBubbles_validationFailedMessage").then(function (msgValue) {
notificationsService.error(headerValue, msgValue);
});
});
@@ -331,7 +351,7 @@
function getDataTypeDetails(property) {
if (property.propertyState !== "init") {
dataTypeResource.getById(property.dataTypeId)
.then(function(dataType) {
.then(function (dataType) {
property.dataTypeIcon = dataType.icon;
property.dataTypeName = dataType.name;
});
@@ -345,7 +365,7 @@
});
}
evts.push(eventsService.on("app.refreshEditor", function(name, error) {
evts.push(eventsService.on("app.refreshEditor", function (name, error) {
loadDocumentType();
}));
@@ -0,0 +1,4 @@
angular.module("umbraco").controller("Umbraco.PrevalueEditors.BooleanController",
function ($scope) {
$scope.htmlId = "bool-" + String.CreateGuid();
});
@@ -1 +1,4 @@
<input name="boolean" type="checkbox" ng-model="model.value" ng-true-value="1" ng-false-value="0" />
<label ng-controller="Umbraco.PrevalueEditors.BooleanController" for="{{htmlId}}" class="checkbox">
<input name="boolean" type="checkbox" ng-model="model.value" ng-true-value="1" ng-false-value="0" id="{{htmlId}}" />
<localize key="general_yes">Yes</localize>
</label>
@@ -5,6 +5,7 @@ angular.module("umbraco").controller("Umbraco.PrevalueEditors.MultiValuesControl
$scope.newItem = "";
$scope.hasError = false;
$scope.focusOnNew = false;
if (!angular.isArray($scope.model.value)) {
@@ -43,6 +44,7 @@ angular.module("umbraco").controller("Umbraco.PrevalueEditors.MultiValuesControl
$scope.model.value.push({ value: $scope.newItem });
$scope.newItem = "";
$scope.hasError = false;
$scope.focusOnNew = true;
return;
}
}
@@ -73,6 +75,12 @@ angular.module("umbraco").controller("Umbraco.PrevalueEditors.MultiValuesControl
}
};
$scope.createNew = function (event) {
if (event.keyCode == 13) {
$scope.add(event);
}
}
function getElementIndexByPrevalueText(value) {
for (var i = 0; i < $scope.model.value.length; i++) {
if ($scope.model.value[i].value === value) {
@@ -1,13 +1,21 @@
<div class="umb-editor" ng-controller="Umbraco.PrevalueEditors.MultiValuesController">
<div class="control-group">
<input name="newItem" type="text" ng-model="newItem" val-highlight="{{hasError}}" />
<button class="btn" ng-click="add($event)">Add</button>
<div class="umb-editor umb-prevalues-multivalues" ng-controller="Umbraco.PrevalueEditors.MultiValuesController">
<div class="control-group umb-prevalues-multivalues__add">
<div class="umb-prevalues-multivalues__left">
<input overlay-submit-on-enter="false" name="newItem" focus-when="{{focusOnNew}}" ng-keydown="createNew($event)" type="text" ng-model="newItem" val-highlight="{{hasError}}" />
</div>
<div class="umb-prevalues-multivalues__right">
<button class="btn btn-info" ng-click="add($event)">Add</button>
</div>
</div>
<div ui-sortable="sortableOptions">
<div class="control-group" ng-repeat="item in model.value">
<div class="control-group umb-prevalues-multivalues__listitem" ng-repeat="item in model.value">
<i class="icon icon-navigation handle"></i>
<input type="text" ng-model="item.value" val-server="item_{{$index}}" required />
<button class="btn btn-danger" ng-click="remove(item, $event)">Remove</button>
<div class="umb-prevalues-multivalues__left">
<input type="text" ng-model="item.value" val-server="item_{{$index}}" required />
</div>
<div class="umb-prevalues-multivalues__right">
<a class="umb-node-preview__action" ng-click="remove(item, $event)">Remove</a>
</div>
</div>
</div>
</div>
@@ -20,7 +20,7 @@
</umb-node-preview>
</div>
<a ng-show="model.config.multiPicker === true || renderModel.length === 0"
<a ng-show="model.config.multiPicker === true && renderModel.length < model.config.maxNumber || renderModel.length === 0 || !model.config.maxNumber"
class="umb-node-preview-add"
href=""
ng-click="openContentPicker()"
@@ -28,6 +28,39 @@
<localize key="general_add">Add</localize>
</a>
<div class="umb-contentpicker__min-max-help">
<!-- Both min and max items -->
<span ng-if="model.config.minNumber && model.config.maxNumber && model.config.minNumber !== model.config.maxNumber">
<span ng-if="renderModel.length < model.config.maxNumber">Add between {{model.config.minNumber}} and {{model.config.maxNumber}} items</span>
<span ng-if="renderModel.length > model.config.maxNumber">
<localize key="validation_maxCount">You can only have</localize> {{model.config.maxNumber}} <localize key="validation_itemsSelected"> items selected</localize>
</span>
</span>
<!-- Equal min and max -->
<span ng-if="model.config.minNumber && model.config.maxNumber && model.config.minNumber === model.config.maxNumber">
<span ng-if="renderModel.length < model.config.maxNumber">Add {{model.config.minNumber - renderModel.length}} item(s)</span>
<span ng-if="renderModel.length > model.config.maxNumber">
<localize key="validation_maxCount">You can only have</localize> {{model.config.maxNumber}} <localize key="validation_itemsSelected"> items selected</localize>
</span>
</span>
<!-- Only max -->
<span ng-if="!model.config.minNumber && model.config.maxNumber">
<span ng-if="renderModel.length < model.config.maxNumber">Add up to {{model.config.maxNumber}} items</span>
<span ng-if="renderModel.length > model.config.maxNumber">
<localize key="validation_maxCount">You can only have</localize> {{model.config.maxNumber}} <localize key="validation_itemsSelected">items selected</localize>
</span>
</span>
<!-- Only min -->
<span ng-if="model.config.minNumber && !model.config.maxNumber && renderModel.length < model.config.minNumber">
Add at least {{model.config.minNumber}} item(s)
</span>
</div>
<!--These are here because we need ng-form fields to validate against-->
<input type="hidden" name="minCount" ng-model="renderModel" />
<input type="hidden" name="maxCount" ng-model="renderModel" />
@@ -0,0 +1,81 @@
angular.module("umbraco").controller("Umbraco.PropertyEditors.DropdownFlexibleController",
function($scope) {
//setup the default config
var config = {
items: [],
multiple: false
};
//map the user config
angular.extend(config, $scope.model.config);
//map back to the model
$scope.model.config = config;
function convertArrayToDictionaryArray(model){
//now we need to format the items in the dictionary because we always want to have an array
var newItems = [];
for (var i = 0; i < model.length; i++) {
newItems.push({ id: model[i], sortOrder: 0, value: model[i] });
}
return newItems;
}
function convertObjectToDictionaryArray(model){
//now we need to format the items in the dictionary because we always want to have an array
var newItems = [];
var vals = _.values($scope.model.config.items);
var keys = _.keys($scope.model.config.items);
for (var i = 0; i < vals.length; i++) {
var label = vals[i].value ? vals[i].value : vals[i];
newItems.push({ id: keys[i], sortOrder: vals[i].sortOrder, value: label });
}
return newItems;
}
$scope.updateSingleDropdownValue = function() {
$scope.model.value = [$scope.model.singleDropdownValue];
}
if (angular.isArray($scope.model.config.items)) {
//PP: I dont think this will happen, but we have tests that expect it to happen..
//if array is simple values, convert to array of objects
if(!angular.isObject($scope.model.config.items[0])){
$scope.model.config.items = convertArrayToDictionaryArray($scope.model.config.items);
}
}
else if (angular.isObject($scope.model.config.items)) {
$scope.model.config.items = convertObjectToDictionaryArray($scope.model.config.items);
}
else {
throw "The items property must be either an array or a dictionary";
}
//sort the values
$scope.model.config.items.sort(function (a, b) { return (a.sortOrder > b.sortOrder) ? 1 : ((b.sortOrder > a.sortOrder) ? -1 : 0); });
//now we need to check if the value is null/undefined, if it is we need to set it to "" so that any value that is set
// to "" gets selected by default
if ($scope.model.value === null || $scope.model.value === undefined) {
if ($scope.model.config.multiple) {
$scope.model.value = [];
}
else {
$scope.model.value = "";
}
}
// if we run in single mode we'll store the value in a local variable
// so we can pass an array as the model as our PropertyValueEditor expects that
$scope.model.singleDropdownValue = "";
if ($scope.model.config.multiple === "0") {
$scope.model.singleDropdownValue = Array.isArray($scope.model.value) ? $scope.model.value[0] : $scope.model.value;
}
});
@@ -0,0 +1,19 @@
<div ng-controller="Umbraco.PropertyEditors.DropdownFlexibleController" ng-switch="model.config.multiple">
<select name="dropDownList"
class="umb-editor umb-dropdown"
ng-switch-default
ng-change="updateSingleDropdownValue()"
ng-model="model.singleDropdownValue"
ng-options="item.id as item.value for item in model.config.items">
<option></option>
</select>
<!--NOTE: This ng-switch is required because ng-multiple doesn't actually support dynamic bindings with multi-select lists -->
<select name="dropDownList"
class="umb-editor umb-dropdown"
ng-switch-when="1"
multiple
ng-model="model.value"
ng-options="item.id as item.value for item in model.config.items"></select>
</div>
@@ -30,15 +30,14 @@
vm.dragLeave = dragLeave;
vm.onFilesQueue = onFilesQueue;
vm.onUploadComplete = onUploadComplete;
markAsSensitive();
function activate() {
if ($scope.entityType === 'media') {
mediaTypeHelper.getAllowedImagetypes(vm.nodeId).then(function (types) {
vm.acceptedMediatypes = types;
});
}
}
function selectAll($event) {
@@ -87,6 +86,27 @@
$scope.getContent($scope.contentId);
}
function markAsSensitive() {
angular.forEach($scope.options.includeProperties, function (option) {
option.isSensitive = false;
angular.forEach($scope.items,
function (item) {
angular.forEach(item.properties,
function (property) {
if (option.alias === property.alias) {
option.isSensitive = property.isSensitive;
}
});
});
});
}
activate();
}
@@ -46,6 +46,7 @@ function MarkdownEditorController($scope, $element, assetsService, dialogService
// init the md editor after this digest because the DOM needs to be ready first
// so run the init on a timeout
$timeout(function () {
$scope.markdownEditorInitComplete = false;
var converter2 = new Markdown.Converter();
var editor2 = new Markdown.Editor(converter2, "-" + $scope.model.alias);
editor2.run();
@@ -59,7 +60,12 @@ function MarkdownEditorController($scope, $element, assetsService, dialogService
editor2.hooks.set("onPreviewRefresh", function () {
// We must manually update the model as there is no way to hook into the markdown editor events without exstensive edits to the library.
if ($scope.model.value !== $("textarea", $element).val()) {
angularHelper.getCurrentForm($scope).$setDirty();
if ($scope.markdownEditorInitComplete) {
//only set dirty after init load to avoid "unsaved" dialogue when we don't want it
angularHelper.getCurrentForm($scope).$setDirty();
} else {
$scope.markdownEditorInitComplete = true;
}
$scope.model.value = $("textarea", $element).val();
}
});
@@ -185,6 +185,12 @@ angular.module("umbraco")
//cannot parse, we'll just leave it
}
}
if (val === "true") {
tinyMceConfig.customConfig[i] = true;
}
if (val === "false") {
tinyMceConfig.customConfig[i] = false;
}
}
}
@@ -359,7 +365,8 @@ angular.module("umbraco")
//this is instead of doing a watch on the model.value = faster
$scope.model.onValueChanged = function (newVal, oldVal) {
//update the display val again if it has changed from the server;
tinyMceEditor.setContent(newVal, { format: 'raw' });
//uses an empty string in the editor when the value is null
tinyMceEditor.setContent(newVal || "", { format: 'raw' });
//we need to manually fire this event since it is only ever fired based on loading from the DOM, this
// is required for our plugins listening to this event to execute
tinyMceEditor.fire('LoadContent', null);
@@ -92,7 +92,6 @@
$scope.model.config.ticksPositions = _.map($scope.model.config.ticksPositions.split(','), function (item) {
return parseInt(item.trim());
});
console.log($scope.model.config.ticksPositions);
}
if (!$scope.model.config.ticksLabels) {
@@ -215,4 +214,4 @@
assetsService.loadCss("lib/slider/bootstrap-slider.css");
assetsService.loadCss("lib/slider/bootstrap-slider-custom.css");
}
angular.module("umbraco").controller("Umbraco.PropertyEditors.SliderController", sliderController);
angular.module("umbraco").controller("Umbraco.PropertyEditors.SliderController", sliderController);
+15 -3
View File
@@ -837,6 +837,19 @@
<Content Include="Views\Partials\Grid\Editors\Base.cshtml" />
<Content Include="Views\Partials\Grid\Bootstrap3-Fluid.cshtml" />
<Content Include="Views\Partials\Grid\Bootstrap2-Fluid.cshtml" />
<Content Include="Umbraco\Views\Preview\Background.cshtml" />
<Content Include="Umbraco\Views\Preview\Border.cshtml" />
<Content Include="Umbraco\Views\Preview\Color.cshtml" />
<Content Include="Umbraco\Views\Preview\Googlefontpicker.cshtml" />
<Content Include="Umbraco\Views\Preview\GridRow.cshtml" />
<Content Include="Umbraco\Views\Preview\Index.cshtml" />
<Content Include="Umbraco\Views\Preview\Layout.cshtml" />
<Content Include="Umbraco\Views\Preview\Margin.cshtml" />
<Content Include="Umbraco\Views\Preview\Padding.cshtml" />
<Content Include="Umbraco\Views\Preview\Radius.cshtml" />
<Content Include="Umbraco\Views\Preview\Shadow.cshtml" />
<Content Include="Umbraco\Views\Preview\Slider.cshtml" />
<Content Include="Umbraco\Views\Preview\web.config" />
<None Include="Web.Debug.config.transformed" />
<None Include="web.Template.Debug.config">
<DependentUpon>Web.Template.config</DependentUpon>
@@ -994,7 +1007,6 @@
</ItemGroup>
<ItemGroup>
<Folder Include="App_Data\" />
<Folder Include="Umbraco\preview\" />
<Folder Include="Views\MacroPartials\" />
</ItemGroup>
<ItemGroup>
@@ -1023,9 +1035,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\"
<WebProjectProperties>
<UseIIS>True</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>7920</DevelopmentServerPort>
<DevelopmentServerPort>7100</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:7920</IISUrl>
<IISUrl>http://localhost:7100</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
@@ -1,4 +1,4 @@

@inherits System.Web.Mvc.WebViewPage
<div ng-controller="Umbraco.canvasdesigner.background">
<div class="box-slider">
@@ -1,4 +1,4 @@

@inherits System.Web.Mvc.WebViewPage
<div ng-controller="Umbraco.canvasdesigner.border" class="bordereditor">
<div class="box-slider">
@@ -17,4 +17,4 @@
<div ui-slider min="0" max="40" step="1" ng-model="selectedBorder.size"></div>
</div>
</div>
</div>
@@ -0,0 +1,4 @@
@inherits System.Web.Mvc.WebViewPage
<div class="box-slider">
<div colorpicker ng-model="item.values.color"></div>
</div>
@@ -1,4 +1,4 @@

@inherits System.Web.Mvc.WebViewPage
<div ng-controller="Umbraco.canvasdesigner.googlefontpicker">
<div class="box-slider">
@@ -1,8 +1,8 @@

@inherits System.Web.Mvc.WebViewPage
<div ng-controller="Umbraco.canvasdesigner.gridRow">
<div class="box-slider">
<input type="checkbox" ng-model="item.values.fullsize" /><label>Full size</label>
</div>
</div>
</div>
@@ -1,4 +1,9 @@
<!DOCTYPE html>
@using System.Web.Mvc.Html
@inherits System.Web.Mvc.WebViewPage<Umbraco.Web.Models.ContentEditing.BackOfficePreview>
@{
var disableDevicePreview = Model.DisableDevicePreview.ToString().ToLowerInvariant();
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>Umbraco Canvas Designer</title>
@@ -6,27 +11,25 @@
<link href="../lib/spectrum/spectrum.css" type="text/css" rel="stylesheet" />
<link href="../lib/jquery-ui/jquery-ui-1.10.4.custom.min.css" type="text/css" rel="stylesheet" />
</head>
<body id="canvasdesignerPanel" ng-mouseover="outlinePositionHide()" ng-class="{ leftOpen: (showStyleEditor || showPalettePicker) && !showDevicesPreview }" ng-controller="Umbraco.canvasdesignerController">
<div class="wait" ng-show="!frameLoaded"></div>
@if (string.IsNullOrWhiteSpace(Model.PreviewExtendedHeaderView) == false)
{
@Html.Partial(Model.PreviewExtendedHeaderView)
}
<div id="demo-iframe-wrapper" ng-show="frameLoaded" class="{{previewDevice.css}}">
<iframe id="resultFrame" ng-src="{{pageUrl}}" frameborder="0" iframe-is-loaded></iframe>
</div>
<div class="canvasdesigner" ng-init="showDevicesPreview = true; showPalettePicker = true" ng-mouseenter="positionSelectedHide()">
<div class="canvasdesigner" ng-init="showDevicesPreview = true; showDevices = !@(disableDevicePreview); showPalettePicker = true" ng-mouseenter="positionSelectedHide()">
<div class="fix-left-menu selected">
<div class="avatar">
<img
ng-src="../assets/img/application/logo.png"
ng-srcset="../assets/img/application/logo@2x.png 2x,
<img ng-src="../assets/img/application/logo.png"
ng-srcset="../assets/img/application/logo@2x.png 2x,
../assets/img/application/logo@3x.png 3x" />
</div>
<ul class="sections" ng-class="{selected: showDevicesPreview}">
<ul class="sections" ng-class="{selected: showDevicesPreview && showDevices}">
<li ng-repeat="device in devices" ng-class="{ current:previewDevice==device }" ng-click="updatePreviewDevice(device)">
<a href="#"><i class="icon {{device.icon}}" title="{{device.title}}"></i><span></span></a>
</li>
@@ -39,9 +42,8 @@
</li>
<li ng-click="exitPreview()">
<a href="#" title="Exit Preview"><i class="icon icon-wrong"></i><span> </span></a>
</li>
</li>
</ul>
<ul class="sections" ng-class="{selected: !showDevicesPreview}" ng-if="enableCanvasdesigner > 0">
<li ng-click="openPreviewDevice()">
<a href="#"><i class="icon {{previewDevice.icon}}"></i><span>Preview</span></a>
@@ -53,15 +55,11 @@
<a href="#"><i class="icon icon-paint-roller"></i><span>UI Designer</span></a>
</li>
</ul>
</div>
<div class="main-panel" ng-class="{selected: !showDevicesPreview && ( showPalettePicker || showStyleEditor )}">
<div class="header">
<h3>Palette Style</h3>
</div>
<div class="content">
<ul class="samples">
<li ng-repeat="palette in canvasdesignerPalette">
@@ -78,7 +76,6 @@
</li>
</ul>
</div>
<div class="btn-group">
<a class="btn btn-success" ng-click="saveStyle()">Save Style</a>
<a class="btn btn-success dropdown-toggle" ng-click="opendropdown = !opendropdown">
@@ -90,11 +87,8 @@
<li><a ng-click="makePreset();opendropdown = false">Make preset</a></li>
</ul>
</div>
</div>
<div class="main-panel" ng-class="{selected: !showDevicesPreview && showStyleEditor}">
<div ng-show="!currentSelected">
<div class="header">
<h3>Select</h3>
@@ -112,7 +106,6 @@
</ul>
</div>
</div>
<div ng-repeat="configItem in canvasdesignerModel.configs" ng-show="currentSelected && currentSelected.name.toLowerCase() == configItem.name.toLowerCase()
&& currentSelected.schema.toLowerCase() == configItem.schema.toLowerCase()" on-finish-render-filters>
<div class="header">
@@ -134,7 +127,6 @@
</div>
</div>
</div>
<div class="btn-group">
<a class="btn btn-success" ng-click="saveStyle()">Save Style</a>
<a class="btn btn-success dropdown-toggle" ng-click="opendropdown = !opendropdown">
@@ -146,20 +138,13 @@
<li><a ng-click="makePreset();opendropdown = false">Make preset</a></li>
</ul>
</div>
</div>
<div class="float-panel"></div>
</div>
<div id="speechbubble">
<p>Styles saved and published</p>
</div>
<script src="../lib/rgrove-lazyload/lazyload.js"></script>
<script src="../js/canvasdesigner.loader.js"></script>
</body>
</html>
@@ -1,4 +1,4 @@

@inherits System.Web.Mvc.WebViewPage
<div ng-controller="Umbraco.canvasdesigner.layout">
<div class="box-slider">
@@ -7,4 +7,4 @@
<input type="radio" ng-model="item.values.layout" value="full"> Full
</div>
</div>
</div>
@@ -1,7 +1,7 @@

@inherits System.Web.Mvc.WebViewPage
<div ng-controller="Umbraco.canvasdesigner.margin">
<div class="box-slider">
<div class="box-slider">
<ul class="box-preview">
<li ng-repeat="margin in marginList" class="border-{{margin}}" ng-class="{selected: selectedmargin.name == margin}" ng-click="setSelectedmargin(margin)"></li>
</ul>
@@ -11,4 +11,4 @@
<div ui-slider min="0" max="400" step="1" ng-model="selectedmargin.value"></div>
</div>
</div>
</div>
@@ -1,4 +1,4 @@

@inherits System.Web.Mvc.WebViewPage
<div ng-controller="Umbraco.canvasdesigner.padding">
<div class="box-slider">
@@ -11,4 +11,4 @@
<div ui-slider min="0" max="400" step="1" ng-model="selectedpadding.value"></div>
</div>
</div>
</div>
@@ -1,9 +1,9 @@

@inherits System.Web.Mvc.WebViewPage
<div ng-controller="Umbraco.canvasdesigner.radius">
<div class="box-slider">
<ul class="box-preview">
<li ng-repeat="radius in radiusList" ng-class="{selected: selectedradius.name == radius}" ng-click="setSelectedradius(radius)">
<span ng-show="radius == 'topleft' || radius == 'all'" class="radius-top-left"></span>
<span ng-show="radius == 'topright' || radius == 'all'" class="radius-top-right"></span>
@@ -18,4 +18,4 @@
<div ui-slider min="0" max="40" step="1" ng-model="selectedradius.value"></div>
</div>
</div>
</div>
@@ -1,8 +1,8 @@

@inherits System.Web.Mvc.WebViewPage
<div ng-controller="Umbraco.canvasdesigner.shadow">
<div class="box-slider">
<div ui-slider min="0" max="100" step="1" ng-model="item.values.shadow"></div>
</div>
</div>
</div>
@@ -1,8 +1,8 @@

@inherits System.Web.Mvc.WebViewPage
<div ng-controller="Umbraco.canvasdesigner.slider">
<div class="box-slider">
<div ui-slider min="{{item.min}}" max="{{item.max}}" step="1" ng-model="item.values.slider"></div>
</div>
</div>
</div>
@@ -0,0 +1,41 @@
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
</sectionGroup>
</configSections>
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
</namespaces>
</pages>
</system.web.webPages.razor>
<appSettings>
<add key="webpages:Enabled" value="false" />
</appSettings>
<system.webServer>
<handlers>
<remove name="BlockViewHandler"/>
<add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
</handlers>
</system.webServer>
<system.web>
<compilation>
<assemblies>
<add assembly="System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
</assemblies>
</compilation>
</system.web>
</configuration>
@@ -661,7 +661,7 @@
<area alias="graphicheadline">
<key alias="backgroundcolor">Baggrundsfarve</key>
<key alias="bold">Fed</key>
<key alias="color">Tekst farve</key>
<key alias="color">Tekstfarve</key>
<key alias="font">Skrifttype</key>
<key alias="text">Tekst</key>
</area>
@@ -1259,9 +1259,9 @@ Mange hilsner fra Umbraco robotten
<key alias="styles">Typografi</key>
<key alias="stylesDetails">Vælg, hvilke typografiværdier, en redaktør kan ændre</key>
<key alias="stylesDetails">Vælg hvilke typografiværdier en redaktør kan ændre</key>
<key alias="settingDialogDetails">Indstillinger gemmes kun, hvis den indtaste json-konfiguration er gyldig</key>
<key alias="settingDialogDetails">Indstillinger gemmes kun, hvis den indtastede json-konfiguration er gyldig</key>
<key alias="allowAllEditors">Tillad alle editorer</key>
<key alias="allowAllRowConfigurations">Tillad alle rækkekonfigurationer</key>
@@ -1272,7 +1272,7 @@ Mange hilsner fra Umbraco robotten
<key alias="areAdded">er tilføjet</key>
<key alias="maxItems">Maksimalt emner</key>
<key alias="maxItemsDescription">Efterlad blank eller sat til 0 ubegrænset for</key>
<key alias="maxItemsDescription">Efterlad blank eller sæt til 0 for ubegrænset</key>
</area>
<area alias="contentTypeEditor">
@@ -1282,7 +1282,7 @@ Mange hilsner fra Umbraco robotten
<key alias="addNewTab">Tilføj ny fane</key>
<key alias="addAnotherTab">Tilføj endnu en fane</key>
<key alias="inheritedFrom">Nedarvet fra</key>
<key alias="addProperty">Tilføj property</key>
<key alias="addProperty">Tilføj egenskab</key>
<key alias="requiredLabel">Påkrævet label</key>
<key alias="enableListViewHeading">Aktiver listevisning</key>
@@ -1473,7 +1473,6 @@ Mange hilsner fra Umbraco robotten
<key alias="noLogin">har endnu ikke logget ind</key>
<key alias="oldPassword">Gammelt kodeord</key>
<key alias="password">Adgangskode</key>
<key alias="removePhoto">Fjern billede</key>
<key alias="resetPassword">Nulstil kodeord</key>
<key alias="passwordChanged">Dit kodeord er blevet ændret!</key>
<key alias="passwordConfirm">Bekræft venligst dit nye kodeord</key>
@@ -229,6 +229,7 @@
<key alias="removeTextBox">Remove this text box</key>
<key alias="contentRoot">Content root</key>
<key alias="isSensitiveValue">This value is hidden. If you need access to view this value please contact your website administrator.</key>
<key alias="isSensitiveValue_short">This value is hidden.</key>
</area>
<area alias="blueprints">
<key alias="createBlueprintFrom">Create a new Content Template from '%0%'</key>
@@ -662,7 +663,20 @@
<key alias="yellow">Yellow</key>
<key alias="orange">Orange</key>
<key alias="blue">Blue</key>
<key alias="bluegrey">Blue Grey</key>
<key alias="grey">Grey</key>
<key alias="brown">Brown</key>
<key alias="lightblue">Light Blue</key>
<key alias="cyan">Cyan</key>
<key alias="lightgreen">Light Green</key>
<key alias="lime">Lime</key>
<key alias="amber">Amber</key>
<key alias="deeporange">Deep Orange</key>
<key alias="red">Red</key>
<key alias="pink">Pink</key>
<key alias="purple">Purple</key>
<key alias="deeppurple">Deep Purple</key>
<key alias="indigo">Indigo</key>
</area>
<area alias="shortcuts">
@@ -229,6 +229,7 @@
<key alias="removeTextBox">Remove this text box</key>
<key alias="contentRoot">Content root</key>
<key alias="isSensitiveValue">This value is hidden. If you need access to view this value please contact your website administrator.</key>
<key alias="isSensitiveValue_short">This value is hidden.</key>
</area>
<area alias="blueprints">
<key alias="createBlueprintFrom">Create a new Content Template from '%0%'</key>
@@ -660,7 +661,20 @@
<key alias="yellow">Yellow</key>
<key alias="orange">Orange</key>
<key alias="blue">Blue</key>
<key alias="bluegrey">Blue Grey</key>
<key alias="grey">Grey</key>
<key alias="brown">Brown</key>
<key alias="lightblue">Light Blue</key>
<key alias="cyan">Cyan</key>
<key alias="lightgreen">Light Green</key>
<key alias="lime">Lime</key>
<key alias="amber">Amber</key>
<key alias="deeporange">Deep Orange</key>
<key alias="red">Red</key>
<key alias="pink">Pink</key>
<key alias="purple">Purple</key>
<key alias="deeppurple">Deep Purple</key>
<key alias="indigo">Indigo</key>
</area>
<area alias="shortcuts">
<key alias="addTab">Add tab</key>
+3 -2
View File
@@ -155,7 +155,8 @@ namespace Umbraco.Web.Cache
foreach (var payload in payloads)
{
ApplicationContext.Current.Services.IdkMap.ClearCache(payload.Id);
if (payload.Operation == OperationType.Deleted)
ApplicationContext.Current.Services.IdkMap.ClearCache(payload.Id);
var mediaCache = ApplicationContext.Current.ApplicationCache.IsolatedRuntimeCache.GetCache<IMedia>();
@@ -190,4 +191,4 @@ namespace Umbraco.Web.Cache
}
}
}
}
}
@@ -84,7 +84,6 @@ namespace Umbraco.Web.Cache
public override void Refresh(int id)
{
ApplicationContext.Current.Services.IdkMap.ClearCache(id);
ClearRepositoryCacheItemById(id);
ClearAllIsolatedCacheByEntityType<PublicAccessEntry>();
content.Instance.UpdateSortOrder(id);
@@ -104,7 +103,6 @@ namespace Umbraco.Web.Cache
public override void Refresh(IContent instance)
{
ApplicationContext.Current.Services.IdkMap.ClearCache(instance.Id);
ClearRepositoryCacheItemById(instance.Id);
ClearAllIsolatedCacheByEntityType<PublicAccessEntry>();
content.Instance.UpdateSortOrder(instance);
@@ -150,4 +148,4 @@ namespace Umbraco.Web.Cache
}
}
}
}
}
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;
using Umbraco.Core.IO;
@@ -13,16 +14,15 @@ namespace Umbraco.Web.Editors
[HttpGet]
public IEnumerable<string> GetSupportedMomentLocales()
{
var momentLocaleFolder = "moment";
const string momentLocaleFolder = "moment";
var fileSystem = FileSystemProviderManager.Current.JavaScriptLibraryFileSystem;
var cultures = fileSystem.GetFiles(momentLocaleFolder, "*.js").ToList();
for (var i = 0; i < cultures.Count(); i++)
for (var i = 0; i < cultures.Count; i++)
{
cultures[i] = cultures[i]
.Substring(cultures[i].IndexOf(momentLocaleFolder) + momentLocaleFolder.Length + 1);
.Substring(cultures[i].IndexOf(momentLocaleFolder, StringComparison.Ordinal) + momentLocaleFolder.Length + 1);
}
return cultures;
}
}
}
@@ -13,6 +13,7 @@ using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
using Umbraco.Web.Features;
using Umbraco.Web.HealthCheck;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Mvc;
@@ -52,7 +53,8 @@ namespace Umbraco.Web.Editors
{"umbracoUrls", new[] {"authenticationApiBaseUrl", "serverVarsJs", "externalLoginsUrl", "currentUserApiBaseUrl"}},
{"umbracoSettings", new[] {"allowPasswordReset", "imageFileTypes", "maxFileSize", "loginBackgroundImage"}},
{"application", new[] {"applicationPath", "cacheBuster"}},
{"isDebuggingEnabled", new string[] { }}
{"isDebuggingEnabled", new string[] { }},
{"features", new [] {"disabledFeatures"}}
};
//now do the filtering...
var defaults = GetServerVariables();
@@ -81,7 +83,7 @@ namespace Umbraco.Web.Editors
//TODO: This is ultra confusing! this same key is used for different things, when returning the full app when authenticated it is this URL but when not auth'd it's actually the ServerVariables address
// so based on compat and how things are currently working we need to replace the serverVarsJs one
((Dictionary<string, object>) defaults["umbracoUrls"])["serverVarsJs"] = _urlHelper.Action("ServerVariables", "BackOffice");
((Dictionary<string, object>)defaults["umbracoUrls"])["serverVarsJs"] = _urlHelper.Action("ServerVariables", "BackOffice");
return defaults;
}
@@ -332,6 +334,18 @@ namespace Umbraco.Web.Editors
.ToArray()
}
}
},
{
"features", new Dictionary<string,object>
{
{
"disabledFeatures", new Dictionary<string,object>
{
{ "disableTemplates", FeaturesResolver.Current.Features.Disabled.DisableTemplates}
}
}
}
}
};
return defaultVals;
@@ -356,9 +370,9 @@ namespace Umbraco.Web.Editors
.ToArray();
return (from p in pluginTreesWithAttributes
let treeAttr = p.attributes.OfType<TreeAttribute>().Single()
let pluginAttr = p.attributes.OfType<PluginControllerAttribute>().Single()
select new Dictionary<string, string>
let treeAttr = p.attributes.OfType<TreeAttribute>().Single()
let pluginAttr = p.attributes.OfType<PluginControllerAttribute>().Single()
select new Dictionary<string, string>
{
{"alias", treeAttr.Alias}, {"packageFolder", pluginAttr.AreaName}
}).ToArray();
+21 -30
View File
@@ -1,29 +1,18 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Reflection;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;
using System.Web.Http.ModelBinding;
using System.Web.Security;
using AutoMapper;
using Examine.LuceneEngine.SearchCriteria;
using Examine.SearchCriteria;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Security;
using Umbraco.Core.Services;
@@ -33,10 +22,7 @@ using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Mvc;
using Umbraco.Web.WebApi.Binders;
using Umbraco.Web.WebApi.Filters;
using umbraco;
using Constants = Umbraco.Core.Constants;
using Examine;
using Newtonsoft.Json;
namespace Umbraco.Web.Editors
{
@@ -96,16 +82,18 @@ namespace Umbraco.Web.Editors
if (MembershipScenario == MembershipScenario.NativeUmbraco)
{
long totalRecords;
var members = Services.MemberService
.GetAll((pageNumber - 1), pageSize, out totalRecords, orderBy, orderDirection, orderBySystemField, memberTypeAlias, filter).ToArray();
.GetAll((pageNumber - 1), pageSize, out var totalRecords, orderBy, orderDirection, orderBySystemField, memberTypeAlias, filter).ToArray();
if (totalRecords == 0)
{
return new PagedResult<MemberBasic>(0, 0, 0);
}
var pagedResult = new PagedResult<MemberBasic>(totalRecords, pageNumber, pageSize);
pagedResult.Items = members
.Select(Mapper.Map<IMember, MemberBasic>);
var pagedResult = new PagedResult<MemberBasic>(totalRecords, pageNumber, pageSize)
{
Items = members
.Select(x => AutoMapperExtensions.MapWithUmbracoContext<IMember, MemberBasic>(x, UmbracoContext))
};
return pagedResult;
}
else
@@ -133,10 +121,13 @@ namespace Umbraco.Web.Editors
{
return new PagedResult<MemberBasic>(0, 0, 0);
}
var pagedResult = new PagedResult<MemberBasic>(totalRecords, pageNumber, pageSize);
pagedResult.Items = members
.Cast<MembershipUser>()
.Select(Mapper.Map<MembershipUser, MemberBasic>);
var pagedResult = new PagedResult<MemberBasic>(totalRecords, pageNumber, pageSize)
{
Items = members
.Cast<MembershipUser>()
.Select(Mapper.Map<MembershipUser, MemberBasic>)
};
return pagedResult;
}
@@ -437,7 +428,7 @@ namespace Umbraco.Web.Editors
var sensitiveProperties = contentItem.PersistedContent.ContentType
.PropertyTypes.Where(x => contentItem.PersistedContent.ContentType.IsSensitiveProperty(x.Alias))
.ToList();
foreach (var sensitiveProperty in sensitiveProperties)
{
//if found, change the value of the contentItem model to the persisted value so it remains unchanged
@@ -665,7 +656,7 @@ namespace Umbraco.Web.Editors
contentItem.Email,
"TEMP", //some membership provider's require something here even if q/a is disabled!
"TEMP", //some membership provider's require something here even if q/a is disabled!
contentItem.IsApproved,
contentItem.IsApproved,
contentItem.PersistedContent.Key, //custom membership provider, we'll link that based on the IMember unique id (GUID)
out status);
@@ -682,7 +673,7 @@ namespace Umbraco.Web.Editors
contentItem.Email,
"TEMP", //some membership provider's require something here even if q/a is disabled!
"TEMP", //some membership provider's require something here even if q/a is disabled!
contentItem.IsApproved,
contentItem.IsApproved,
newKey,
out status);
@@ -828,17 +819,17 @@ namespace Umbraco.Web.Editors
var member = ((MemberService)Services.MemberService).ExportMember(key);
var fileName = $"{member.Name}_{member.Email}.txt";
httpResponseMessage.Content = new ObjectContent<MemberExportModel>(member, new JsonMediaTypeFormatter {Indent = true});
httpResponseMessage.Content = new ObjectContent<MemberExportModel>(member, new JsonMediaTypeFormatter { Indent = true });
httpResponseMessage.Content.Headers.Add("x-filename", fileName);
httpResponseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
httpResponseMessage.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
httpResponseMessage.Content.Headers.ContentDisposition.FileName = fileName;
httpResponseMessage.StatusCode = HttpStatusCode.OK;
return httpResponseMessage;
}
}
}
@@ -0,0 +1,41 @@
using System;
using System.Web.Mvc;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Web.Features;
using Umbraco.Web.Models.ContentEditing;
using Umbraco.Web.Mvc;
namespace Umbraco.Web.Editors
{
[DisableBrowserCache]
public class PreviewController : Controller
{
[UmbracoAuthorize(redirectToUmbracoLogin: true)]
public ActionResult Index()
{
var model = new BackOfficePreview
{
DisableDevicePreview = FeaturesResolver.Current.Features.Disabled.DisableDevicePreview,
PreviewExtendedHeaderView = FeaturesResolver.Current.Features.Enabled.PreviewExtendedView
};
if (model.PreviewExtendedHeaderView.IsNullOrWhiteSpace() == false)
{
var viewEngineResult = ViewEngines.Engines.FindPartialView(ControllerContext, model.PreviewExtendedHeaderView);
if (viewEngineResult.View == null)
{
throw new InvalidOperationException("Could not find the view " + model.PreviewExtendedHeaderView + ", the following locations were searched: " + Environment.NewLine + string.Join(Environment.NewLine, viewEngineResult.SearchedLocations));
}
}
return View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Preview/" + "Index.cshtml", model);
}
public ActionResult Editors(string editor)
{
if (string.IsNullOrEmpty(editor)) throw new ArgumentNullException("editor");
return View(GlobalSettings.Path.EnsureEndsWith('/') + "Views/Preview/" + editor.Replace(".html", string.Empty) + ".cshtml");
}
}
}
+11 -5
View File
@@ -70,14 +70,20 @@ namespace Umbraco.Web.Editors
//Checking to see if the user has access to the required tour sections, else we remove the tour
foreach (var backOfficeTourFile in result)
{
foreach (var tour in backOfficeTourFile.Tours)
if (backOfficeTourFile.Tours != null)
{
foreach (var toursRequiredSection in tour.RequiredSections)
foreach (var tour in backOfficeTourFile.Tours)
{
if (allowedSections.Contains(toursRequiredSection) == false)
if (tour.RequiredSections != null)
{
toursToBeRemoved.Add(backOfficeTourFile);
break;
foreach (var toursRequiredSection in tour.RequiredSections)
{
if (allowedSections.Contains(toursRequiredSection) == false)
{
toursToBeRemoved.Add(backOfficeTourFile);
break;
}
}
}
}
}
@@ -20,5 +20,16 @@ namespace Umbraco.Web.Features
/// Gets the disabled controllers.
/// </summary>
public TypeList<UmbracoApiControllerBase> Controllers { get; private set; }
/// <summary>
/// Disables the device preview feature of previewing.
/// </summary>
public bool DisableDevicePreview { get; set; }
/// <summary>
/// If true, all references to templates will be removed in the back office and routing
/// </summary>
public bool DisableTemplates { get; set; }
}
}
+5 -3
View File
@@ -6,9 +6,11 @@ namespace Umbraco.Web.Features
internal class EnabledFeatures
{
/// <summary>
/// Specifies if rendering pipeline should ignore HasTemplate check when handling a request.
/// <remarks>This is to allow JSON preview of content with no template set.</remarks>
/// This allows us to inject a razor view into the Umbraco preview view to extend it
/// </summary>
public bool RenderNoTemplate { get; set; }
/// <remarks>
/// This is set to a virtual path of a razor view file
/// </remarks>
public string PreviewExtendedView { get; set; }
}
}
+3 -10
View File
@@ -16,14 +16,7 @@ namespace Umbraco.Web.Features
Disabled = new DisabledFeatures();
Enabled = new EnabledFeatures();
}
// note
// currently, the only thing a FeatureSet does is list disabled controllers,
// but eventually we could enable and disable more parts of Umbraco. and then
// we would need some logic to figure out what's enabled/disabled - hence it's
// better to use IsEnabled, where the logic would go, rather than directly
// accessing the Disabled collection.
/// <summary>
/// Gets the disabled features.
/// </summary>
@@ -35,9 +28,9 @@ namespace Umbraco.Web.Features
public EnabledFeatures Enabled { get; set; }
/// <summary>
/// Determines whether a feature is enabled.
/// Determines whether a controller is enabled.
/// </summary>
public bool IsEnabled(Type feature)
public bool IsControllerEnabled(Type feature)
{
if (typeof(UmbracoApiControllerBase).IsAssignableFrom(feature))
return Disabled.Controllers.Contains(feature) == false;
+5
View File
@@ -9,6 +9,11 @@ namespace Umbraco.Web.Models
[DataContract(Name = "tour", Namespace = "")]
public class BackOfficeTour
{
public BackOfficeTour()
{
RequiredSections = new List<string>();
}
[DataMember(Name = "name")]
public string Name { get; set; }
[DataMember(Name = "alias")]
+6 -1
View File
@@ -9,6 +9,11 @@ namespace Umbraco.Web.Models
[DataContract(Name = "tourFile", Namespace = "")]
public class BackOfficeTourFile
{
public BackOfficeTourFile()
{
Tours = new List<BackOfficeTour>();
}
/// <summary>
/// The file name for the tour
/// </summary>
@@ -27,4 +32,4 @@ namespace Umbraco.Web.Models
[DataMember(Name = "tours")]
public IEnumerable<BackOfficeTour> Tours { get; set; }
}
}
}
@@ -6,6 +6,7 @@ using Umbraco.Core.Models;
namespace Umbraco.Web.Models.ContentEditing
{
[DataContract(Name = "auditLog", Namespace = "")]
public class AuditLog
{
@@ -31,4 +32,4 @@ namespace Umbraco.Web.Models.ContentEditing
[DataMember(Name = "comment")]
public string Comment { get; set; }
}
}
}
@@ -0,0 +1,12 @@
namespace Umbraco.Web.Models.ContentEditing
{
/// <summary>
/// The model representing Previewing of a content item from the back office
/// </summary>
public class BackOfficePreview
{
public string PreviewExtendedHeaderView { get; set; }
//TODO: We could potentially have a 'footer' view
public bool DisableDevicePreview { get; set; }
}
}
@@ -30,6 +30,11 @@ namespace Umbraco.Web.Models.ContentEditing
[DataMember(Name = "editor", IsRequired = false)]
public string Editor { get; set; }
/// <summary>
/// Flags the property to denote that it can contain sensitive data
/// </summary>
[DataMember(Name = "isSensitive", IsRequired = false)]
public bool IsSensitive { get; set; }
/// <summary>
/// Used internally during model mapping
@@ -38,4 +43,4 @@ namespace Umbraco.Web.Models.ContentEditing
internal PropertyEditor PropertyEditor { get; set; }
}
}
}
@@ -80,17 +80,21 @@ namespace Umbraco.Web.Models.Mapping
//FROM IMember TO MemberBasic
config.CreateMap<IMember, MemberBasic>()
.ForMember(display => display.Udi, expression => expression.MapFrom(content => Udi.Create(Constants.UdiEntityType.Member, content.Key)))
.ForMember(display => display.Udi,
expression =>
expression.MapFrom(content => Udi.Create(Constants.UdiEntityType.Member, content.Key)))
.ForMember(dto => dto.Owner, expression => expression.ResolveUsing(new OwnerResolver<IMember>()))
.ForMember(dto => dto.Icon, expression => expression.MapFrom(content => content.ContentType.Icon))
.ForMember(dto => dto.ContentTypeAlias, expression => expression.MapFrom(content => content.ContentType.Alias))
.ForMember(dto => dto.ContentTypeAlias,
expression => expression.MapFrom(content => content.ContentType.Alias))
.ForMember(dto => dto.Email, expression => expression.MapFrom(content => content.Email))
.ForMember(dto => dto.Username, expression => expression.MapFrom(content => content.Username))
.ForMember(dto => dto.Trashed, expression => expression.Ignore())
.ForMember(dto => dto.Published, expression => expression.Ignore())
.ForMember(dto => dto.Updater, expression => expression.Ignore())
.ForMember(dto => dto.Alias, expression => expression.Ignore())
.ForMember(dto => dto.HasPublishedVersion, expression => expression.Ignore());
.ForMember(dto => dto.HasPublishedVersion, expression => expression.Ignore())
.ForMember(dto => dto.Properties, expression => expression.ResolveUsing(new MemberBasicPropertiesResolver()));
//FROM MembershipUser TO MemberBasic
config.CreateMap<MembershipUser, MemberBasic>()
@@ -395,6 +399,8 @@ namespace Umbraco.Web.Models.Mapping
//check permissions for viewing sensitive data
if (isSensitiveProperty && umbracoContext.Security.CurrentUser.HasAccessToSensitiveData() == false)
{
//mark this property as sensitive
prop.IsSensitive = true;
//mark this property as readonly so that it does not post any data
prop.Readonly = true;
//replace this editor with a sensitivevalue
@@ -477,8 +483,51 @@ namespace Umbraco.Web.Models.Mapping
return AutoMapperExtensions.MapWithUmbracoContext<IMember, MemberDisplay>(member, context.GetUmbracoContext());
}
}
/// <summary>
/// A resolver to map <see cref="IMember"/> properties to a collection of <see cref="ContentPropertyBasic"/>
/// </summary>
internal class MemberBasicPropertiesResolver : IValueResolver
{
public ResolutionResult Resolve(ResolutionResult source)
{
if (source.Value != null && (source.Value is IMember) == false)
throw new AutoMapperMappingException(string.Format("Value supplied is of type {0} but expected {1}.\nChange the value resolver source type, or redirect the source value supplied to the value resolver using FromMember.", new object[]
{
source.Value.GetType(),
typeof (IMember)
}));
return source.New(
//perform the mapping with the current umbraco context
ResolveCore(source.Context.GetUmbracoContext(), (IMember)source.Value), typeof(IEnumerable<ContentPropertyDisplay>));
}
private IEnumerable<ContentPropertyBasic> ResolveCore(UmbracoContext umbracoContext, IMember content)
{
var result = Mapper.Map<IEnumerable<Property>, IEnumerable<ContentPropertyBasic>>(
// Sort properties so items from different compositions appear in correct order (see U4-9298). Map sorted properties.
content.Properties.OrderBy(prop => prop.PropertyType.SortOrder))
.ToList();
var member = (IMember)content;
var memberType = member.ContentType;
//now update the IsSensitive value
foreach (var prop in result)
{
//check if this property is flagged as sensitive
var isSensitiveProperty = memberType.IsSensitiveProperty(prop.Alias);
//check permissions for viewing sensitive data
if (isSensitiveProperty && umbracoContext.Security.CurrentUser.HasAccessToSensitiveData() == false)
{
//mark this property as sensitive
prop.IsSensitive = true;
//clear the value
prop.Value = null;
}
}
return result;
}
}
}
}
@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using AutoMapper;
using Umbraco.Core;
@@ -9,7 +7,6 @@ using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.Services;
using Umbraco.Web.Models.ContentEditing;
using umbraco;
namespace Umbraco.Web.Models.Mapping
{
@@ -53,7 +50,7 @@ namespace Umbraco.Web.Models.Mapping
//perform the mapping with the current umbraco context
ResolveCore(source.Context.GetUmbracoContext(), (TSource)source.Value), typeof(List<Tab<ContentPropertyDisplay>>));
}
/// <summary>
/// Adds the container (listview) tab to the document
/// </summary>
@@ -275,7 +272,7 @@ namespace Umbraco.Web.Models.Mapping
//now add the user props
contentProps.AddRange(currProps);
//re-assign
genericProps.Properties = contentProps;
@@ -308,6 +305,6 @@ namespace Umbraco.Web.Models.Mapping
return result;
}
}
}
+8 -6
View File
@@ -1,10 +1,6 @@
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using System.Web.Mvc;
using Umbraco.Core.Configuration;
using Umbraco.Web.Editors;
using Umbraco.Web.Install;
using Umbraco.Web.Install.Controllers;
namespace Umbraco.Web.Mvc
{
@@ -24,6 +20,12 @@ namespace Umbraco.Web.Mvc
/// </remarks>
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapRoute(
"Umbraco_preview",
GlobalSettings.UmbracoMvcArea + "/preview/{action}/{editor}",
new {controller = "Preview", action = "Index", editor = UrlParameter.Optional},
new[] { "Umbraco.Web.Editors" });
context.MapRoute(
"Umbraco_back_office",
GlobalSettings.UmbracoMvcArea + "/{action}/{id}",
@@ -51,4 +53,4 @@ namespace Umbraco.Web.Mvc
get { return GlobalSettings.UmbracoMvcArea; }
}
}
}
}
+6 -6
View File
@@ -393,12 +393,12 @@ namespace Umbraco.Web.Mvc
return GetWebFormsHandler();
}
//here we need to check if there is no hijacked route and no template assigned, if this is the case
//we want to return a blank page, but we'll leave that up to the NoTemplateHandler.
//we also check if we're allowed to render even though there's no template (json render in headless).
if (publishedContentRequest.HasTemplate == false &&
routeDef.HasHijackedRoute == false &&
FeaturesResolver.Current.Features.Enabled.RenderNoTemplate == false)
//Here we need to check if there is no hijacked route and no template assigned,
//if this is the case we want to return a blank page, but we'll leave that up to the NoTemplateHandler.
//We also check if templates have been disabled since if they are then we're allowed to render even though there's no template,
//for example for json rendering in headless.
if ((publishedContentRequest.HasTemplate == false && FeaturesResolver.Current.Features.Disabled.DisableTemplates == false)
&& routeDef.HasHijackedRoute == false)
{
publishedContentRequest.UpdateOnMissingTemplate(); // will go 404
@@ -4,6 +4,7 @@ using System.Web.Mvc;
using Umbraco.Core;
using Umbraco.Web.Security;
using umbraco.BasePages;
using Umbraco.Core.Configuration;
namespace Umbraco.Web.Mvc
{
@@ -14,6 +15,7 @@ namespace Umbraco.Web.Mvc
{
private readonly ApplicationContext _applicationContext;
private readonly UmbracoContext _umbracoContext;
private readonly string _redirectUrl;
private ApplicationContext GetApplicationContext()
{
@@ -36,16 +38,40 @@ namespace Umbraco.Web.Mvc
_applicationContext = _umbracoContext.Application;
}
/// <summary>
/// Default constructor
/// </summary>
public UmbracoAuthorizeAttribute()
{
}
/// <summary>
/// Ensures that the user must be in the Administrator or the Install role
/// </summary>
/// <param name="httpContext"></param>
/// <returns></returns>
protected override bool AuthorizeCore(HttpContextBase httpContext)
/// <summary>
/// Constructor specifying to redirect to the specified location if not authorized
/// </summary>
/// <param name="redirectUrl"></param>
public UmbracoAuthorizeAttribute(string redirectUrl)
{
_redirectUrl = redirectUrl ?? throw new ArgumentNullException(nameof(redirectUrl));
}
/// <summary>
/// Constructor specifying to redirect to the umbraco login page if not authorized
/// </summary>
/// <param name="redirectToUmbracoLogin"></param>
public UmbracoAuthorizeAttribute(bool redirectToUmbracoLogin)
{
if (redirectToUmbracoLogin)
{
_redirectUrl = GlobalSettings.Path.EnsureStartsWith("~");
}
}
/// <summary>
/// Ensures that the user must be in the Administrator or the Install role
/// </summary>
/// <param name="httpContext"></param>
/// <returns></returns>
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null) throw new ArgumentNullException("httpContext");
@@ -73,11 +99,20 @@ namespace Umbraco.Web.Mvc
/// <param name="filterContext"></param>
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = (ActionResult)new HttpUnauthorizedResult("You must login to view this resource.");
if (_redirectUrl.IsNullOrWhiteSpace())
{
filterContext.Result = (ActionResult)new HttpUnauthorizedResult("You must login to view this resource.");
}
else
{
filterContext.Result = new RedirectResult(_redirectUrl);
}
//DON'T do a FormsAuth redirect... argh!! thankfully we're running .Net 4.5 :)
filterContext.RequestContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
}
}
}
}
@@ -15,7 +15,7 @@ namespace Umbraco.Web.PropertyEditors
[ParameterEditor("propertyTypePickerMultiple", "Name", "textbox")]
[ParameterEditor("contentTypeMultiple", "Name", "textbox")]
[ParameterEditor("tabPickerMultiple", "Name", "textbox")]
[PropertyEditor(Constants.PropertyEditors.DropDownListMultipleAlias, "Dropdown list multiple", "dropdown", Group = "lists", Icon="icon-bulleted-list")]
[PropertyEditor(Constants.PropertyEditors.DropDownListMultipleAlias, "Dropdown list multiple", "dropdown", Group = "lists", Icon="icon-bulleted-list", IsDeprecated = true)]
public class DropDownMultiplePropertyEditor : DropDownMultipleWithKeysPropertyEditor
{
protected override PropertyValueEditor CreateValueEditor()
@@ -28,4 +28,4 @@ namespace Umbraco.Web.PropertyEditors
}
}
@@ -12,7 +12,7 @@ namespace Umbraco.Web.PropertyEditors
/// Due to maintaining backwards compatibility this data type stores the value as a string which is a comma separated value of the
/// ids of the individual items so we have logic in here to deal with that.
/// </remarks>
[PropertyEditor(Constants.PropertyEditors.DropdownlistMultiplePublishKeysAlias, "Dropdown list multiple, publish keys", "dropdown", Group = "lists", Icon = "icon-bulleted-list")]
[PropertyEditor(Constants.PropertyEditors.DropdownlistMultiplePublishKeysAlias, "Dropdown list multiple, publish keys", "dropdown", Group = "lists", Icon = "icon-bulleted-list", IsDeprecated = true)]
public class DropDownMultipleWithKeysPropertyEditor : DropDownPropertyEditor
{
protected override PropertyValueEditor CreateValueEditor()
@@ -62,4 +62,4 @@ namespace Umbraco.Web.PropertyEditors
}
}
}
}
@@ -16,7 +16,7 @@ namespace Umbraco.Web.PropertyEditors
/// as INT and we have logic in here to ensure it is formatted correctly including ensuring that the string value is published
/// in cache and not the int ID.
/// </remarks>
[PropertyEditor(Constants.PropertyEditors.DropDownListAlias, "Dropdown list", "dropdown", ValueType = PropertyEditorValueTypes.String, Group = "lists", Icon = "icon-indent")]
[PropertyEditor(Constants.PropertyEditors.DropDownListAlias, "Dropdown list", "dropdown", ValueType = PropertyEditorValueTypes.String, Group = "lists", Icon = "icon-indent", IsDeprecated = true)]
public class DropDownPropertyEditor : DropDownWithKeysPropertyEditor
{
/// <summary>
@@ -29,4 +29,4 @@ namespace Umbraco.Web.PropertyEditors
}
}
}
}
@@ -11,7 +11,7 @@ namespace Umbraco.Web.PropertyEditors
/// as INT and we have logic in here to ensure it is formatted correctly including ensuring that the INT ID value is published
/// in cache and not the string value.
/// </remarks>
[PropertyEditor(Constants.PropertyEditors.DropdownlistPublishingKeysAlias, "Dropdown list, publishing keys", "dropdown", ValueType = PropertyEditorValueTypes.Integer, Group = "lists", Icon = "icon-indent")]
[PropertyEditor(Constants.PropertyEditors.DropdownlistPublishingKeysAlias, "Dropdown list, publishing keys", "dropdown", ValueType = PropertyEditorValueTypes.Integer, Group = "lists", Icon = "icon-indent", IsDeprecated = true)]
public class DropDownWithKeysPropertyEditor : PropertyEditor
{
@@ -24,4 +24,4 @@ namespace Umbraco.Web.PropertyEditors
return new ValueListPreValueEditor();
}
}
}
}
@@ -0,0 +1,84 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json.Linq;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.PropertyEditors;
namespace Umbraco.Web.PropertyEditors
{
[PropertyEditor(Constants.PropertyEditors.DropDownListFlexibleAlias, "Dropdown", "dropdownFlexible", Group = "lists", Icon = "icon-indent")]
public class DropdownFlexiblePropertyEditor : PropertyEditor
{
private static readonly string _multipleKey = "multiple";
/// <summary>
/// Return a custom pre-value editor
/// </summary>
/// <returns></returns>
/// <remarks>
/// We are just going to re-use the ValueListPreValueEditor
/// </remarks>
protected override PreValueEditor CreatePreValueEditor()
{
return new DropdownFlexiblePreValueEditor();
}
/// <summary>
/// We need to override the value editor so that we can ensure the string value is published in cache and not the integer ID value.
/// </summary>
/// <returns></returns>
protected override PropertyValueEditor CreateValueEditor()
{
return new PublishValuesMultipleValueEditor(false, base.CreateValueEditor());
}
internal class DropdownFlexiblePreValueEditor : ValueListPreValueEditor
{
public DropdownFlexiblePreValueEditor()
{
Fields.Insert(0, new PreValueField
{
Key = "multiple",
Name = "Enable multiple choice",
Description = "When checked, the dropdown will be a select multiple / combo box style dropdown",
View = "boolean"
});
}
public override IDictionary<string, PreValue> ConvertEditorToDb(IDictionary<string, object> editorValue, PreValueCollection currentValue)
{
var result = base.ConvertEditorToDb(editorValue, currentValue);
// get multiple config
var multipleValue = editorValue[_multipleKey] != null ? editorValue[_multipleKey].ToString() : "0";
result.Add(_multipleKey, new PreValue(-1, multipleValue));
return result;
}
public override IDictionary<string, object> ConvertDbToEditor(IDictionary<string, object> defaultPreVals, PreValueCollection persistedPreVals)
{
// weird way, but as the value stored is 0 or 1 need to do it this way
string multipleMode = "0";
if (persistedPreVals != null && persistedPreVals.PreValuesAsDictionary[_multipleKey] != null)
{
multipleMode = persistedPreVals.PreValuesAsDictionary[_multipleKey].Value;
// remove from the collection sent to the base multiple values collection
persistedPreVals.PreValuesAsDictionary.Remove(_multipleKey);
}
var returnVal = base.ConvertDbToEditor(defaultPreVals, persistedPreVals);
returnVal[_multipleKey] = multipleMode;
return returnVal;
}
}
}
}
@@ -47,8 +47,7 @@ namespace Umbraco.Web.PublishedCache
/// <remarks>Considers published or unpublished content depending on context.</remarks>
public IPublishedContent GetById(Guid contentId)
{
var intId = UmbracoContext.Application.Services.EntityService.GetIdForKey(contentId, UmbracoObjectTypes.Document);
return GetById(intId.Success ? intId.Result : -1);
return GetById(UmbracoContext.InPreviewMode, contentId);
}
/// <summary>
@@ -59,6 +58,15 @@ namespace Umbraco.Web.PublishedCache
/// <returns>The content, or null.</returns>
public abstract IPublishedContent GetById(bool preview, int contentId);
// same with Guid
// cannot make this public nor abstract without breaking backward compatibility
public virtual IPublishedContent GetById(bool preview, Guid contentKey)
{
// original implementation - override in concrete classes
var intId = UmbracoContext.Application.Services.EntityService.GetIdForKey(contentKey, UmbracoObjectTypes.Document);
return GetById(intId.Success ? intId.Result : -1);
}
/// <summary>
/// Gets content at root.
/// </summary>

Some files were not shown because too many files have changed in this diff Show More