Compare commits

..

135 Commits

Author SHA1 Message Date
Sebastiaan Jansssen 4e57e1cc18 Nicer variable name, thank to Lee Kelleher! 2018-01-19 12:50:45 +01:00
Sebastiaan Jansssen 410afffaa9 Optimizing use of newlines array 2018-01-19 12:42:04 +01:00
Claus 936e94789d adding to tinyMceConfig.Release.config. 2018-01-19 12:21:57 +01:00
Claus 468a56e5de Merge branch 'karltynan-dev-v7' into dev-v7 2018-01-19 11:11:53 +01:00
Claus 468ec8824a Merge branch 'dev-v7' of git://github.com/karltynan/Umbraco-CMS into karltynan-dev-v7 2018-01-19 11:11:13 +01:00
Sebastiaan Jansssen cad913b7a1 U4-10857 Update to ClientDependency 1.9.5 2018-01-19 08:26:34 +01:00
Sebastiaan Jansssen 382103d99d Bump version to 7.7.9 2018-01-19 08:26:33 +01:00
Sebastiaan Janssen cbb6b9bca0 Merge pull request #2310 from matthew-darby/U4-10495
U4-10495 - Install and customize buttons disabled
2018-01-18 18:38:37 +01:00
Sebastiaan Janssen a1b90a50cd Merge pull request #2343 from soreng/patch-5
Fix for U4-10733
2018-01-18 18:28:34 +01:00
Sebastiaan Janssen 9ea5855073 Merge pull request #2360 from janvanhelvoort/U4-10785
U4-10785 - Filtering of Grid Editors
2018-01-18 18:20:11 +01:00
Sebastiaan Janssen 4a37433042 Merge pull request #2372 from bjarnef/dev-v7-U4-10809
Fix checkmark tree icon, when custom font icon is used for tree icon
2018-01-18 18:00:53 +01:00
Sebastiaan Janssen 91469812d3 Merge pull request #2383 from MMasey/U4-10727
U4 10727 - If nodes with an empty name exist, it's not possible to empty recycle bin
2018-01-18 17:54:40 +01:00
Sebastiaan Janssen 68a8eb7f3f Merge pull request #2375 from redmorello/U4-10762
U4-10762 Fix issue with empty name when registering new members from …
2018-01-18 17:40:05 +01:00
Sebastiaan Janssen 2e7baabb94 Merge pull request #2394 from umbraco/temp-u4-10813
U4-10813 - fix error with groups having a large number of permissions
2018-01-18 17:27:11 +01:00
Sebastiaan Janssen 57745fe71d Merge pull request #2396 from leekelleher/issue/U4-10842
U4-10842 LegacyMediaPickerPropertyConverter null-reference check
2018-01-18 17:17:45 +01:00
Sebastiaan Janssen de6f9236e7 Merge pull request #2399 from leekelleher/issue/U4-8712
U4-8712 MultipleTextstring value newline delimiter changes
2018-01-18 17:13:46 +01:00
Sebastiaan Janssen a00c59e8b5 Merge pull request #2393 from umbraco/temp-u4-10079
U4-10079 - remove default template
2018-01-18 16:54:22 +01:00
Stephan 05c2da807f U4-10079 - fix test 2018-01-18 15:58:51 +01:00
leekelleher 0fd8ca43d6 U4-8712 MultipleTextstring value newline delimiter changes
PR #2185 goes towards resolving this, but doesn't handle the impromptu switch between the `\r\n` and `\n` newline delimiters when republishing a content node.

Using an explicit array of newline chars will resolve this, e.g. `Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None)`

<http://issues.umbraco.org/issue/U4-8712>
2018-01-18 12:18:51 +00:00
leekelleher e466878925 U4-10842 LegacyMediaPickerPropertyConverter ConvertDataToSource null-reference check
If a selected media node has been trashed on the source environment,
when Deploy comes to transfer the node ID, because it can't transfer the media dependency,
the node ID value is set to `null`.

This causes an issue for the `LegacyMediaPickerPropertyConverter`
and `ConvertDataToSource` throws a null-reference exception.

This patch adds in a null-reference check for the `source` value.

<http://issues.umbraco.org/issue/U4-10842>
2018-01-18 10:04:55 +00:00
Mikulas Tomanka 319acc199e Merge pull request #2391 from matthew-darby/U4-10825
U4-10825 Search member by email in member section
2018-01-17 14:18:43 +01:00
Stephan 2a982f21a7 U4-10813 - fix error with groups having a large number of permissions 2018-01-17 13:07:03 +01:00
Stephan 3ff455f11d U4-10079 - remove default template 2018-01-17 11:36:08 +01:00
Matt Darby f49d939a2d U4-10825 Search member by email in member section 2018-01-16 23:06:15 +08:00
Shannon 7e1e83b493 Fixes PackageInstaller event args to make sure the package metadata is passed through 2018-01-16 19:18:08 +11:00
Sebastiaan Janssen 23be0134e7 Merge pull request #1605 from jobf/dev-v7
fix U4-8792 override overflow
2018-01-13 17:57:49 +01:00
Sebastiaan Janssen 355fb64d8b Merge pull request #1573 from drbldgtl/dev-v7-U4-6415
Renamed SerializeToCropDataSet to DeserializeToCropDataSet
2018-01-13 17:33:44 +01:00
Stephan 7f12cff3bd Minor build cleanup 2018-01-11 16:25:18 +01:00
Mads Rasmussen 62d9a1a132 Merge pull request #2379 from umbraco/mzajkowski-U4-4902
U4-4902 Enable 'discard changes' alert throughout the UI
2018-01-11 10:59:22 +01:00
Mads Rasmussen f8c4481eb1 Merge branch 'dev-v7' into mzajkowski-U4-4902 2018-01-11 10:28:28 +01:00
Mike 9f6e6e4701 Add tests to SimilarNodeNameTests to check for null and "" values. 2018-01-10 20:58:10 +00:00
Mike 34ba3f3351 Merge remote-tracking branch 'upstream/dev-v7' into U4-10727 2018-01-10 20:48:28 +00:00
Mike dcfb8b94d8 Refactor SimilarNodeName to account for null nodeName values. 2018-01-10 20:44:30 +00:00
Ilham Boulghallat 700b71f9fb Merge pull request #2377 from abjerner/patch-32
A few fixes for the Danish translation
2018-01-10 15:14:27 +01:00
Robert 3642ff72a4 Removed console.log 2018-01-10 10:03:26 +01:00
Robert 6e830c1171 Wrapping the watch in the elm.focus
Seems to bring the watch calls way down.
2018-01-10 10:03:02 +01:00
Robert ab523baf4f Changed no-dirty-check directive to use scope.$watch to change $pristine to false 2018-01-10 09:24:42 +01:00
Claus 2dec03f441 Merge pull request #2374 from umbraco/temp-U4-10810
U4-10810 Update CDF to support storing TEMP files in environment %tem…
2018-01-10 09:04:58 +01:00
Claus 9ada0d9c97 reverting committed iis settings. 2018-01-10 09:03:35 +01:00
Shannon df553140e8 Updates to latest 1.9.4 of CDF and updates Nuspec 2018-01-10 12:25:24 +11:00
Anders Bjerner 0b898f2e32 A few fixes for the Danish translation 2018-01-09 22:54:48 +01:00
Mads Rasmussen 4c9be2cc49 Merge pull request #2376 from abjerner/patch-31
Start node -> Startnode
2018-01-09 21:32:53 +01:00
Anders Bjerner 1aad4e50d5 Start node -> Startnode 2018-01-09 21:25:36 +01:00
Ian Houghton f5f3676a56 U4-10762 Fix issue with empty name when registering new members from snippet 2018-01-09 15:51:32 +00:00
Shannon bc828fc6f3 U4-10810 Update CDF to support storing TEMP files in environment %temp% location 2018-01-09 13:52:52 +11:00
Mike dc7b83ca6c Add initial test fix for SimilarNodeName when a node has no name. 2018-01-08 17:30:11 +00:00
Robert 8188e4ff55 Merge branch 'U4-4902' of git://github.com/mzajkowski/Umbraco-CMS into mzajkowski-U4-4902 2018-01-08 15:39:29 +01:00
Bjarne Fyrstenborg fcf9dcd803 Fix checkmark tree icon, when custom font icon is used for tree icon, e.g. in UCommerce 2018-01-08 14:40:31 +01:00
Claus f52a84937b Merge pull request #2332 from ruant/U4-10596
fix: add CultureInfo.InvariantCulture to int.Parse
2018-01-08 14:07:10 +01:00
Sebastiaan Jansssen 3556043b55 Update to latest modelsbuilder 2018-01-08 12:44:29 +01:00
Sebastiaan Jansssen 3e8fb11abd Update to latest modelsbuilder 2018-01-08 08:39:01 +01:00
Shannon 5181988a41 forgot to set the flag 2018-01-08 18:10:27 +11:00
Shannon 5169310258 Makes sure we check for index locking on both a normal boot with empty indexes and a cold boot when that is being forced 2018-01-08 17:57:15 +11:00
Shannon Deminick f987640462 Merge pull request #2370 from abjerner/patch-30
Fixed the xmldoc for UserService.Delete
2018-01-08 14:34:53 +11:00
Anders Bjerner 55e97dad74 Fixed the xmldoc for UserService.Delete 2018-01-06 20:24:02 +01:00
Sebastiaan Jansssen d2f3e162f1 Bump version to 7.7.8 2018-01-04 16:45:00 +01:00
Claus 7404e20a19 Merge pull request #2331 from JackPenney/JackPenney-patch-1
Removed CMS Import keys from hebrew translation
2018-01-04 14:05:43 +01:00
Claus 744ff0cf33 Merge pull request #2328 from akierczynska/patch-3
Update pl.xml
2018-01-04 14:04:47 +01:00
Claus afd0018dd6 Merge pull request #2349 from dallastaylor/remove-console-writeline
Remove Console.Writeline() from IsPublishable().
2018-01-04 13:56:43 +01:00
Shannon Deminick c36aec624b Merge pull request #2367 from umbraco/temp-U4-10756-performance-fix
Doesn't fix the issue but improves performance by ~30%
2018-01-04 23:43:25 +11:00
Claus 1ba86f361a Merge pull request #2368 from umbraco/temp-U4-9268
U4-9268 Hidden preview button reappears after 'save' or 'save and pub…
2018-01-04 12:29:00 +01:00
Shannon e5a21625ea U4-9268 Hidden preview button reappears after 'save' or 'save and publish'. 2018-01-04 21:53:55 +11:00
Sebastiaan Janssen efd3d6937a Merge pull request #2365 from umbraco/temp-U4-10701
U4-10701 Umbraco.MemberHasAccess generates slow query after upgrading…
2018-01-03 15:36:51 +01:00
Niels Hartvig 6d46c2204d Doesn't fix the issue but improves performance by ~30% 2018-01-03 12:54:25 +01:00
Warren Buckley 27b9385df5 Update client build NPM dependancy for gulp-connect to use 5.0.0 as next/latest version required you to use CoffeeScript to compile their src code to use the module/component 2018-01-03 11:08:55 +00:00
Shannon ea6d81f7ac U4-10701 Umbraco.MemberHasAccess generates slow query after upgrading to 7.7.6 2018-01-03 11:47:26 +11:00
Mads Rasmussen f56bd731b7 Merge pull request #2227 from abryukhov/U4-10481
U4-10481 - v7.7.x - RU localization of the last added keys
2017-12-27 13:24:42 +01:00
Mads Rasmussen bee0642417 Merge pull request #2263 from krighi/U4-10323
U4-10323 - FIX - Grid stuck at 12 columns (percentage calculation incorrect)
2017-12-27 13:04:31 +01:00
Mads Rasmussen 43abb08e59 Merge pull request #2305 from marcemarc/temp-u4-10637
Fixes U4-10637 - textarea Macro Parameters hidden in niche circumstances
2017-12-27 11:05:12 +01:00
Mads Rasmussen 17db5709f1 Merge pull request #2339 from bjarnef/dev-v7-U4-10720
U4-10720 - Add documentation to umb-table component
2017-12-27 10:38:43 +01:00
Mads Rasmussen 2fc6d9b7df Merge pull request #2327 from bjarnef/dev-v7-U4-10703
Wrap text in umb-node-preview component
2017-12-27 10:19:23 +01:00
Jan van Helvoort 591a881283 Filtering of Grid Editors
If there are more than 15 items, 5 rows of 3, then show the filter.
2017-12-24 15:48:16 +01:00
Shannon e4561851a4 modifies some code changes to null check and not to use extension methods that require singleton access. 2017-12-21 17:30:37 +11:00
Shannon Deminick c6daf2e111 Merge pull request #2353 from mitutee/temp-U4-10770
U4-10770
2017-12-21 17:20:19 +11:00
Sebastiaan Janssen 883366f741 Merge pull request #2295 from JacekJMMJ/temp-u4-10626
Temp u4 10626
2017-12-20 16:07:14 +01:00
Claus cac331adbc U4-10640 Multiple Media Picker duplicate image Angular issue in Umbraco 7.7.4 2017-12-20 13:38:07 +01:00
Shannon Deminick 18318ecabf Merge pull request #2354 from umbraco/temp-u4-10764
U4-10764 - workaround broken events
2017-12-20 17:27:42 +11:00
Shannon 6b9ef6df7a fix tests 2017-12-20 17:02:52 +11:00
Shannon Deminick fcaf78ef29 Merge pull request #2355 from umbraco/temp-u4-10774
U4-10774 - leak in CacheRefresherEventHandler
2017-12-20 16:06:41 +11:00
Sebastiaan Janssen 833b4c552c Merge pull request #2350 from umbraco/temp-U4-10686
U4-10686 TypedMediaAtRoot().Descendants() calls SQL
2017-12-19 18:25:23 +01:00
Mads Rasmussen c678b7f6d9 Merge branch 'bjarnef-dev-v7-U4-10639' into dev-v7 2017-12-19 10:40:59 +01:00
Mads Rasmussen e320840a29 fix position of add button in media picker 2017-12-19 10:39:52 +01:00
Stephan b664fc5e94 U4-10774 - leak in CacheRefresherEventHandler 2017-12-19 10:04:33 +01:00
Stephan b87346bee5 U4-10764 - minor fix 2017-12-19 10:01:51 +01:00
Mads Rasmussen 6029306fe9 Merge branch 'dev-v7-U4-10639' of git://github.com/bjarnef/Umbraco-CMS into bjarnef-dev-v7-U4-10639 2017-12-19 09:53:52 +01:00
Stephan f979792290 U4-10764 - workaround broken events 2017-12-18 16:53:58 +01:00
m.kilianovskyi 5f82fc6e20 Merge branch 'dev-v7' into HEAD 2017-12-18 17:51:27 +02:00
m.kilianovskyi b1a0ca98ea U4-10770 Get all permissions for entity instead of explicit only 2017-12-18 17:50:53 +02:00
Ilham Boulghallat f4f99c2922 Merge pull request #2336 from MrCosmo/temp-U4-10722
U4-10722 fix in Dutch localization
2017-12-18 10:32:33 +00:00
Shannon c1b3da869d U4-10686 TypedMediaAtRoot().Descendants() calls SQL 2017-12-15 16:01:20 +11:00
Dallas Taylor e39158d5e5 Remove Console.Writeline() from IsPublishable(). 2017-12-14 22:18:49 -05:00
Shannon ddd9c8ef7d Do a lock check on the index on startup and unlock it if it is, this is a safety check since we are now using the simplefs dir 2017-12-14 19:25:01 +11:00
Shannon 44db4e7a48 updates nuspec and references to use latest Examine 2017-12-14 18:34:48 +11:00
Shannon f44b158c15 When we disable examine indexing on startup with MainDom, also suspend all indexing 2017-12-14 16:19:54 +11:00
Robert 1ff66d0c3a Merge pull request #2345 from umbraco/temp-U4-10735
U4-10735 Examine update to better manage appdomain shutdowns
2017-12-13 10:52:56 +01:00
Robert aba2c2a79e Merge pull request #2346 from umbraco/temp-U4-10738
U4-10738 Deleting a media type folder causes an exception
2017-12-12 16:02:21 +01:00
Robert 9f62dfc087 Merge pull request #2348 from umbraco/temp-U4-10588
U4-10588 Indexed member data is missing fields
2017-12-12 13:40:48 +01:00
Shannon Deminick a21912dc41 Merge pull request #2337 from skttl/U4-10549-rte-memory-usage
Fix for U4-10549 RTE memory usage
2017-12-12 11:53:42 +01:00
Robert 733b4a770f Merge pull request #2347 from umbraco/temp-U4-10587
U4-10587 Email field in InternalMemberIndex seems to be attempted to …
2017-12-12 11:29:10 +01:00
Shannon 2e097b7e46 U4-10588 Indexed member data is missing fields 2017-12-12 11:25:53 +01:00
Shannon e1b6997ef7 U4-10587 Email field in InternalMemberIndex seems to be attempted to being added to the index twice 2017-12-11 15:50:27 +01:00
Shannon 8181f88cb0 Do not keep looking up data to index if the app is shutting down 2017-12-08 09:09:14 +01:00
Claus 3a4865ef7d U4-10738 Deleting a media type folder causes an exception 2017-12-07 13:45:49 +01:00
Shannon 37f6dbfa6b more logging 2017-12-06 15:46:35 +01:00
Shannon 131fea3ba4 updates some proj refs 2017-12-06 15:38:00 +01:00
Shannon b0661218a0 U4-10735 Examine update to better manage appdomain shutdowns 2017-12-06 15:21:38 +01:00
Søren Gregersen 50335723b0 Fix for U4-10733 2017-12-06 10:09:40 +01:00
Bjarne Fyrstenborg 3b8a2d7d65 Add basic documentation to umbPasswordToggle 2017-11-30 23:48:41 +01:00
Bjarne Fyrstenborg 61b9ab5c7b Fix typo 2017-11-30 23:47:55 +01:00
Bjarne Fyrstenborg cfda04b6ed Add documentation of umb-table component 2017-11-30 23:47:23 +01:00
Søren Kottal a20844b55b Destroy tineMceEditors on $destroy 2017-11-29 12:16:12 +01:00
Marco 158e40d7f6 U4-10722 fix in Dutch localization 2017-11-29 08:25:04 +01:00
Rune Antonsen fe67a09ccb fix: add CultureInfo.InvariantCulture to int.Parse
Fix issue where different Culture some times makes int.Parse thrown an `System.FormatException: 'Input string was not in a correct format.' `

Closes: U4-10596
2017-11-23 15:12:01 +01:00
Jack Penney 1c4e1db054 Removed CMS Import keys from hebrew translation 2017-11-23 12:28:17 +00:00
Karl Tynan 58697eaa04 Merge pull request #1 from karltynan/karltynan-patch-1
Added small to allowed TinyMCE valid elements
2017-11-21 15:20:06 +00:00
Karl Tynan ce58ad91b5 Added `small` to allowed TinyMCE valid elements
We use ``small`` a lot in the RTE, and ``small`` is now considered a really useful tag in HTML5. I would like to see this in the default valid elements list for people to use out-of-the box.
2017-11-21 15:18:42 +00:00
Bjarne Fyrstenborg 3c98d9d2e1 Wrap text in umb-node-preview component 2017-11-20 19:18:57 +01:00
akierczynska f3ba1fa7ed Update pl.xml
Adding translations and adjusting pl.xml to en.xml format.
2017-11-15 18:07:31 +00:00
Marcin Zajkowski e14aba3875 More no-dirty-checks and code polishment 2017-11-07 23:21:50 +01:00
Matt Darby 77162e4b51 Move val-email attribute before required attribute 2017-11-07 19:17:42 +07:00
Bjarne Fyrstenborg e72758e04a Ensure box is square when picker is multiple picker 2017-11-06 22:01:35 +01:00
Bjarne Fyrstenborg 9d373c194d Show thumbnails if any images/files has been selected 2017-11-06 21:42:01 +01:00
Bjarne Fyrstenborg 856e123ec2 Oops - remove duplicated disableFolderSelect 2017-11-06 19:23:41 +01:00
Bjarne Fyrstenborg 0b2af6b48f Fix square image in imagepicker prevalue editor. Cleanup and consistency 2017-11-06 19:12:27 +01:00
Marc Goodson 360665c082 Fixes accidental hiding of textarea parameters when inserting a Macro(with those parameters) via the Rich Text Editor Macro button within a grid cell - U4-10637 2017-11-05 10:36:14 +00:00
Alexander Bryukhov ff98b5f321 U4-10481 - v7.7.x - RU localization of the last added keys (grid editor U4-5722) 2017-11-03 12:18:24 +07:00
Marcin Zajkowski 0df7767f4a Added no-dirty-check to search fields in all dialogs 2017-11-02 17:32:20 +01:00
Jacek Malinowski 92378095a2 U4 10-626. Detecting new Application Url and _umbracoApplicationUrl refresh. 2017-11-02 09:08:46 -07:00
Jacek Malinowski daa0741802 U4-10626 Detecting deplayoment Id change 2017-11-02 07:40:53 -07:00
Stephan eaa8ca5fdc U4-10626 - support resetting UmbracoApplicationUrl 2017-11-02 13:30:45 +01:00
Kaue Righi e0e9823a03 U4-10323 - Grid stuck at 12 columns (percentage calculation incorrect) - fix 2017-10-25 11:40:46 -02:00
Alexander Bryukhov 3a98d63bf1 U4-10481v7.7.2 - RU localization of the last added keys (user section filters & sort) 2017-09-29 15:15:28 +07:00
Alexander Bryukhov ac65af772a U4-10481 - v7.7.2 - RU localization of the last added keys 2017-09-29 13:27:45 +07:00
jf 7566546fd7 fix U4-8792 override overflow 2016-11-03 17:32:24 +00:00
Shane Marsden 59b8b397b7 Renamed SerializeToCropDataSet to DeserializeToCropDataSet 2016-11-03 11:33:00 +00:00
111 changed files with 1709 additions and 1096 deletions
@@ -239,18 +239,18 @@ function Prepare-Tests
# data
Write-Host "Copy data files"
if( -Not (Test-Path -Path "$tmp\tests\Packaging" ) )
if (-Not (Test-Path -Path "$tmp\tests\Packaging" ) )
{
Write-Host "Create packaging directory"
New-Item -ItemType directory -Path "$tmp\tests\Packaging"
mkdir "$tmp\tests\Packaging" > $null
}
Copy-Files "$src\Umbraco.Tests\Packaging\Packages" "*" "$tmp\tests\Packaging\Packages"
# required for package install tests
if( -Not (Test-Path -Path "$tmp\tests\bin" ) )
if (-Not (Test-Path -Path "$tmp\tests\bin" ) )
{
Write-Host "Create bin directory"
New-Item -ItemType directory -Path "$tmp\tests\bin"
mkdir "$tmp\tests\bin" > $null
}
}
+2 -2
View File
@@ -29,11 +29,11 @@
<dependency id="Lucene.Net" version="[2.9.4.1, 3.0.0.0)" />
<dependency id="SharpZipLib" version="[0.86.0, 1.0.0)" />
<dependency id="MySql.Data" version="[6.9.9, 7.0.0)" />
<dependency id="ClientDependency" version="[1.9.2, 2.0.0)" />
<dependency id="ClientDependency" version="[1.9.5, 2.0.0)" />
<dependency id="ClientDependency-Mvc5" version="[1.8.0.0, 2.0.0)" />
<dependency id="AutoMapper" version="[3.3.1, 4.0.0)" />
<dependency id="Newtonsoft.Json" version="[10.0.2, 11.0.0)" />
<dependency id="Examine" version="[0.1.88, 1.0.0)" />
<dependency id="Examine" version="[0.1.89, 1.0.0)" />
<dependency id="ImageProcessor" version="[2.5.6, 3.0.0)" />
<dependency id="ImageProcessor.Web" version="[4.8.7, 5.0.0)" />
<dependency id="semver" version="[1.1.2, 3.0.0)" />
+1 -1
View File
@@ -17,7 +17,7 @@
<dependencies>
<dependency id="UmbracoCms.Core" version="[$version$]" />
<dependency id="Newtonsoft.Json" version="[10.0.2, 11.0.0)" />
<dependency id="Umbraco.ModelsBuilder" version="[3.0.7, 4.0.0)" />
<dependency id="Umbraco.ModelsBuilder" version="[3.0.8, 4.0.0)" />
<dependency id="Microsoft.AspNet.SignalR.Core" version="[2.2.1, 3.0.0)" />
<dependency id="ImageProcessor.Web.Config" version="[2.3.1, 3.0.0)" />
</dependencies>
-2
View File
@@ -49,11 +49,9 @@
<Reference Include="System.Core" />
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Data.SqlServerCe.Entity, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
+2 -2
View File
@@ -11,5 +11,5 @@ using System.Resources;
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("7.7.7")]
[assembly: AssemblyInformationalVersion("7.7.7")]
[assembly: AssemblyFileVersion("7.7.9")]
[assembly: AssemblyInformationalVersion("7.7.9")]
+15 -2
View File
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Threading;
using Umbraco.Core.Configuration;
@@ -260,7 +261,7 @@ namespace Umbraco.Core
/// - http://issues.umbraco.org/issue/U4-5728
/// - http://issues.umbraco.org/issue/U4-5391
/// </remarks>
internal string UmbracoApplicationUrl
public string UmbracoApplicationUrl
{
get
{
@@ -268,9 +269,21 @@ namespace Umbraco.Core
return _umbracoApplicationUrl;
}
}
/// <summary>
/// Resets the url.
/// </summary>
public void ResetUmbracoApplicationUrl()
{
_umbracoApplicationUrl = null;
}
// ReSharper disable once InconsistentNaming
internal string _umbracoApplicationUrl;
internal string _umbracoApplicationUrl;
internal List<string> _umbracoApplicationDomains = new List<string>();
internal string _umbracoApplicationDeploymentId;
private Lazy<bool> _configured;
internal MainDom MainDom { get; private set; }
@@ -6,7 +6,7 @@ namespace Umbraco.Core.Configuration
{
public class UmbracoVersion
{
private static readonly Version Version = new Version("7.7.7");
private static readonly Version Version = new Version("7.7.9");
/// <summary>
/// Gets the current version of Umbraco.
+34 -34
View File
@@ -21,9 +21,9 @@ namespace Umbraco.Core
public static DateTime TruncateTo(this DateTime dt, DateTruncate truncateTo)
{
if (truncateTo == DateTruncate.Year)
return new DateTime(dt.Year, 0, 0);
return new DateTime(dt.Year, 1, 1);
if (truncateTo == DateTruncate.Month)
return new DateTime(dt.Year, dt.Month, 0);
return new DateTime(dt.Year, dt.Month, 1);
if (truncateTo == DateTruncate.Day)
return new DateTime(dt.Year, dt.Month, dt.Day);
if (truncateTo == DateTruncate.Hour)
@@ -41,43 +41,43 @@ namespace Umbraco.Core
Hour,
Minute,
Second
}
}
/// <summary>
/// Calculates the number of minutes from a date time, on a rolling daily basis (so if
/// Calculates the number of minutes from a date time, on a rolling daily basis (so if
/// date time is before the time, calculate onto next day)
/// </summary>
/// <param name="fromDateTime">Date to start from</param>
/// <param name="scheduledTime">Time to compare against (in Hmm form, e.g. 330, 2200)</param>
/// <returns></returns>
public static int PeriodicMinutesFrom(this DateTime fromDateTime, string scheduledTime)
{
// Ensure time provided is 4 digits long
if (scheduledTime.Length == 3)
{
scheduledTime = "0" + scheduledTime;
}
var scheduledHour = int.Parse(scheduledTime.Substring(0, 2));
var scheduledMinute = int.Parse(scheduledTime.Substring(2));
DateTime scheduledDateTime;
if (IsScheduledInRemainingDay(fromDateTime, scheduledHour, scheduledMinute))
{
scheduledDateTime = new DateTime(fromDateTime.Year, fromDateTime.Month, fromDateTime.Day, scheduledHour, scheduledMinute, 0);
}
else
{
var nextDay = fromDateTime.AddDays(1);
scheduledDateTime = new DateTime(nextDay.Year, nextDay.Month, nextDay.Day, scheduledHour, scheduledMinute, 0);
}
return (int)(scheduledDateTime - fromDateTime).TotalMinutes;
}
private static bool IsScheduledInRemainingDay(DateTime fromDateTime, int scheduledHour, int scheduledMinute)
{
return scheduledHour > fromDateTime.Hour || (scheduledHour == fromDateTime.Hour && scheduledMinute >= fromDateTime.Minute);
/// <returns></returns>
public static int PeriodicMinutesFrom(this DateTime fromDateTime, string scheduledTime)
{
// Ensure time provided is 4 digits long
if (scheduledTime.Length == 3)
{
scheduledTime = "0" + scheduledTime;
}
var scheduledHour = int.Parse(scheduledTime.Substring(0, 2));
var scheduledMinute = int.Parse(scheduledTime.Substring(2));
DateTime scheduledDateTime;
if (IsScheduledInRemainingDay(fromDateTime, scheduledHour, scheduledMinute))
{
scheduledDateTime = new DateTime(fromDateTime.Year, fromDateTime.Month, fromDateTime.Day, scheduledHour, scheduledMinute, 0);
}
else
{
var nextDay = fromDateTime.AddDays(1);
scheduledDateTime = new DateTime(nextDay.Year, nextDay.Month, nextDay.Day, scheduledHour, scheduledMinute, 0);
}
return (int)(scheduledDateTime - fromDateTime).TotalMinutes;
}
private static bool IsScheduledInRemainingDay(DateTime fromDateTime, int scheduledHour, int scheduledMinute)
{
return scheduledHour > fromDateTime.Hour || (scheduledHour == fromDateTime.Hour && scheduledMinute >= fromDateTime.Minute);
}
}
}
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using Umbraco.Core.Packaging.Models;
namespace Umbraco.Core.Events
@@ -7,18 +8,27 @@ namespace Umbraco.Core.Events
public class ImportPackageEventArgs<TEntity> : CancellableEnumerableObjectEventArgs<TEntity>, IEquatable<ImportPackageEventArgs<TEntity>>
{
private readonly MetaData _packageMetaData;
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("Use the overload specifying packageMetaData instead")]
public ImportPackageEventArgs(TEntity eventObject, bool canCancel)
: base(new[] { eventObject }, canCancel)
{
}
public ImportPackageEventArgs(TEntity eventObject, MetaData packageMetaData)
: base(new[] { eventObject })
public ImportPackageEventArgs(TEntity eventObject, MetaData packageMetaData, bool canCancel)
: base(new[] { eventObject }, canCancel)
{
if (packageMetaData == null) throw new ArgumentNullException("packageMetaData");
_packageMetaData = packageMetaData;
}
public ImportPackageEventArgs(TEntity eventObject, MetaData packageMetaData)
: this(eventObject, packageMetaData, true)
{
}
public MetaData PackageMetaData
{
get { return _packageMetaData; }
@@ -76,260 +76,257 @@ namespace Umbraco.Core.Events
{
if (_events == null)
return Enumerable.Empty<IEventDefinition>();
IReadOnlyList<IEventDefinition> events;
switch (filter)
{
case EventDefinitionFilter.All:
return FilterSupersededAndUpdateToLatestEntity(_events);
events = _events;
break;
case EventDefinitionFilter.FirstIn:
var l1 = new OrderedHashSet<IEventDefinition>();
foreach (var e in _events)
{
l1.Add(e);
}
return FilterSupersededAndUpdateToLatestEntity(l1);
events = l1;
break;
case EventDefinitionFilter.LastIn:
var l2 = new OrderedHashSet<IEventDefinition>(keepOldest: false);
foreach (var e in _events)
{
l2.Add(e);
}
return FilterSupersededAndUpdateToLatestEntity(l2);
events = l2;
break;
default:
throw new ArgumentOutOfRangeException("filter", filter, null);
}
return FilterSupersededAndUpdateToLatestEntity(events);
}
private class EventDefinitionTypeData
private class EventDefinitionInfos
{
public IEventDefinition EventDefinition { get; set; }
public Type EventArgType { get; set; }
public SupersedeEventAttribute[] SupersedeAttributes { get; set; }
public Type[] SupersedeTypes { get; set; }
}
/// <summary>
/// This will iterate over the events (latest first) and filter out any events or entities in event args that are included
/// in more recent events that Supersede previous ones. For example, If an Entity has been Saved and then Deleted, we don't want
/// to raise the Saved event (well actually we just don't want to include it in the args for that saved event)
/// </summary>
/// <param name="events"></param>
/// <returns></returns>
private static IEnumerable<IEventDefinition> FilterSupersededAndUpdateToLatestEntity(IReadOnlyList<IEventDefinition> events)
// fixme
// this is way too convoluted, the superceede attribute is used only on DeleteEventargs to specify
// that it superceeds save, publish, move and copy - BUT - publish event args is also used for
// unpublishing and should NOT be superceeded - so really it should not be managed at event args
// level but at event level
//
// what we want is:
// if an entity is deleted, then all Saved, Moved, Copied, Published events prior to this should
// not trigger for the entity - and even though, does it make any sense? making a copy of an entity
// should ... trigger?
//
// not going to refactor it all - we probably want to *always* trigger event but tell people that
// due to scopes, they should not expected eg a saved entity to still be around - however, now,
// going to write a ugly condition to deal with U4-10764
// iterates over the events (latest first) and filter out any events or entities in event args that are included
// in more recent events that Supersede previous ones. For example, If an Entity has been Saved and then Deleted, we don't want
// to raise the Saved event (well actually we just don't want to include it in the args for that saved event)
internal static IEnumerable<IEventDefinition> FilterSupersededAndUpdateToLatestEntity(IReadOnlyList<IEventDefinition> events)
{
//used to keep the 'latest' entity and associated event definition data
var allEntities = new List<Tuple<IEntity, EventDefinitionTypeData>>();
//tracks all CancellableObjectEventArgs instances in the events which is the only type of args we can work with
var cancelableArgs = new List<CancellableObjectEventArgs>();
// keeps the 'latest' entity and associated event data
var entities = new List<Tuple<IEntity, EventDefinitionInfos>>();
// collects the event definitions
// collects the arguments in result, that require their entities to be updated
var result = new List<IEventDefinition>();
var resultArgs = new List<CancellableObjectEventArgs>();
//This will eagerly load all of the event arg types and their attributes so we don't have to continuously look this data up
var allArgTypesWithAttributes = events.Select(x => x.Args.GetType())
// eagerly fetch superceeded arg types for each arg type
var argTypeSuperceeding = events.Select(x => x.Args.GetType())
.Distinct()
.ToDictionary(x => x, x => x.GetCustomAttributes<SupersedeEventAttribute>(false).ToArray());
//Iterate all events and collect the actual entities in them and relates them to their corresponding EventDefinitionTypeData
//we'll process the list in reverse because events are added in the order they are raised and we want to filter out
//any entities from event args that are not longer relevant
//(i.e. if an item is Deleted after it's Saved, we won't include the item in the Saved args)
.ToDictionary(x => x, x => x.GetCustomAttributes<SupersedeEventAttribute>(false).Select(y => y.SupersededEventArgsType).ToArray());
// iterate over all events and filter
//
// process the list in reverse, because events are added in the order they are raised and we want to keep
// the latest (most recent) entities and filter out what is not relevant anymore (too old), eg if an entity
// is Deleted after being Saved, we want to filter out the Saved event
for (var index = events.Count - 1; index >= 0; index--)
{
var eventDefinition = events[index];
var def = events[index];
var argType = eventDefinition.Args.GetType();
var attributes = allArgTypesWithAttributes[eventDefinition.Args.GetType()];
var meta = new EventDefinitionTypeData
var infos = new EventDefinitionInfos
{
EventDefinition = eventDefinition,
EventArgType = argType,
SupersedeAttributes = attributes
EventDefinition = def,
SupersedeTypes = argTypeSuperceeding[def.Args.GetType()]
};
var args = eventDefinition.Args as CancellableObjectEventArgs;
if (args != null)
var args = def.Args as CancellableObjectEventArgs;
if (args == null)
{
var list = TypeHelper.CreateGenericEnumerableFromObject(args.EventObject);
if (list == null)
// not a cancellable event arg, include event definition in result
result.Add(def);
}
else
{
// event object can either be a single object or an enumerable of objects
// try to get as an enumerable, get null if it's not
var eventObjects = TypeHelper.CreateGenericEnumerableFromObject(args.EventObject);
if (eventObjects == null)
{
//extract the event object
var obj = args.EventObject as IEntity;
if (obj != null)
// single object, cast as an IEntity
// if cannot cast, cannot filter, nothing - just include event definition in result
var eventEntity = args.EventObject as IEntity;
if (eventEntity == null)
{
//Now check if this entity already exists in other event args that supersede this current event arg type
if (IsFiltered(obj, meta, allEntities) == false)
{
//if it's not filtered we can adde these args to the response
cancelableArgs.Add(args);
result.Add(eventDefinition);
//track the entity
allEntities.Add(Tuple.Create(obj, meta));
}
result.Add(def);
continue;
}
else
// look for this entity in superceding event args
// found = must be removed (ie not added), else track
if (IsSuperceeded(eventEntity, infos, entities) == false)
{
//Can't retrieve the entity so cant' filter or inspect, just add to the output
result.Add(eventDefinition);
// track
entities.Add(Tuple.Create(eventEntity, infos));
// track result arguments
// include event definition in result
resultArgs.Add(args);
result.Add(def);
}
}
else
{
// enumerable of objects
var toRemove = new List<IEntity>();
foreach (var entity in list)
foreach (var eventObject in eventObjects)
{
//extract the event object
var obj = entity as IEntity;
if (obj != null)
{
//Now check if this entity already exists in other event args that supersede this current event arg type
if (IsFiltered(obj, meta, allEntities))
{
//track it to be removed
toRemove.Add(obj);
}
else
{
//track the entity, it's not filtered
allEntities.Add(Tuple.Create(obj, meta));
}
}
// extract the event object, cast as an IEntity
// if cannot cast, cannot filter, nothing to do - just leave it in the list & continue
var eventEntity = eventObject as IEntity;
if (eventEntity == null)
continue;
// look for this entity in superceding event args
// found = must be removed, else track
if (IsSuperceeded(eventEntity, infos, entities))
toRemove.Add(eventEntity);
else
{
//we don't need to do anything here, we can't cast to IEntity so we cannot filter, so it will just remain in the list
}
entities.Add(Tuple.Create(eventEntity, infos));
}
//remove anything that has been filtered
// remove superceded entities
foreach (var entity in toRemove)
{
list.Remove(entity);
}
eventObjects.Remove(entity);
//track the event and include in the response if there's still entities remaining in the list
if (list.Count > 0)
// if there are still entities in the list, keep the event definition
if (eventObjects.Count > 0)
{
if (toRemove.Count > 0)
{
//re-assign if the items have changed
args.EventObject = list;
// re-assign if changed
args.EventObject = eventObjects;
}
cancelableArgs.Add(args);
result.Add(eventDefinition);
// track result arguments
// include event definition in result
resultArgs.Add(args);
result.Add(def);
}
}
}
else
{
//it's not a cancelable event arg so we just include it in the result
result.Add(eventDefinition);
}
}
//Now we'll deal with ensuring that only the latest(non stale) entities are used throughout all event args
UpdateToLatestEntities(allEntities, cancelableArgs);
// go over all args in result, and update them with the latest instanceof each entity
UpdateToLatestEntities(entities, resultArgs);
//we need to reverse the result since we've been adding by latest added events first!
// reverse, since we processed the list in reverse
result.Reverse();
return result;
}
private static void UpdateToLatestEntities(IEnumerable<Tuple<IEntity, EventDefinitionTypeData>> allEntities, IEnumerable<CancellableObjectEventArgs> cancelableArgs)
// edits event args to use the latest instance of each entity
private static void UpdateToLatestEntities(IEnumerable<Tuple<IEntity, EventDefinitionInfos>> entities, IEnumerable<CancellableObjectEventArgs> args)
{
//Now we'll deal with ensuring that only the latest(non stale) entities are used throughout all event args
// get the latest entities
// ordered hash set + keepOldest will keep the latest inserted entity (in case of duplicates)
var latestEntities = new OrderedHashSet<IEntity>(keepOldest: true);
foreach (var entity in allEntities.OrderByDescending(entity => entity.Item1.UpdateDate))
{
foreach (var entity in entities.OrderByDescending(entity => entity.Item1.UpdateDate))
latestEntities.Add(entity.Item1);
}
foreach (var args in cancelableArgs)
foreach (var arg in args)
{
var list = TypeHelper.CreateGenericEnumerableFromObject(args.EventObject);
if (list == null)
// event object can either be a single object or an enumerable of objects
// try to get as an enumerable, get null if it's not
var eventObjects = TypeHelper.CreateGenericEnumerableFromObject(arg.EventObject);
if (eventObjects == null)
{
//try to find the args entity in the latest entity - based on the equality operators, this will
//match by Id since that is the default equality checker for IEntity. If one is found, than it is
//the most recent entity instance so update the args with that instance so we don't emit a stale instance.
var foundEntity = latestEntities.FirstOrDefault(x => Equals(x, args.EventObject));
// single object
// look for a more recent entity for that object, and replace if any
// works by "equalling" entities ie the more recent one "equals" this one (though different object)
var foundEntity = latestEntities.FirstOrDefault(x => Equals(x, arg.EventObject));
if (foundEntity != null)
{
args.EventObject = foundEntity;
}
arg.EventObject = foundEntity;
}
else
{
// enumerable of objects
// same as above but for each object
var updated = false;
for (int i = 0; i < list.Count; i++)
for (var i = 0; i < eventObjects.Count; i++)
{
//try to find the args entity in the latest entity - based on the equality operators, this will
//match by Id since that is the default equality checker for IEntity. If one is found, than it is
//the most recent entity instance so update the args with that instance so we don't emit a stale instance.
var foundEntity = latestEntities.FirstOrDefault(x => Equals(x, list[i]));
if (foundEntity != null)
{
list[i] = foundEntity;
updated = true;
}
var foundEntity = latestEntities.FirstOrDefault(x => Equals(x, eventObjects[i]));
if (foundEntity == null) continue;
eventObjects[i] = foundEntity;
updated = true;
}
if (updated)
{
args.EventObject = list;
}
arg.EventObject = eventObjects;
}
}
}
/// <summary>
/// This will check against all of the processed entity/events (allEntities) to see if this entity already exists in
/// event args that supersede the event args being passed in and if so returns true.
/// </summary>
/// <param name="entity"></param>
/// <param name="eventDef"></param>
/// <param name="allEntities"></param>
/// <returns></returns>
private static bool IsFiltered(
IEntity entity,
EventDefinitionTypeData eventDef,
List<Tuple<IEntity, EventDefinitionTypeData>> allEntities)
// determines if a given entity, appearing in a given event definition, should be filtered out,
// considering the entities that have already been visited - an entity is filtered out if it
// appears in another even definition, which superceedes this event definition.
private static bool IsSuperceeded(IEntity entity, EventDefinitionInfos infos, List<Tuple<IEntity, EventDefinitionInfos>> entities)
{
var argType = eventDef.EventDefinition.Args.GetType();
//var argType = meta.EventArgsType;
var argType = infos.EventDefinition.Args.GetType();
//check if the entity is found in any processed event data that could possible supersede this one
var foundByEntity = allEntities
.Where(x => x.Item2.SupersedeAttributes.Length > 0
//if it's the same arg type than it cannot supersede
&& x.Item2.EventArgType != argType
&& Equals(x.Item1, entity))
// look for other instances of the same entity, coming from an event args that supercedes other event args,
// ie is marked with the attribute, and is not this event args (cannot supersede itself)
var superceeding = entities
.Where(x => x.Item2.SupersedeTypes.Length > 0 // has the attribute
&& x.Item2.EventDefinition.Args.GetType() != argType // is not the same
&& Equals(x.Item1, entity)) // same entity
.ToArray();
//no args have been processed with this entity so it should not be filtered
if (foundByEntity.Length == 0)
// first time we see this entity = not filtered
if (superceeding.Length == 0)
return false;
// fixme see notes above
// delete event args does NOT superceedes 'unpublished' event
if (argType.IsGenericType && argType.GetGenericTypeDefinition() == typeof(PublishEventArgs<>) && infos.EventDefinition.EventName == "UnPublished")
return false;
// found occurences, need to determine if this event args is superceded
if (argType.IsGenericType)
{
var supercededBy = foundByEntity
.FirstOrDefault(x =>
x.Item2.SupersedeAttributes.Any(y =>
//if the attribute type is a generic type def then compare with the generic type def of the event arg
(y.SupersededEventArgsType.IsGenericTypeDefinition && y.SupersededEventArgsType == argType.GetGenericTypeDefinition())
//if the attribute type is not a generic type def then compare with the normal type of the event arg
|| (y.SupersededEventArgsType.IsGenericTypeDefinition == false && y.SupersededEventArgsType == argType)));
// generic, must compare type arguments
var supercededBy = superceeding.FirstOrDefault(x =>
x.Item2.SupersedeTypes.Any(y =>
// superceeding a generic type which has the same generic type definition
// fixme no matter the generic type parameters? could be different?
y.IsGenericTypeDefinition && y == argType.GetGenericTypeDefinition()
// or superceeding a non-generic type which is ... fixme how is this ever possible? argType *is* generic?
|| y.IsGenericTypeDefinition == false && y == argType));
return supercededBy != null;
}
else
{
var supercededBy = foundByEntity
.FirstOrDefault(x =>
x.Item2.SupersedeAttributes.Any(y =>
//since the event arg type is not a generic type, then we just compare type 1:1
y.SupersededEventArgsType == argType));
// non-generic, can compare types 1:1
var supercededBy = superceeding.FirstOrDefault(x =>
x.Item2.SupersedeTypes.Any(y => y == argType));
return supercededBy != null;
}
}
+4 -2
View File
@@ -95,8 +95,10 @@ namespace Umbraco.Core.Models
get { return _allowedTemplates; }
set
{
SetPropertyValueAndDetectChanges(value, ref _allowedTemplates, Ps.Value.AllowedTemplatesSelector,
Ps.Value.TemplateComparer);
SetPropertyValueAndDetectChanges(value, ref _allowedTemplates, Ps.Value.AllowedTemplatesSelector, Ps.Value.TemplateComparer);
if (_allowedTemplates.Any(x => x.Id == _defaultTemplate) == false)
DefaultTemplateId = 0;
}
}
@@ -183,17 +183,17 @@ namespace Umbraco.Core.Persistence.Repositories
}
public IEnumerable<IMemberGroup> GetMemberGroupsForMember(string username)
{
var sql = new Sql()
{
var sql = new Sql()
.Select("un.*")
.From("umbracoNode AS un")
.InnerJoin("cmsMember2MemberGroup")
.On("un.id = cmsMember2MemberGroup.MemberGroup")
.LeftJoin("(SELECT umbracoNode.id, cmsMember.LoginName FROM umbracoNode INNER JOIN cmsMember ON umbracoNode.id = cmsMember.nodeId) AS member")
.On("member.id = cmsMember2MemberGroup.Member")
.Where("un.nodeObjectType=@objectType", new {objectType = NodeObjectTypeId })
.Where("member.LoginName=@loginName", new {loginName = username});
.On("cmsMember2MemberGroup.MemberGroup = un.id")
.InnerJoin("cmsMember")
.On("cmsMember.nodeId = cmsMember2MemberGroup.Member")
.Where("un.nodeObjectType=@objectType", new { objectType = NodeObjectTypeId })
.Where("cmsMember.LoginName=@loginName", new { loginName = username });
return Database.Fetch<NodeDto>(sql)
.DistinctBy(dto => dto.NodeId)
.Select(x => _modelFactory.BuildEntity(x));
@@ -20,6 +20,12 @@ namespace Umbraco.Core.Persistence.Repositories
var name = Name;
// cater for instances where node has no name.
if(string.IsNullOrWhiteSpace(name))
{
return _numPos;
}
if (name[name.Length - 1] != ')')
return _numPos = -1;
@@ -106,7 +112,7 @@ namespace Umbraco.Core.Persistence.Repositories
}
}
return uniqueing ? string.Concat(nodeName, " (", uniqueNumber.ToString(), ")") : nodeName;
return uniqueing || string.IsNullOrWhiteSpace(nodeName) ? string.Concat(nodeName, " (", uniqueNumber.ToString(), ")") : nodeName;
}
}
}
@@ -18,6 +18,8 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
return Constants.PropertyEditors.MultipleTextstringAlias.Equals(propertyType.PropertyEditorAlias);
}
private static readonly string[] NewLineDelimiters = { "\r\n", "\r", "\n" };
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
{
// data is (both in database and xml):
@@ -53,7 +55,7 @@ namespace Umbraco.Core.PropertyEditors.ValueConverters
// Fall back on normal behaviour
if (values.Any() == false)
{
return sourceString.Split(new string[] { Environment.NewLine }, StringSplitOptions.None);
return sourceString.Split(NewLineDelimiters, StringSplitOptions.None);
}
return values.ToArray();
+4 -5
View File
@@ -993,8 +993,7 @@ namespace Umbraco.Core.Services
FROM umbracoNode
JOIN cmsDocument ON umbracoNode.id=cmsDocument.nodeId AND cmsDocument.published=@0
WHERE umbracoNode.trashed=@1 AND umbracoNode.id IN (@2)",
true, false, ids);
Console.WriteLine(sql.SQL);
true, false, ids);
var x = uow.Database.Fetch<int>(sql);
return ids.Length == x.Count;
}
@@ -2007,7 +2006,7 @@ namespace Umbraco.Core.Services
}
return true;
}
}
/// <summary>
/// Sorts a collection of <see cref="IContent"/> objects by updating the SortOrder according
@@ -2029,7 +2028,7 @@ namespace Umbraco.Core.Services
using (new WriteLock(Locker))
{
var allContent = GetByIds(ids).ToDictionary(x => x.Id, x => x);
var items = ids.Select(x => allContent[x]);
var items = ids.Select(x => allContent[x]);
using (var uow = UowProvider.GetUnitOfWork())
{
@@ -2839,4 +2838,4 @@ namespace Umbraco.Core.Services
#endregion
}
}
}
@@ -377,7 +377,7 @@ namespace Umbraco.Core.Services
repo.Delete(container);
uow.Commit();
deleteEventArgs.CanCancel = false;
uow.Events.Dispatch(DeletedMediaTypeContainer, this, deleteEventArgs);
uow.Events.Dispatch(DeletedMediaTypeContainer, this, deleteEventArgs, "DeletedMediaTypeContainer");
return OperationStatus.Success(evtMsgs);
//TODO: Audit trail ?
+1 -1
View File
@@ -695,7 +695,7 @@ namespace Umbraco.Core.Services
IQuery<IMember> filterQuery = null;
if (filter.IsNullOrWhiteSpace() == false)
{
filterQuery = Query<IMember>.Builder.Where(x => x.Name.Contains(filter) || x.Username.Contains(filter));
filterQuery = Query<IMember>.Builder.Where(x => x.Name.Contains(filter) || x.Username.Contains(filter) || x.Email.Contains(filter));
}
var repository = RepositoryFactory.CreateMemberRepository(uow);
@@ -1748,9 +1748,10 @@ namespace Umbraco.Core.Services
internal InstallationSummary InstallPackage(string packageFilePath, int userId = 0, bool raiseEvents = false)
{
var metaData = GetPackageMetaData(packageFilePath);
if (raiseEvents)
{
var metaData = GetPackageMetaData(packageFilePath);
{
if (ImportingPackage.IsRaisedEventCancelled(new ImportPackageEventArgs<string>(packageFilePath, metaData), this))
{
var initEmpty = new InstallationSummary().InitEmpty();
@@ -1762,7 +1763,7 @@ namespace Umbraco.Core.Services
if (raiseEvents)
{
ImportedPackage.RaiseEvent(new ImportPackageEventArgs<InstallationSummary>(installationSummary, false), this);
ImportedPackage.RaiseEvent(new ImportPackageEventArgs<InstallationSummary>(installationSummary, metaData, false), this);
}
return installationSummary;
+3 -3
View File
@@ -228,9 +228,9 @@ namespace Umbraco.Core.Services
}
/// <summary>
/// Deletes an <see cref="IUser"/>
/// Disables an <see cref="IUser"/>
/// </summary>
/// <param name="membershipUser"><see cref="IUser"/> to Delete</param>
/// <param name="membershipUser"><see cref="IUser"/> to disable</param>
public void Delete(IUser membershipUser)
{
//disable
@@ -712,7 +712,7 @@ namespace Umbraco.Core.Services
/// <param name="id">Id of the User to retrieve</param>
/// <returns><see cref="IProfile"/></returns>
public IProfile GetProfileById(int id)
{
{
//This is called a TON. Go get the full user from cache which should already be IProfile
var fullUser = GetUserById(id);
var asProfile = fullUser as IProfile;
+21 -3
View File
@@ -3,6 +3,7 @@ using System.Web;
using Umbraco.Core.Configuration;
using Umbraco.Core.Configuration.UmbracoSettings;
using Umbraco.Core.IO;
using Umbraco.Core.Logging;
using Umbraco.Core.ObjectResolution;
namespace Umbraco.Core.Sync
@@ -46,8 +47,20 @@ namespace Umbraco.Core.Sync
// settings: for unit tests only
internal static void EnsureApplicationUrl(ApplicationContext appContext, HttpRequestBase request = null, IUmbracoSettingsSection settings = null)
{
bool newApplicationUrl = false;
if (request != null)
{
var applicationUrl = GetApplicationUrlFromRequest(request);
newApplicationUrl = !appContext._umbracoApplicationDomains.Contains(applicationUrl);
if (newApplicationUrl)
{
appContext._umbracoApplicationDomains.Add(applicationUrl);
LogHelper.Info(typeof(ApplicationUrlHelper), $"New ApplicationUrl detected: {applicationUrl}");
}
}
// if initialized, return
if (appContext._umbracoApplicationUrl != null) return;
if (appContext._umbracoApplicationUrl != null && !newApplicationUrl) return;
var logger = appContext.ProfilingLogger.Logger;
@@ -132,6 +145,12 @@ namespace Umbraco.Core.Sync
{
var logger = appContext.ProfilingLogger.Logger;
appContext._umbracoApplicationUrl = GetApplicationUrlFromRequest(request);
logger.Info(TypeOfApplicationUrlHelper, "ApplicationUrl: " + appContext.UmbracoApplicationUrl + " (UmbracoModule request)");
}
private static string GetApplicationUrlFromRequest(HttpRequestBase request)
{
// if (HTTP and SSL not required) or (HTTPS and SSL required),
// use ports from request
// otherwise,
@@ -147,8 +166,7 @@ namespace Umbraco.Core.Sync
var ssl = useSsl ? "s" : ""; // force, whatever the first request
var url = "http" + ssl + "://" + request.ServerVariables["SERVER_NAME"] + port + IOHelper.ResolveUrl(SystemDirectories.Umbraco);
appContext._umbracoApplicationUrl = url.TrimEnd('/');
logger.Info(TypeOfApplicationUrlHelper, "ApplicationUrl: " + appContext.UmbracoApplicationUrl + " (UmbracoModule request)");
return url.TrimEnd('/');
}
}
}
+3 -12
View File
@@ -39,22 +39,18 @@
<ItemGroup>
<Reference Include="AutoMapper, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="AutoMapper.Net4, Version=3.3.1.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005, processorArchitecture=MSIL">
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="ClientDependency.Core, Version=1.9.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ClientDependency.1.9.2\lib\net45\ClientDependency.Core.dll</HintPath>
<Reference Include="ClientDependency.Core, Version=1.9.5.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ClientDependency.1.9.5\lib\net45\ClientDependency.Core.dll</HintPath>
</Reference>
<Reference Include="HtmlAgilityPack, Version=1.4.9.5, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a, processorArchitecture=MSIL">
<HintPath>..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
<HintPath>..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="ImageProcessor, Version=2.5.6.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ImageProcessor.2.5.6\lib\net45\ImageProcessor.dll</HintPath>
@@ -67,11 +63,9 @@
</Reference>
<Reference Include="Microsoft.AspNet.Identity.Core, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNet.Identity.Core.2.2.1\lib\net45\Microsoft.AspNet.Identity.Core.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.AspNet.Identity.Owin, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNet.Identity.Owin.2.2.1\lib\net45\Microsoft.AspNet.Identity.Owin.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Owin, Version=3.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Owin.3.1.0\lib\net45\Microsoft.Owin.dll</HintPath>
@@ -87,17 +81,16 @@
</Reference>
<Reference Include="MiniProfiler, Version=2.1.0.0, Culture=neutral, PublicKeyToken=b44f9351044011a3, processorArchitecture=MSIL">
<HintPath>..\packages\MiniProfiler.2.1.0\lib\net40\MiniProfiler.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="MySql.Data, Version=6.9.9.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d, processorArchitecture=MSIL">
<HintPath>..\packages\MySql.Data.6.9.9\lib\net45\MySql.Data.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Newtonsoft.Json, Version=10.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="Owin, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f0ebd12fd5e55cc5, processorArchitecture=MSIL">
<HintPath>..\packages\Owin.1.0\lib\net40\Owin.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Semver, Version=1.1.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\semver.1.1.2\lib\net45\Semver.dll</HintPath>
@@ -109,11 +102,9 @@
<Reference Include="System.Data.Entity" />
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Data.SqlServerCe.Entity, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.DirectoryServices.AccountManagement" />
<Reference Include="System.Drawing" />
+1 -1
View File
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AutoMapper" version="3.3.1" targetFramework="net45" />
<package id="ClientDependency" version="1.9.2" targetFramework="net45" />
<package id="ClientDependency" version="1.9.5" targetFramework="net45" />
<package id="HtmlAgilityPack" version="1.4.9.5" targetFramework="net45" />
<package id="ImageProcessor" version="2.5.6" targetFramework="net45" />
<package id="log4net" version="2.0.8" targetFramework="net45" />
@@ -40,34 +40,27 @@
<ItemGroup>
<Reference Include="BenchmarkDotNet, Version=0.9.9.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
<HintPath>..\packages\BenchmarkDotNet.0.9.9\lib\net45\BenchmarkDotNet.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="BenchmarkDotNet.Core, Version=0.9.9.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
<HintPath>..\packages\BenchmarkDotNet.Core.0.9.9\lib\net45\BenchmarkDotNet.Core.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="BenchmarkDotNet.Diagnostics.Windows, Version=0.9.9.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
<HintPath>..\packages\BenchmarkDotNet.Diagnostics.Windows.0.9.9\lib\net45\BenchmarkDotNet.Diagnostics.Windows.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="BenchmarkDotNet.Toolchains.Roslyn, Version=0.9.9.0, Culture=neutral, PublicKeyToken=aa0ca2f9092cefc4, processorArchitecture=MSIL">
<HintPath>..\packages\BenchmarkDotNet.Toolchains.Roslyn.0.9.9\lib\net45\BenchmarkDotNet.Toolchains.Roslyn.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
<HintPath>..\packages\Castle.Core.4.0.0\lib\net45\Castle.Core.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CodeAnalysis, Version=1.3.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.CodeAnalysis.Common.1.3.2\lib\net45\Microsoft.CodeAnalysis.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.CodeAnalysis.CSharp, Version=1.3.1.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.CodeAnalysis.CSharp.1.3.2\lib\net45\Microsoft.CodeAnalysis.CSharp.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.Diagnostics.Tracing.TraceEvent, Version=1.0.41.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Diagnostics.Tracing.TraceEvent.1.0.41\lib\net40\Microsoft.Diagnostics.Tracing.TraceEvent.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Moq, Version=4.1.1309.919, Culture=neutral, PublicKeyToken=69f491c39445e920, processorArchitecture=MSIL">
<HintPath>..\packages\Moq.4.1.1309.0919\lib\net40\Moq.dll</HintPath>
@@ -75,27 +68,22 @@
<Reference Include="System" />
<Reference Include="System.Collections.Immutable, Version=1.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Collections.Immutable.1.2.0\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.Core" />
<Reference Include="System.Data.SqlServerCe, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Data.SqlServerCe.Entity, Version=4.0.0.1, Culture=neutral, PublicKeyToken=89845dcd8080cc91, processorArchitecture=MSIL">
<HintPath>..\packages\SqlServerCE.4.0.0.1\lib\System.Data.SqlServerCe.Entity.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Management" />
<Reference Include="System.Numerics" />
<Reference Include="System.Reflection.Metadata, Version=1.3.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Reflection.Metadata.1.3.0\lib\portable-net45+win8\System.Reflection.Metadata.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Threading.Tasks.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.0.0\lib\portable-net45+win8+wp8+wpa81\System.Threading.Tasks.Extensions.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
@@ -116,6 +104,7 @@
<ItemGroup>
<None Include="App.config" />
<None Include="packages.config" />
<None Include="_TraceEventProgrammersGuide.docx" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Umbraco.Core\Umbraco.Core.csproj">
@@ -132,8 +121,8 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Analyzer Include="..\packages\Microsoft.CodeAnalysis.Analyzers.1.1.0\analyzers\dotnet\cs\Microsoft.CodeAnalysis.Analyzers.dll" />
<Analyzer Include="..\packages\Microsoft.CodeAnalysis.Analyzers.1.1.0\analyzers\dotnet\cs\Microsoft.CodeAnalysis.CSharp.Analyzers.dll" />
<Content Include="TraceEvent.ReadMe.txt" />
<Content Include="TraceEvent.ReleaseNotes.txt" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
@@ -332,6 +332,9 @@ namespace Umbraco.Tests.Persistence.Repositories
var contentType = (IContentType)MockedContentTypes.CreateSimpleContentType2("test", "Test", propertyGroupName: "testGroup");
Assert.AreEqual(4, contentType.PropertyTypes.Count());
// remove all templates - since they are not saved, they would break the (wtf) mapping code
contentType.AllowedTemplates = new ITemplate[0];
// there is NO mapping from display to contentType, but only from save
// to contentType, so if we want to test, let's to it properly!
@@ -24,7 +24,9 @@ namespace Umbraco.Tests.Persistence.Repositories
[TestCase("Alpha (10)", "Alpha (2)", +1)] // this is the real stuff
[TestCase("Kilo", "Golf (2)", +1)]
[TestCase("Kilo (1)", "Golf (2)", +1)]
public void ComparerTest(string name1, string name2, int expected)
[TestCase("", "", 0)]
[TestCase(null, null, 0)]
public void ComparerTest(string name1, string name2, int expected)
{
var comparer = new SimilarNodeName.Comparer();
@@ -76,7 +78,9 @@ namespace Umbraco.Tests.Persistence.Repositories
[TestCase(0, "Alpha", "Alpha (3)")]
[TestCase(0, "Kilo (1)", "Kilo (1) (1)")] // though... we might consider "Kilo (2)"
[TestCase(6, "Kilo (1)", "Kilo (1)")] // because of the id
public void Test(int nodeId, string nodeName, string expected)
[TestCase(0, "", " (1)")]
[TestCase(0, null, " (1)")]
public void Test(int nodeId, string nodeName, string expected)
{
var names = new[]
{
@@ -29,7 +29,7 @@ namespace Umbraco.Tests.PropertyEditors
[Test]
public void ImageCropData_Properties_As_Dynamic()
{
var sourceObj = cropperJson1.SerializeToCropDataSet();
var sourceObj = cropperJson1.DeserializeToCropDataSet();
dynamic d = sourceObj;
var index = 0;
@@ -62,7 +62,7 @@ namespace Umbraco.Tests.PropertyEditors
[Test]
public void ImageCropFocalPoint_Properties_As_Dynamic()
{
var sourceObj = cropperJson1.SerializeToCropDataSet();
var sourceObj = cropperJson1.DeserializeToCropDataSet();
dynamic d = sourceObj;
Assert.AreEqual(sourceObj.FocalPoint.Left, d.FocalPoint.Left);
@@ -75,7 +75,7 @@ namespace Umbraco.Tests.PropertyEditors
[Test]
public void ImageCropDataSet_Properties_As_Dynamic()
{
var sourceObj = cropperJson1.SerializeToCropDataSet();
var sourceObj = cropperJson1.DeserializeToCropDataSet();
dynamic d = sourceObj;
Assert.AreEqual(sourceObj.Src, d.Src);
@@ -91,7 +91,7 @@ namespace Umbraco.Tests.PropertyEditors
[Test]
public void ImageCropDataSet_Methods_As_Dynamic()
{
var sourceObj = cropperJson1.SerializeToCropDataSet();
var sourceObj = cropperJson1.DeserializeToCropDataSet();
dynamic d = sourceObj;
Assert.AreEqual(sourceObj.HasCrop("thumb"), d.HasCrop("thumb"));
@@ -108,7 +108,7 @@ namespace Umbraco.Tests.PropertyEditors
public void CanConvertImageCropperDataSetSrcToString()
{
//cropperJson3 - has not crops
var sourceObj = cropperJson3.SerializeToCropDataSet();
var sourceObj = cropperJson3.DeserializeToCropDataSet();
var destObj = sourceObj.TryConvertTo<string>();
Assert.IsTrue(destObj.Success);
Assert.AreEqual(destObj.Result, "/media/1005/img_0672.jpg");
@@ -118,7 +118,7 @@ namespace Umbraco.Tests.PropertyEditors
public void CanConvertImageCropperDataSetJObject()
{
//cropperJson3 - has not crops
var sourceObj = cropperJson3.SerializeToCropDataSet();
var sourceObj = cropperJson3.DeserializeToCropDataSet();
var destObj = sourceObj.TryConvertTo<JObject>();
Assert.IsTrue(destObj.Success);
Assert.AreEqual(sourceObj, destObj.Result.ToObject<ImageCropDataSet>());
@@ -127,7 +127,7 @@ namespace Umbraco.Tests.PropertyEditors
[Test]
public void CanConvertImageCropperDataSetJsonToString()
{
var sourceObj = cropperJson1.SerializeToCropDataSet();
var sourceObj = cropperJson1.DeserializeToCropDataSet();
var destObj = sourceObj.TryConvertTo<string>();
Assert.IsTrue(destObj.Success);
Assert.IsTrue(destObj.Result.DetectIsJson());
@@ -150,7 +150,7 @@ namespace Umbraco.Tests.PropertyEditors
var converter = new Umbraco.Web.PropertyEditors.ValueConverters.ImageCropperValueConverter(dataTypeService.Object);
var result = converter.ConvertDataToSource(new PublishedPropertyType("test", 0, "test"), val1, false); // does not use type for conversion
var resultShouldMatch = val2.SerializeToCropDataSet();
var resultShouldMatch = val2.DeserializeToCropDataSet();
if (expected)
{
Assert.AreEqual(resultShouldMatch, result);
@@ -220,7 +220,7 @@ namespace Umbraco.Tests.PropertyEditors
[Test]
public void GetBaseCropUrlFromModelTest()
{
var cropDataSet = cropperJson1.SerializeToCropDataSet();
var cropDataSet = cropperJson1.DeserializeToCropDataSet();
var urlString = cropDataSet.GetCropUrl("thumb");
Assert.AreEqual("?crop=0.58729977382575338,0.055768992440203169,0,0.32457553600198386&cropmode=percentage&width=100&height=100", urlString);
}
@@ -3,10 +3,13 @@ using System.Collections.Generic;
using System.Linq;
using Moq;
using NUnit.Framework;
using umbraco.cms.businesslogic;
using Umbraco.Core;
using Umbraco.Core.Events;
using Umbraco.Core.Models;
using Umbraco.Core.Persistence;
using Umbraco.Core.Scoping;
using Umbraco.Core.Services;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.TestHelpers.Entities;
@@ -99,7 +102,7 @@ namespace Umbraco.Tests.Scoping
DoDeleteForContent += OnDoThingFail;
DoForTestArgs += OnDoThingFail;
DoForTestArgs2 += OnDoThingFail;
var contentType = MockedContentTypes.CreateBasicContentType();
var content1 = MockedContent.CreateBasicContent(contentType);
@@ -114,10 +117,10 @@ namespace Umbraco.Tests.Scoping
var scopeProvider = new ScopeProvider(Mock.Of<IDatabaseFactory2>());
using (var scope = scopeProvider.CreateScope(eventDispatcher: new PassiveEventDispatcher()))
{
//content1 will be filtered from the args
scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs<IContent>(new[]{ content1 , content3}));
scope.Events.Dispatch(DoDeleteForContent, this, new DeleteEventArgs<IContent>(content1));
scope.Events.Dispatch(DoDeleteForContent, this, new DeleteEventArgs<IContent>(content1), "DoDeleteForContent");
scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs<IContent>(content2));
//this entire event will be filtered
scope.Events.Dispatch(DoForTestArgs, this, new TestEventArgs(content1));
@@ -141,15 +144,36 @@ namespace Umbraco.Tests.Scoping
}
}
[Test]
public void SupersededEvents2()
{
var contentService = Mock.Of<IContentService>();
var content = Mock.Of<IContent>();
var l1 = new List<IEventDefinition>
{
new EventDefinition<IContentService, PublishEventArgs<IContent>>(Test_UnPublished, contentService, new PublishEventArgs<IContent>(new [] { content }), "UnPublished"),
new EventDefinition<IContentService, DeleteEventArgs<IContent>>(Test_Deleted, contentService, new DeleteEventArgs<IContent>(new [] { content }), "Deleted")
};
var l2 = new OrderedHashSet<IEventDefinition>(keepOldest: false);
foreach (var e in l1)
l2.Add(e);
var l3 = ScopeEventDispatcherBase.FilterSupersededAndUpdateToLatestEntity(l2);
// see U4-10764
Assert.AreEqual(2, l3.Count());
}
/// <summary>
/// This will test that when we track events that before we Get the events we normalize all of the
/// event entities to be the latest one (most current) found amongst the event so that there is
/// event entities to be the latest one (most current) found amongst the event so that there is
/// no 'stale' entities in any of the args
/// </summary>
[Test]
public void LatestEntities()
{
DoSaveForContent += OnDoThingFail;
DoSaveForContent += OnDoThingFail;
var now = DateTime.Now;
var contentType = MockedContentTypes.CreateBasicContentType();
@@ -165,7 +189,7 @@ namespace Umbraco.Tests.Scoping
var scopeProvider = new ScopeProvider(Mock.Of<IDatabaseFactory2>());
using (var scope = scopeProvider.CreateScope(eventDispatcher: new PassiveEventDispatcher()))
{
{
scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs<IContent>(content1));
scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs<IContent>(content2));
scope.Events.Dispatch(DoSaveForContent, this, new SaveEventArgs<IContent>(content3));
@@ -173,7 +197,7 @@ namespace Umbraco.Tests.Scoping
// events have been queued
var events = scope.Events.GetEvents(EventDefinitionFilter.All).ToArray();
Assert.AreEqual(3, events.Length);
foreach (var t in events)
{
var args = (SaveEventArgs<IContent>)t.Args;
@@ -212,7 +236,7 @@ namespace Umbraco.Tests.Scoping
// events have been queued
var events = scope.Events.GetEvents(EventDefinitionFilter.FirstIn).ToArray();
Assert.AreEqual(1, events.Length);
Assert.AreEqual(1, events.Length);
Assert.AreEqual(content1, ((SaveEventArgs<IContent>) events[0].Args).SavedEntities.First());
Assert.IsTrue(object.ReferenceEquals(content1, ((SaveEventArgs<IContent>)events[0].Args).SavedEntities.First()));
Assert.AreEqual(content1.UpdateDate, ((SaveEventArgs<IContent>) events[0].Args).SavedEntities.First().UpdateDate);
@@ -350,6 +374,9 @@ namespace Umbraco.Tests.Scoping
public static event TypedEventHandler<ScopeEventDispatcherTests, SaveEventArgs<decimal>> DoThing3;
public static event TypedEventHandler<IContentService, PublishEventArgs<IContent>> Test_UnPublished;
public static event TypedEventHandler<IContentService, DeleteEventArgs<IContent>> Test_Deleted;
public class TestEventArgs : CancellableObjectEventArgs
{
public TestEventArgs(object eventObject) : base(eventObject)
+2 -2
View File
@@ -62,8 +62,8 @@
<Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
<HintPath>..\packages\Castle.Core.4.0.0\lib\net45\Castle.Core.dll</HintPath>
</Reference>
<Reference Include="Examine, Version=0.1.88.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.88\lib\net45\Examine.dll</HintPath>
<Reference Include="Examine, Version=0.1.89.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.89\lib\net45\Examine.dll</HintPath>
</Reference>
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
<HintPath>..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
+1 -1
View File
@@ -2,7 +2,7 @@
<packages>
<package id="AutoMapper" version="3.3.1" targetFramework="net45" />
<package id="Castle.Core" version="4.0.0" targetFramework="net45" />
<package id="Examine" version="0.1.88" targetFramework="net45" />
<package id="Examine" version="0.1.89" targetFramework="net45" />
<package id="log4net" version="2.0.8" targetFramework="net45" />
<package id="Log4Net.Async" version="2.0.4" targetFramework="net45" />
<package id="Lucene.Net" version="2.9.4.1" targetFramework="net45" />
+1 -1
View File
@@ -26,7 +26,7 @@
"cssnano": "^3.7.6",
"gulp": "^3.9.1",
"gulp-concat": "^2.6.0",
"gulp-connect": "^5.0.0",
"gulp-connect": "5.0.0",
"gulp-less": "^3.1.0",
"gulp-ngdocs": "^0.3.0",
"gulp-open": "^2.0.0",
@@ -366,6 +366,9 @@ angular.module("umbraco.directives")
// element might still be there even after the modal has been hidden.
scope.$on('$destroy', function () {
unsubscribe();
if (tinyMceEditor !== undefined && tinyMceEditor != null) {
tinyMceEditor.destroy()
}
});
});
@@ -77,7 +77,7 @@
@param {string} icon (<code>binding</code>): The node icon.
@param {string} name (<code>binding</code>): The node name.
@param {boolean} published (<code>binding</code>): The node pusblished state.
@param {boolean} published (<code>binding</code>): The node published state.
@param {string} description (<code>binding</code>): A short description.
@param {boolean} sortable (<code>binding</code>): Will add a move cursor on the node preview. Can used in combination with ui-sortable.
@param {boolean} allowRemove (<code>binding</code>): Show/Hide the remove button.
@@ -1,4 +1,15 @@
(function () {
/**
@ngdoc directive
@name umbraco.directives.directive:umbPasswordToggle
@restrict E
@scope
@description
<strong>Added in Umbraco v. 7.7.4:</strong> Use this directive to render a password toggle.
**/
(function () {
'use strict';
// comes from https://codepen.io/jakob-e/pen/eNBQaP
@@ -1,3 +1,114 @@
/**
@ngdoc directive
@name umbraco.directives.directive:umbTable
@restrict E
@scope
@description
<strong>Added in Umbraco v. 7.4:</strong> Use this directive to render a data table.
<h3>Markup example</h3>
<pre>
<div ng-controller="My.TableController as vm">
<umb-table
ng-if="items"
items="vm.items"
item-properties="vm.options.includeProperties"
allow-select-all="vm.allowSelectAll"
on-select="vm.selectItem"
on-click="vm.clickItem"
on-select-all="vm.selectAll"
on-selected-all="vm.isSelectedAll"
on-sorting-direction="vm.isSortDirection"
on-sort="vm.sort">
</umb-table>
</div>
</pre>
<h3>Controller example</h3>
<pre>
(function () {
"use strict";
function Controller() {
var vm = this;
vm.items = [
{
"icon": "icon-document",
"name": "My node 1",
"published": true,
"description": "A short description of my node",
"author": "Author 1"
},
{
"icon": "icon-document",
"name": "My node 2",
"published": true,
"description": "A short description of my node",
"author": "Author 2"
}
];
vm.options = {
includeProperties: [
{ alias: "description", header: "Description" },
{ alias: "author", header: "Author" }
]
};
vm.selectItem = selectItem;
vm.clickItem = clickItem;
vm.selectAll = selectAll;
vm.isSelectedAll = isSelectedAll;
vm.isSortDirection = isSortDirection;
vm.sort = sort;
function selectAll($event) {
alert("select all");
}
function isSelectedAll() {
}
function clickItem(item) {
alert("click node");
}
function selectItem(selectedItem, $index, $event) {
alert("select node");
}
function isSortDirection(col, direction) {
}
function sort(field, allow, isSystem) {
}
}
angular.module("umbraco").controller("My.TableController", Controller);
})();
</pre>
@param {string} icon (<code>binding</code>): The node icon.
@param {string} name (<code>binding</code>): The node name.
@param {string} published (<code>binding</code>): The node published state.
@param {function} onSelect (<code>expression</code>): Callback function when the row is selected.
@param {function} onClick (<code>expression</code>): Callback function when the "Name" column link is clicked.
@param {function} onSelectAll (<code>expression</code>): Callback function when selecting all items.
@param {function} onSelectedAll (<code>expression</code>): Callback function when all items are selected.
@param {function} onSortingDirection (<code>expression</code>): Callback function when sorting direction is changed.
@param {function} onSort (<code>expression</code>): Callback function when sorting items.
**/
(function () {
'use strict';
@@ -9,9 +9,14 @@ function noDirtyCheck() {
restrict: 'A',
require: 'ngModel',
link: function (scope, elm, attrs, ctrl) {
elm.focus(function () {
ctrl.$pristine = false;
scope.$watch(function() {
ctrl.$pristine = false;
});
});
}
};
}
@@ -18,7 +18,7 @@
<div class="control-group">
<label class="control-label" for="email">Email</label>
<div class="controls">
<input type="email" id="email" name="email" placeholder="you@example.com" required ng-model="installer.current.model.email" val-email />
<input type="email" id="email" name="email" placeholder="you@example.com" val-email required ng-model="installer.current.model.email" />
<small class="inline-help">Your email will be used as your login</small>
</div>
</div>
@@ -535,7 +535,7 @@
color: @gray-3;
}
.umb-grid .umb-cell-rte textarea {
.umb-grid .umb-cell-rte textarea.mceNoEditor {
display: none !important;
}
@@ -37,6 +37,7 @@
.umb-node-preview__content {
flex: 1 1 auto;
margin-right: 25px;
overflow: hidden;
}
.umb-node-preview__name {
@@ -50,6 +51,13 @@
color: @gray-3;
}
.umb-node-preview__name,
.umb-node-preview__description {
/*text-overflow: ellipsis;
overflow: hidden;*/
word-wrap: break-word;
}
.umb-node-preview__actions {
flex: 0 0 auto;
display: flex;
@@ -281,6 +281,12 @@ ul.color-picker li a {
display: block;
}
.umb-sortable-thumbnails .umb-sortable-thumbnails__wrapper {
width: 120px;
height: 114px;
overflow: hidden;
}
.umb-sortable-thumbnails .umb-sortable-thumbnails__actions {
position: absolute;
bottom: 10px;
@@ -308,6 +314,7 @@ ul.color-picker li a {
justify-content: center;
align-items: center;
margin-left: 5px;
text-decoration: none;
}
.umb-sortable-thumbnails .umb-sortable-thumbnails__action.-red {
@@ -240,6 +240,7 @@
.umb-tree .umb-tree-node-checked i:before {
/*check box*/
content: "\e165" !important;
font-family: inherit;
}
a.umb-options {
@@ -1,7 +1,7 @@
<div class="umb-panel" ng-controller="Umbraco.Dialogs.IconPickerController">
<div class="umb-panel-header">
<div class="umb-el-wrap umb-panel-buttons">
<div class="form-search">
<div class="umb-panel-header">
<div class="umb-el-wrap umb-panel-buttons">
<div class="form-search">
<i class="icon-search"></i>
<input type="text"
style="width: 100%"
@@ -9,50 +9,49 @@
class="umb-search-field search-query input-block-level"
localize="placeholder"
placeholder="@placeholders_filter"
no-dirty-check>
no-dirty-check />
</div>
</div>
</div>
</div>
</div>
<div class="umb-panel-body with-footer">
<div class="umb-panel-body with-footer">
<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>
</select>
<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>
</select>
</div>
<umb-load-indicator ng-if="loading"></umb-load-indicator>
<div class="umb-control-group" ng-show="!loading">
<ul class="umb-iconpicker" ng-class="color" ng-show="icons">
<li class="umb-iconpicker-item" ng-repeat="icon in filtered = (icons | filter: searchTerm) track by $id(icon)">
<a href="#" title="{{icon}}" ng-click="submitClass(icon)" prevent-default>
<i class="{{icon}} large"></i>
</a>
</li>
</ul>
</div>
<ul class="umb-iconpicker" ng-class="color" ng-show="icons">
<li class="umb-iconpicker-item" ng-repeat="icon in filtered = (icons | filter: searchTerm) track by $id(icon)">
<a href="#" title="{{icon}}" ng-click="submitClass(icon)" prevent-default>
<i class="{{icon}} large"></i>
</a>
</li>
</ul>
</div>
<umb-empty-state
ng-if="filtered.length === 0"
position="center">
<localize key="defaultdialogs_noIconsFound">No icons were found.</localize>
</umb-empty-state>
</div>
<umb-empty-state ng-if="filtered.length === 0"
position="center">
<localize key="defaultdialogs_noIconsFound">No icons were found.</localize>
</umb-empty-state>
</div>
<div class="umb-panel-footer" >
<div class="umb-el-wrap umb-panel-buttons">
<div class="btn-toolbar umb-btn-toolbar pull-right">
<a href ng-click="close()" class="btn btn-link">
<localize key="general_cancel">Cancel</localize>
</a>
</div>
</div>
</div>
<div class="umb-panel-footer">
<div class="umb-el-wrap umb-panel-buttons">
<div class="btn-toolbar umb-btn-toolbar pull-right">
<a href ng-click="close()" class="btn btn-link">
<localize key="general_cancel">Cancel</localize>
</a>
</div>
</div>
</div>
</div>
@@ -61,22 +61,23 @@
<div class="umb-panel umb-dialogs-mediapicker browser"
on-drag-leave="dragLeave()"
on-drag-end="dragLeave()"
on-drag-enter="dragEnter()"
ng-hide="target">
on-drag-leave="dragLeave()"
on-drag-end="dragLeave()"
on-drag-enter="dragEnter()"
ng-hide="target">
<div class="umb-panel-header">
<div class="umb-el-wrap umb-panel-buttons umb-mediapicker-upload">
<div class="form-search">
<i class="icon-search"></i>
<input type="text"
ng-model="searchTerm"
class="umb-search-field search-query"
localize="placeholder"
placeholder="@placeholders_filter">
<div class="form-search">
<i class="icon-search"></i>
<input type="text"
ng-model="searchTerm"
class="umb-search-field search-query"
localize="placeholder"
placeholder="@placeholders_filter"
no-dirty-check />
</div>
<div class="upload-button">
@@ -97,7 +98,7 @@
<li ng-repeat="item in path">
<a href ng-click="gotoFolder(item)" prevent-default>{{item.name}}</a> /
</li>
<li>
<a href ng-hide="showFolderInput" ng-click="showFolderInput = true">
<i class="icon icon-add small"></i>
@@ -114,28 +115,26 @@
</ul>
</div>
</div>
<div class="umb-panel-body with-footer">
<umb-file-dropzone
ng-if="acceptedMediatypes.length > 0"
accepted-mediatypes="acceptedMediatypes"
hide-dropzone="{{!activeDrag && images.length > 0}}"
parent-id="{{currentFolder.id}}"
files-uploaded="onUploadComplete"
files-queued="onFilesQueue">
<umb-file-dropzone ng-if="acceptedMediatypes.length > 0"
accepted-mediatypes="acceptedMediatypes"
hide-dropzone="{{!activeDrag && images.length > 0}}"
parent-id="{{currentFolder.id}}"
files-uploaded="onUploadComplete"
files-queued="onFilesQueue">
</umb-file-dropzone>
<umb-photo-folder
min-height="105"
min-width="150"
max-height="250"
ideal-items-per-row="3"
on-click="clickHandler"
ng-model="images"
images-only="{{onlyImages}}"
filter-by="searchTerm" />
<umb-photo-folder min-height="105"
min-width="150"
max-height="250"
ideal-items-per-row="3"
on-click="clickHandler"
ng-model="images"
images-only="{{onlyImages}}"
filter-by="searchTerm" />
</div>
@@ -1,7 +1,7 @@
<div class="umb-panel" ng-controller="Umbraco.Dialogs.MemberGroupPickerController">
<div class="umb-panel-body with-footer no-header">
<div>
<umb-tree section="member"
treealias="memberGroups"
@@ -14,21 +14,21 @@
</div>
</div>
<div class="umb-panel-footer" >
<div class="umb-el-wrap umb-panel-buttons">
<div class="btn-toolbar umb-btn-toolbar pull-right">
<div class="umb-panel-footer">
<div class="umb-el-wrap umb-panel-buttons">
<div class="btn-toolbar umb-btn-toolbar pull-right">
<a href ng-click="close()" class="btn btn-link">
<localize key="general_cancel">Cancel</localize>
</a>
<a href ng-click="close()" class="btn btn-link">
<localize key="general_cancel">Cancel</localize>
</a>
<button class="btn btn-primary"
ng-click="submit(dialogData.selection)">
<localize key="buttons_select">Select</localize>
({{dialogData.selection.length}})
</button>
<button class="btn btn-primary"
ng-click="submit(dialogData.selection)">
<localize key="buttons_select">Select</localize>
({{dialogData.selection.length}})
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
@@ -7,9 +7,10 @@
style="width: 100%"
ng-model="searchTerm"
class="umb-search-field search-query input-block-level"
localize="placeholder"
placeholder="@placeholders_filter"
umb-auto-focus>
localize="placeholder"
placeholder="@placeholders_filter"
umb-auto-focus
no-dirty-check />
</div>
</div>
@@ -17,20 +18,17 @@
<localize key="contentTypeEditor_compositionsDescription"></localize>
</div>
<umb-empty-state
ng-if="model.availableCompositeContentTypes.length === 0 && model.totalContentTypes <= 1"
position="center">
<localize key="contentTypeEditor_noAvailableCompositions"></localize>
<umb-empty-state ng-if="model.availableCompositeContentTypes.length === 0 && model.totalContentTypes <= 1"
position="center">
<localize key="contentTypeEditor_noAvailableCompositions"></localize>
</umb-empty-state>
<umb-empty-state
ng-if="model.availableCompositeContentTypes.length === 0 && model.totalContentTypes > 1"
position="center">
<localize key="contentTypeEditor_compositionInUse"></localize>
<umb-empty-state ng-if="model.availableCompositeContentTypes.length === 0 && model.totalContentTypes > 1"
position="center">
<localize key="contentTypeEditor_compositionInUse"></localize>
</umb-empty-state>
<ul class="umb-checkbox-list">
<li class="umb-checkbox-list__item"
ng-repeat="compositeContentType in model.availableCompositeContentTypes | filter:searchTerm"
ng-class="{'-disabled': compositeContentType.allowed===false || compositeContentType.inherited, '-selected': vm.isSelected(compositeContentType.contentType.alias)}">
@@ -41,7 +39,7 @@
checklist-model="model.compositeContentTypes"
checklist-value="compositeContentType.contentType.alias"
ng-change="model.selectCompositeContentType(compositeContentType.contentType)"
ng-disabled="compositeContentType.allowed===false || compositeContentType.inherited"/>
ng-disabled="compositeContentType.allowed===false || compositeContentType.inherited" />
</div>
<label for="umb-overlay-comp-{{compositeContentType.contentType.key}}" class="umb-checkbox-list__item-text" ng-class="{'-faded': compositeContentType.allowed===false}">
@@ -1,117 +1,100 @@
<div class="umb-overlay-body" ng-controller="Umbraco.Overlays.EditorPickerOverlay as vm">
<!-- FILTER -->
<div class="umb-control-group -no-border">
<div class="form-search">
<i class="icon-search"></i>
<input type="text"
style="width: 100%"
ng-change="vm.filterItems()"
ng-model="vm.searchTerm"
class="umb-search-field search-query search-input input-block-level"
localize="placeholder"
placeholder="@placeholders_filter"
umb-auto-focus>
</div>
</div>
<umb-load-indicator ng-if="vm.loading"></umb-load-indicator>
<!-- TABS -->
<div ng-if="vm.showTabs">
<umb-tabs-nav model="vm.tabs"></umb-tabs-nav>
<umb-tabs-content>
<umb-tab id="tab{{tab.id}}" ng-repeat="tab in vm.tabs" rel="{{tab.id}}">
<div ng-if="tab.alias==='Default'">
<div ng-repeat="(key,value) in tab.typesAndEditors">
<h5>{{key}}</h5>
<ul class="umb-card-grid" ng-mouseleave="vm.hideDetailsOverlay()">
<li ng-repeat="systemDataType in value | orderBy:'name'"
ng-mouseover="vm.showDetailsOverlay(systemDataType)"
ng-click="vm.pickEditor(systemDataType)"
class="-four-in-row">
<a class="umb-card-grid-item" href="" title="{{ systemDataType.name }}">
<i class="{{ systemDataType.icon }}" ng-class="{'icon-autofill': systemDataType.icon == null}"></i>
{{ systemDataType.name }}
</a>
</li>
</ul>
</div>
</div>
<div ng-if="tab.alias==='Reuse'">
<div ng-repeat="(key,value) in tab.userConfigured">
<h5>{{key}}</h5>
<ul class="umb-card-grid" ng-mouseleave="vm.hideDetailsOverlay()">
<li ng-repeat="dataType in value | orderBy:'name'"
ng-mouseover="vm.showDetailsOverlay(dataType)"
ng-click="vm.pickDataType(dataType)"
class="-four-in-row">
<a class="umb-card-grid-item" href="" title="{{ dataType.name }}">
<i class="{{ dataType.icon }}" ng-class="{'icon-autofill': dataType.icon == null}"></i>
{{ dataType.name }}
</a>
</li>
</ul>
</div>
</div>
</umb-tab>
</umb-tabs-content>
</div>
<!-- FILTER RESULTS -->
<div ng-if="vm.showFilterResult">
<h5 class="-border-bottom -black"><localize key="contentTypeEditor_reuse"></localize></h5>
<div ng-repeat="(key,value) in vm.userConfigured">
<div ng-if="(value | filter:vm.searchTerm).length > 0">
<h5>{{key}}</h5>
<ul class="umb-card-grid" ng-mouseleave="vm.hideDetailsOverlay()">
<li ng-repeat="dataType in value | orderBy:'name' | filter: vm.searchTerm"
ng-mouseover="vm.showDetailsOverlay(dataType)"
ng-click="vm.pickDataType(dataType)"
class="-four-in-row">
<a class="umb-card-grid-item" href="" title="{{ dataType.name }}">
<i class="{{ dataType.icon }}" ng-class="{'icon-autofill': dataType.icon == null}"></i>
{{ dataType.name }}
</a>
</li>
</ul>
</div>
</div>
<h5 class="-border-bottom -black"><localize key="contentTypeEditor_availableEditors"></localize></h5>
<div ng-repeat="(key,value) in vm.typesAndEditors">
<div ng-if="(value | filter:vm.searchTerm).length > 0">
<h5>{{key}}</h5>
<ul class="umb-card-grid" ng-mouseleave="vm.hideDetailsOverlay()">
<li ng-repeat="systemDataType in value | orderBy:'name' | filter: vm.searchTerm"
ng-mouseover="vm.showDetailsOverlay(systemDataType)"
ng-click="vm.pickEditor(systemDataType)"
class="-four-in-row">
<a class="umb-card-grid-item" href="" title="{{ systemDataType.name }}">
<i class="{{ systemDataType.icon }}" ng-class="{'icon-autofill': systemDataType.icon == null}"></i>
{{ systemDataType.name }}
</a>
</li>
</ul>
</div>
</div>
</div>
<umb-overlay
ng-if="vm.editorSettingsOverlay.show"
model="vm.editorSettingsOverlay"
position="right"
view="vm.editorSettingsOverlay.view">
</umb-overlay>
<!-- FILTER -->
<div class="umb-control-group -no-border">
<div class="form-search">
<i class="icon-search"></i>
<input type="text"
style="width: 100%"
ng-change="vm.filterItems()"
ng-model="vm.searchTerm"
class="umb-search-field search-query search-input input-block-level"
localize="placeholder"
placeholder="@placeholders_filter"
umb-auto-focus
no-dirty-check />
</div>
</div>
<umb-load-indicator ng-if="vm.loading"></umb-load-indicator>
<!-- TABS -->
<div ng-if="vm.showTabs">
<umb-tabs-nav model="vm.tabs"></umb-tabs-nav>
<umb-tabs-content>
<umb-tab id="tab{{tab.id}}" ng-repeat="tab in vm.tabs" rel="{{tab.id}}">
<div ng-if="tab.alias==='Default'">
<div ng-repeat="(key,value) in tab.typesAndEditors">
<h5>{{key}}</h5>
<ul class="umb-card-grid" ng-mouseleave="vm.hideDetailsOverlay()">
<li ng-repeat="systemDataType in value | orderBy:'name'"
ng-mouseover="vm.showDetailsOverlay(systemDataType)"
ng-click="vm.pickEditor(systemDataType)"
class="-four-in-row">
<a class="umb-card-grid-item" href="" title="{{ systemDataType.name }}">
<i class="{{ systemDataType.icon }}" ng-class="{'icon-autofill': systemDataType.icon == null}"></i>
{{ systemDataType.name }}
</a>
</li>
</ul>
</div>
</div>
<div ng-if="tab.alias==='Reuse'">
<div ng-repeat="(key,value) in tab.userConfigured">
<h5>{{key}}</h5>
<ul class="umb-card-grid" ng-mouseleave="vm.hideDetailsOverlay()">
<li ng-repeat="dataType in value | orderBy:'name'"
ng-mouseover="vm.showDetailsOverlay(dataType)"
ng-click="vm.pickDataType(dataType)"
class="-four-in-row">
<a class="umb-card-grid-item" href="" title="{{ dataType.name }}">
<i class="{{ dataType.icon }}" ng-class="{'icon-autofill': dataType.icon == null}"></i>
{{ dataType.name }}
</a>
</li>
</ul>
</div>
</div>
</umb-tab>
</umb-tabs-content>
</div>
<!-- FILTER RESULTS -->
<div ng-if="vm.showFilterResult">
<h5 class="-border-bottom -black"><localize key="contentTypeEditor_reuse"></localize></h5>
<div ng-repeat="(key,value) in vm.userConfigured">
<div ng-if="(value | filter:vm.searchTerm).length > 0">
<h5>{{key}}</h5>
<ul class="umb-card-grid" ng-mouseleave="vm.hideDetailsOverlay()">
<li ng-repeat="dataType in value | orderBy:'name' | filter: vm.searchTerm"
ng-mouseover="vm.showDetailsOverlay(dataType)"
ng-click="vm.pickDataType(dataType)"
class="-four-in-row">
<a class="umb-card-grid-item" href="" title="{{ dataType.name }}">
<i class="{{ dataType.icon }}" ng-class="{'icon-autofill': dataType.icon == null}"></i>
{{ dataType.name }}
</a>
</li>
</ul>
</div>
</div>
<h5 class="-border-bottom -black"><localize key="contentTypeEditor_availableEditors"></localize></h5>
<div ng-repeat="(key,value) in vm.typesAndEditors">
<div ng-if="(value | filter:vm.searchTerm).length > 0">
<h5>{{key}}</h5>
<ul class="umb-card-grid" ng-mouseleave="vm.hideDetailsOverlay()">
<li ng-repeat="systemDataType in value | orderBy:'name' | filter: vm.searchTerm"
ng-mouseover="vm.showDetailsOverlay(systemDataType)"
ng-click="vm.pickEditor(systemDataType)"
class="-four-in-row">
<a class="umb-card-grid-item" href="" title="{{ systemDataType.name }}">
<i class="{{ systemDataType.icon }}" ng-class="{'icon-autofill': systemDataType.icon == null}"></i>
{{ systemDataType.name }}
</a>
</li>
</ul>
</div>
</div>
</div>
<umb-overlay ng-if="vm.editorSettingsOverlay.show"
model="vm.editorSettingsOverlay"
position="right"
view="vm.editorSettingsOverlay.view">
</umb-overlay>
</div>
@@ -10,7 +10,7 @@
localize="placeholder"
placeholder="@placeholders_filter"
umb-auto-focus
no-dirty-check>
no-dirty-check />
</div>
</div>
@@ -1,25 +1,25 @@
<div ng-controller="Umbraco.Overlays.ItemPickerOverlay">
<div class="form-search" ng-hide="model.filter === false" style="margin-bottom: 15px;">
<i class="icon-search"></i>
<input type="text"
ng-model="searchTerm"
class="umb-search-field search-query input-block-level -full-width-input"
localize="placeholder"
placeholder="@placeholders_filter"
umb-auto-focus />
<i class="icon-search"></i>
<input type="text"
ng-model="searchTerm"
class="umb-search-field search-query input-block-level -full-width-input"
localize="placeholder"
placeholder="@placeholders_filter"
umb-auto-focus
no-dirty-check />
</div>
<ul class="umb-card-grid">
<li
ng-repeat="availableItem in model.availableItems | compareArrays:model.selectedItems:'alias' | orderBy:'name' | filter:searchTerm"
ng-click="selectItem(availableItem)"
class="-three-in-row">
<a class="umb-card-grid-item" href="" title="{{ availableItem.name }}">
<i class="{{ availableItem.icon }}"></i>
{{ availableItem.name }}
</a>
</li>
<li ng-repeat="availableItem in model.availableItems | compareArrays:model.selectedItems:'alias' | orderBy:'name' | filter:searchTerm"
ng-click="selectItem(availableItem)"
class="-three-in-row">
<a class="umb-card-grid-item" href="" title="{{ availableItem.name }}">
<i class="{{ availableItem.icon }}"></i>
{{ availableItem.name }}
</a>
</li>
</ul>
</div>
@@ -13,7 +13,8 @@
class="umb-search-field search-query input-block-level"
localize="placeholder"
placeholder="@placeholders_filter"
umb-auto-focus />
umb-auto-focus
no-dirty-check />
</div>
<ul class="umb-card-grid">
@@ -27,9 +28,8 @@
</li>
</ul>
<umb-empty-state
ng-if="nomacros"
position="center">
<umb-empty-state ng-if="nomacros"
position="center">
<localize key="defaultdialogs_noMacros">
There are no macros available to insert
</localize>
@@ -52,9 +52,8 @@
</li>
</ul>
<umb-empty-state
ng-if="noMacroParams"
position="center">
<umb-empty-state ng-if="noMacroParams"
position="center">
<localize key="defaultdialogs_noMacroParams">There are no parameters for this macro</localize>
</umb-empty-state>
@@ -3,159 +3,147 @@
enctype="multipart/form-data"
umb-image-upload="options">
<div
on-drag-leave="dragLeave()"
on-drag-end="dragLeave()"
on-drag-enter="dragEnter()">
<div on-drag-leave="dragLeave()"
on-drag-end="dragLeave()"
on-drag-enter="dragEnter()">
<div class="umb-control-group umb-mediapicker-upload">
<div class="umb-control-group umb-mediapicker-upload">
<umb-load-indicator
ng-if="loading">
</umb-load-indicator>
<umb-load-indicator ng-if="loading">
</umb-load-indicator>
<div class="form-search">
<i class="icon-search"></i>
<input
class="umb-search-field search-query -full-width-input"
ng-model="searchOptions.filter"
localize="placeholder"
placeholder="@placeholders_search"
ng-change="changeSearch()"
type="text">
</div>
<div class="form-search">
<i class="icon-search"></i>
<input class="umb-search-field search-query -full-width-input"
ng-model="searchOptions.filter"
localize="placeholder"
placeholder="@placeholders_search"
ng-change="changeSearch()"
type="text"
no-dirty-check />
</div>
<div class="upload-button">
<umb-button
type="button"
label-key="general_upload"
action="upload()"
disabled="lockedFolder">
</umb-button>
</div>
<div class="upload-button">
<umb-button type="button"
label-key="general_upload"
action="upload()"
disabled="lockedFolder">
</umb-button>
</div>
</div>
</div>
<div class="row umb-control-group" ng-show="!searchOptions.filter">
<ul class="umb-breadcrumbs">
<li ng-hide="startNodeId != -1" class="umb-breadcrumbs__ancestor">
<a href ng-click="gotoFolder()" prevent-default>Media</a>
<span class="umb-breadcrumbs__seperator">&#47;</span>
</li>
<div class="row umb-control-group" ng-show="!searchOptions.filter">
<ul class="umb-breadcrumbs">
<li ng-hide="startNodeId != -1" class="umb-breadcrumbs__ancestor">
<a href ng-click="gotoFolder()" prevent-default>Media</a>
<span class="umb-breadcrumbs__seperator">&#47;</span>
</li>
<li ng-repeat="item in path" class="umb-breadcrumbs__ancestor">
<a href ng-click="gotoFolder(item)" prevent-default>{{item.name}}</a>
<span class="umb-breadcrumbs__seperator">&#47;</span>
</li>
<li ng-repeat="item in path" class="umb-breadcrumbs__ancestor">
<a href ng-click="gotoFolder(item)" prevent-default>{{item.name}}</a>
<span class="umb-breadcrumbs__seperator">&#47;</span>
</li>
<li class="umb-breadcrumbs__ancestor" ng-show="!lockedFolder">
<a href ng-hide="showFolderInput" ng-click="showFolderInput = true">
<i class="icon icon-add small"></i>
</a>
<li class="umb-breadcrumbs__ancestor" ng-show="!lockedFolder">
<a href ng-hide="showFolderInput" ng-click="showFolderInput = true">
<i class="icon icon-add small"></i>
</a>
<input
type="text"
class="umb-breadcrumbs__add-ancestor"
ng-show="showFolderInput"
ng-model="newFolderName"
ng-keydown="enterSubmitFolder($event)"
on-blur="submitFolder()"
focus-when="{{showFolderInput}}" />
</li>
</ul>
<div class="umb-loader" ng-if="creatingFolder"></div>
</div>
<input type="text"
class="umb-breadcrumbs__add-ancestor"
ng-show="showFolderInput"
ng-model="newFolderName"
ng-keydown="enterSubmitFolder($event)"
on-blur="submitFolder()"
focus-when="{{showFolderInput}}" />
</li>
</ul>
<div class="umb-loader" ng-if="creatingFolder"></div>
</div>
<umb-file-dropzone
ng-if="acceptedMediatypes.length > 0 && !loading && !lockedFolder"
accepted-mediatypes="acceptedMediatypes"
parent-id="{{currentFolder.id}}"
files-uploaded="onUploadComplete"
files-queued="onFilesQueue"
accept="{{acceptedFileTypes}}"
max-file-size="{{maxFileSize}}"
hide-dropzone="{{!activeDrag && images.length > 0 || searchOptions.filter }}"
compact="{{ images.length > 0 }}">
</umb-file-dropzone>
<umb-file-dropzone ng-if="acceptedMediatypes.length > 0 && !loading && !lockedFolder"
accepted-mediatypes="acceptedMediatypes"
parent-id="{{currentFolder.id}}"
files-uploaded="onUploadComplete"
files-queued="onFilesQueue"
accept="{{acceptedFileTypes}}"
max-file-size="{{maxFileSize}}"
hide-dropzone="{{!activeDrag && images.length > 0 || searchOptions.filter }}"
compact="{{ images.length > 0 }}">
</umb-file-dropzone>
<umb-media-grid
ng-if="!loading"
items="images"
on-click="clickHandler"
on-click-name="clickItemName"
item-max-width="150"
item-max-height="150"
item-min-width="100"
item-min-height="100"
only-images={{onlyImages}}>
</umb-media-grid>
<umb-media-grid ng-if="!loading"
items="images"
on-click="clickHandler"
on-click-name="clickItemName"
item-max-width="150"
item-max-height="150"
item-min-width="100"
item-min-height="100"
only-images={{onlyImages}}>
</umb-media-grid>
<div class="flex justify-center">
<umb-pagination
ng-if="searchOptions.totalPages > 0 && !loading"
page-number="searchOptions.pageNumber"
total-pages="searchOptions.totalPages"
on-change="changePagination(pageNumber)">
<umb-pagination ng-if="searchOptions.totalPages > 0 && !loading"
page-number="searchOptions.pageNumber"
total-pages="searchOptions.totalPages"
on-change="changePagination(pageNumber)">
</umb-pagination>
</div>
<umb-empty-state
ng-if="searchOptions.filter && images.length === 0 && !loading"
position="center">
<umb-empty-state ng-if="searchOptions.filter && images.length === 0 && !loading"
position="center">
<localize key="general_searchNoResult"></localize>
</umb-empty-state>
</div>
</div>
<umb-overlay
ng-if="mediaPickerDetailsOverlay.show"
model="mediaPickerDetailsOverlay"
position="right">
<umb-overlay ng-if="mediaPickerDetailsOverlay.show"
model="mediaPickerDetailsOverlay"
position="right">
<div class="umb-control-group">
<div class="umb-control-group">
<div ng-if="target.url">
<umb-image-gravity
src="target.url"
center="target.focalPoint">
</umb-image-gravity>
</div>
<div ng-if="target.url">
<umb-image-gravity src="target.url"
center="target.focalPoint">
</umb-image-gravity>
</div>
<div ng-if="cropSize">
<div ng-if="cropSize">
<h5>
<localize key="general_preview">Preview</localize>
</h5>
<h5>
<localize key="general_preview">Preview</localize>
</h5>
<umb-image-thumbnail
center="target.focalPoint"
src="target.url"
height="{{cropSize.height}}"
width="{{cropSize.width}}"
max-size="400">
</umb-image-thumbnail>
<umb-image-thumbnail center="target.focalPoint"
src="target.url"
height="{{cropSize.height}}"
width="{{cropSize.width}}"
max-size="400">
</umb-image-thumbnail>
</div>
</div>
</div>
</div>
<div class="umb-control-group">
<label><localize key="@general_url"></localize></label>
<input
type="text"
localize="placeholder"
placeholder="@general_url"
class="umb-editor umb-textstring"
ng-model="target.url"
ng-disabled="target.id" />
</div>
<div class="umb-control-group">
<label><localize key="@general_url"></localize></label>
<input type="text"
localize="placeholder"
placeholder="@general_url"
class="umb-editor umb-textstring"
ng-model="target.url"
ng-disabled="target.id" />
</div>
<div class="umb-control-group">
<label><localize key="@content_altTextOptional"></localize></label>
<input type="text" class="umb-editor umb-textstring" ng-model="target.altText" />
</div>
<div class="umb-control-group">
<label><localize key="@content_altTextOptional"></localize></label>
<input type="text" class="umb-editor umb-textstring" ng-model="target.altText" />
</div>
</umb-overlay>
</umb-overlay>
</form>
@@ -1,7 +1,6 @@
<div ng-controller="Umbraco.Overlays.UserGroupPickerController as vm">
<umb-load-indicator
ng-if="vm.loading">
<umb-load-indicator ng-if="vm.loading">
</umb-load-indicator>
<div ng-if="!vm.loading">
@@ -9,17 +8,18 @@
<div class="form-search" style="margin-bottom: 15px;">
<i class="icon-search"></i>
<input type="text"
ng-model="searchTerm"
class="umb-search-field search-query input-block-level -full-width-input"
localize="placeholder"
placeholder="@placeholders_filter"
umb-auto-focus />
ng-model="searchTerm"
class="umb-search-field search-query input-block-level -full-width-input"
localize="placeholder"
placeholder="@placeholders_filter"
umb-auto-focus
no-dirty-check />
</div>
<div class="umb-user-group-picker-list">
<a href="" class="umb-user-group-picker-list-item" ng-repeat="userGroup in vm.userGroups | filter:searchTerm" ng-click="vm.selectUserGroup(userGroup)">
<div class="umb-user-group-picker-list-item__icon">
<i ng-if="!userGroup.selected" class="{{userGroup.icon}}"></i>
<umb-checkmark ng-if="userGroup.selected" checked="userGroup.selected" size="xs"></umb-checkmark>
@@ -42,7 +42,7 @@
<span ng-if="userGroup.contentStartNode">{{ userGroup.contentStartNode.name }}</span>
</span>
</div>
<div class="umb-user-group-picker-list-item__permission">
<span>
<span class="bold"><localize key="user_mediastartnode">Media start node</localize>:</span>
@@ -55,9 +55,8 @@
</div>
<umb-empty-state
ng-if="vm.userGroups.length === 0"
position="center">
<umb-empty-state ng-if="vm.userGroups.length === 0"
position="center">
No user groups have been added
</umb-empty-state>
@@ -51,7 +51,7 @@
total-pages="vm.usersOptions.totalPages"
on-change="vm.changePageNumber(pageNumber)">
</umb-pagination>
<div>
</div>
</div>
@@ -1,114 +1,114 @@
<div id="leftcolumn" ng-controller="Umbraco.NavigationController"
ng-mouseleave="leaveTree($event)" ng-mouseenter="enterTree($event)">
<umb-sections sections="sections" ng-if="authenticated">
</umb-sections>
<umb-sections sections="sections" ng-if="authenticated">
</umb-sections>
<!-- navigation container -->
<div id="navigation" ng-show="showNavigation" class="fill umb-modalcolumn" ng-animate="'slide'" nav-resize>
<!-- navigation container -->
<div id="navigation" ng-show="showNavigation" class="fill umb-modalcolumn" ng-animate="'slide'" nav-resize>
<div ng-swipe-left="nav.hideNavigation()" class="navigation-inner-container span6">
<div ng-swipe-left="nav.hideNavigation()" class="navigation-inner-container span6">
<!-- the search -->
<div ng-controller="Umbraco.SearchController" ng-if="authenticated">
<!-- the search -->
<div ng-controller="Umbraco.SearchController" ng-if="authenticated">
<!-- Search form -->
<div id="search-form">
<div class="umb-modalcolumn-header">
<!-- Search form -->
<div id="search-form">
<div class="umb-modalcolumn-header">
<form class="form-search" novalidate>
<i class="icon-search"></i>
<input type="text"
hotkey="ctrl+space"
id="search-field"
ng-model="searchTerm"
class="umb-search-field search-query search-input"
localize="placeholder"
placeholder="@placeholders_search"
ng-keydown="navigateResults($event)" />
</form>
</div>
</div>
<!-- Search results -->
<div id="search-results" class="umb-modalcolumn-body" ng-show="showSearchResults">
<umb-load-indicator ng-if="isSearching"></umb-load-indicator>
<umb-empty-state
ng-if="!hasResults && !isSearching"
position="center">
<localize key="general_searchNoResult"></localize>
</umb-empty-state>
<ul class="umb-tree" ng-if="!isSearching && hasResults">
<li class="root">
<div>
<h5 class="umb-tree-header"><localize key="general_searchResults">Search results</localize></h5>
</div>
<div class="umb-search-group" ng-repeat="(key, group) in groups">
<h6 class="umb-tree-header">{{key}}</h6>
<ul>
<li ng-repeat="result in group.results" ng-class="{'current':selectedItem == result}">
<div class="umb-search-group-item">
<a class="umb-search-group-item-link" ng-class="{'first':$first}" ng-click="searchHide()" ng-href="#/{{result.editorPath}}">
<div class="umb-search-group-item-name">
<i class="icon umb-tree-icon sprTree {{result.icon}}"></i>
{{result.name}}
</div>
<small class="search-subtitle" ng-show="result.subTitle">
{{result.subTitle}}
</small>
</a>
<a href ng-hide="!result.menuUrl" ng-click="searchShowMenu($event, {node: result})" class="umb-options"><i></i><i></i><i></i></a>
<form class="form-search" novalidate>
<i class="icon-search"></i>
<input type="text"
hotkey="ctrl+space"
id="search-field"
ng-model="searchTerm"
class="umb-search-field search-query search-input"
localize="placeholder"
placeholder="@placeholders_search"
ng-keydown="navigateResults($event)"
no-dirty-check />
</form>
</div>
</li>
</ul>
</div>
</div>
<!-- Search results -->
<div id="search-results" class="umb-modalcolumn-body" ng-show="showSearchResults">
</li>
</ul>
<umb-load-indicator ng-if="isSearching"></umb-load-indicator>
<umb-empty-state ng-if="!hasResults && !isSearching"
position="center">
<localize key="general_searchNoResult"></localize>
</umb-empty-state>
<ul class="umb-tree" ng-if="!isSearching && hasResults">
<li class="root">
<div>
<h5 class="umb-tree-header"><localize key="general_searchResults">Search results</localize></h5>
</div>
<div class="umb-search-group" ng-repeat="(key, group) in groups">
<h6 class="umb-tree-header">{{key}}</h6>
<ul>
<li ng-repeat="result in group.results" ng-class="{'current':selectedItem == result}">
<div class="umb-search-group-item">
<a class="umb-search-group-item-link" ng-class="{'first':$first}" ng-click="searchHide()" ng-href="#/{{result.editorPath}}">
<div class="umb-search-group-item-name">
<i class="icon umb-tree-icon sprTree {{result.icon}}"></i>
{{result.name}}
</div>
<small class="search-subtitle" ng-show="result.subTitle">
{{result.subTitle}}
</small>
</a>
<a href ng-hide="!result.menuUrl" ng-click="searchShowMenu($event, {node: result})" class="umb-options"><i></i><i></i><i></i></a>
</div>
</li>
</ul>
</div>
</li>
</ul>
</div>
</div>
<!-- the tree -->
<div id="tree" class="umb-modalcolumn-body" ng-if="authenticated">
<umb-tree cachekey="_"
eventhandler="treeEventHandler"
section="{{currentSection}}">
</umb-tree>
</div>
</div>
</div>
<div class="offset6" id="navOffset" style="z-index: 10">
<!-- the tree -->
<div id="tree" class="umb-modalcolumn-body" ng-if="authenticated">
<umb-tree cachekey="_"
eventhandler="treeEventHandler"
section="{{currentSection}}">
</umb-tree>
</div>
<!-- The context menu -->
<div id='contextMenu' class="umb-modalcolumn fill shadow" ng-swipe-left="nav.hideMenu()" ng-show="showContextMenu" ng-animate="'slide'">
<umb-context-menu menu-dialog-title="{{menuDialogTitle}}"
current-section="{{currentSection}}"
current-node="menuNode"
menu-actions="menuActions">
</umb-context-menu>
</div>
<!-- Tree dialogs -->
<div id="dialog" class='umb-modalcolumn fill shadow'
ng-swipe-left="nav.hideDialog()"
ng-show="showContextMenuDialog" ng-animate="'slide'">
<div class='umb-modalcolumn-header'>
<h1>{{menuDialogTitle}}</h1>
</div>
<div class='umb-modalcolumn-body'>
</div>
</div>
</div>
</div>
<div class="offset6" id="navOffset" style="z-index: 10">
<!-- The context menu -->
<div id='contextMenu' class="umb-modalcolumn fill shadow" ng-swipe-left="nav.hideMenu()" ng-show="showContextMenu" ng-animate="'slide'">
<umb-context-menu menu-dialog-title="{{menuDialogTitle}}"
current-section="{{currentSection}}"
current-node="menuNode"
menu-actions="menuActions">
</umb-context-menu>
</div>
<!-- Tree dialogs -->
<div id="dialog" class='umb-modalcolumn fill shadow'
ng-swipe-left="nav.hideDialog()"
ng-show="showContextMenuDialog" ng-animate="'slide'">
<div class='umb-modalcolumn-header'>
<h1>{{menuDialogTitle}}</h1>
</div>
<div class='umb-modalcolumn-body'>
</div>
</div>
</div>
</div>
</div>
@@ -1,20 +1,25 @@
function imageFilePickerController($scope) {
$scope.pick = function() {
$scope.mediaPickerDialog = {};
$scope.mediaPickerDialog.view = "mediapicker";
$scope.mediaPickerDialog.show = true;
$scope.mediaPickerDialog.submit = function(model) {
$scope.model.value = model.selectedImages[0].image;
$scope.mediaPickerDialog.show = false;
$scope.mediaPickerDialog = null;
$scope.add = function() {
$scope.mediaPickerOverlay = {
view: "mediapicker",
disableFolderSelect: true,
onlyImages: true,
show: true,
submit: function (model) {
$scope.model.value = model.selectedImages[0].image;
$scope.mediaPickerOverlay.show = false;
$scope.mediaPickerOverlay = null;
},
close: function () {
$scope.mediaPickerOverlay.show = false;
$scope.mediaPickerOverlay = null;
}
};
};
$scope.mediaPickerDialog.close = function(oldModel) {
$scope.mediaPickerDialog.show = false;
$scope.mediaPickerDialog = null;
};
$scope.remove = function () {
$scope.model.value = null;
};
}
@@ -1,19 +1,28 @@
<div ng-controller="Umbraco.PrevalueEditors.ImageFilePickerController" class="umb-editor umb-mediapicker">
<ul class="umb-sortable-thumbnails">
<li>
<img ng-src="{{model.value}}" alt="" ng-show="model.value">
<a href class="picked-image" ng-click="model.value = null" ng-show="model.value"><i class="icon icon-delete"></i></a>
<ul class="umb-sortable-thumbnails" ng-if="model.value">
<li class="umb-sortable-thumbnails__wrapper">
<img ng-src="{{model.value}}" alt="">
<div class="umb-sortable-thumbnails__actions">
<!--<a class="umb-sortable-thumbnails__action" href="" ng-click="goToItem(image)">
<i class="icon icon-edit"></i>
</a>-->
<a class="umb-sortable-thumbnails__action -red" href="" ng-click="remove()">
<i class="icon icon-delete"></i>
</a>
</div>
</li>
</ul>
<a href ng-click="pick()" class="umb-mediapicker add-link" ng-hide="model.value">
<a href="#" class="add-link" ng-click="add()" ng-class="{'add-link-square': !model.value }" ng-hide="model.value" prevent-default>
<i class="icon icon-add large"></i>
</a>
<umb-overlay
ng-if="mediaPickerDialog.show"
model="mediaPickerDialog"
view="mediaPickerDialog.view"
ng-if="mediaPickerOverlay.show"
model="mediaPickerOverlay"
view="mediaPickerOverlay.view"
position="right">
</umb-overlay>
@@ -261,7 +261,7 @@ angular.module("umbraco")
$scope.openEditorOverlay = function(event, area, index, key) {
$scope.editorOverlay = {
view: "itempicker",
filter: false,
filter: area.$allowedEditors.length > 15,
title: localizationService.localize("grid_insertControl"),
availableItems: area.$allowedEditors,
event: event,
@@ -640,16 +640,16 @@ angular.module("umbraco")
var clear = true;
//settings indicator shortcut
if ( ($scope.model.config.items.config && $scope.model.config.items.config.length > 0) || ($scope.model.config.items.styles && $scope.model.config.items.styles.length > 0)) {
if (($scope.model.config.items.config && $scope.model.config.items.config.length > 0) || ($scope.model.config.items.styles && $scope.model.config.items.styles.length > 0)) {
$scope.hasSettings = true;
}
//ensure the grid has a column value set,
//if nothing is found, set it to 12
if ($scope.model.config.items.columns && angular.isString($scope.model.config.items.columns)) {
$scope.model.config.items.columns = parseInt($scope.model.config.items.columns);
} else {
if (!$scope.model.config.items.columns){
$scope.model.config.items.columns = 12;
} else if (angular.isString($scope.model.config.items.columns)) {
$scope.model.config.items.columns = parseInt($scope.model.config.items.columns);
}
if ($scope.model.value && $scope.model.value.sections && $scope.model.value.sections.length > 0 && $scope.model.value.sections[0].rows && $scope.model.value.sections[0].rows.length > 0) {
@@ -19,6 +19,8 @@ angular.module('umbraco').controller("Umbraco.PropertyEditors.MediaPickerControl
$scope.images = [];
$scope.ids = [];
$scope.isMultiPicker = multiPicker;
if ($scope.model.value) {
var ids = $scope.model.value.split(',');
@@ -2,10 +2,10 @@
<p ng-if="(images|filter:{trashed:true}).length == 1"><localize key="mediaPicker_pickedTrashedItem"></localize></p>
<p ng-if="(images|filter:{trashed:true}).length > 1"><localize key="mediaPicker_pickedTrashedItems"></localize></p>
<div class="flex error">
<ul ui-sortable="sortableOptions" ng-model="images" class="umb-sortable-thumbnails">
<li style="width: 120px; height: 100px; overflow: hidden;" ng-repeat="image in images">
<li class="umb-sortable-thumbnails__wrapper" ng-repeat="image in images track by $index">
<!-- IMAGE -->
<img ng-class="{'trashed': image.trashed}" ng-src="{{image.thumbnail}}" alt="" ng-show="image.thumbnail" title="{{image.trashed ? 'Trashed: ' + image.name : image.name}}" />
@@ -30,11 +30,12 @@
</div>
</li>
<li style="border: none;">
<a href="#" class="add-link" ng-click="add()" ng-class="{'add-link-square': (images.length === 0 || isMultiPicker)}" ng-if="showAdd()" prevent-default>
<i class="icon icon-add large"></i>
</a>
</li>
</ul>
<a href="#" class="add-link" ng-click="add()" ng-class="{'add-link-square': images.length === 0}" ng-if="showAdd()" prevent-default>
<i class="icon icon-add large"></i>
</a>
</div>
<umb-overlay
@@ -374,6 +374,9 @@ angular.module("umbraco")
// element might still be there even after the modal has been hidden.
$scope.$on('$destroy', function () {
unsubscribe();
if (tinyMceEditor !== undefined && tinyMceEditor != null) {
tinyMceEditor.destroy()
}
});
});
});
+8 -11
View File
@@ -116,9 +116,8 @@
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="ClientDependency.Core, Version=1.9.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ClientDependency.1.9.2\lib\net45\ClientDependency.Core.dll</HintPath>
<Private>True</Private>
<Reference Include="ClientDependency.Core, Version=1.9.5.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ClientDependency.1.9.5\lib\net45\ClientDependency.Core.dll</HintPath>
</Reference>
<Reference Include="ClientDependency.Core.Mvc, Version=1.8.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ClientDependency-Mvc5.1.8.0.0\lib\net45\ClientDependency.Core.Mvc.dll</HintPath>
@@ -127,11 +126,10 @@
<Reference Include="dotless.Core, Version=1.5.2.0, Culture=neutral, PublicKeyToken=96b446c9e63eae34, processorArchitecture=MSIL">
<HintPath>..\packages\dotless.1.5.2\lib\dotless.Core.dll</HintPath>
</Reference>
<Reference Include="Examine, Version=0.1.88.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.88\lib\net45\Examine.dll</HintPath>
<Reference Include="Examine, Version=0.1.89.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.89\lib\net45\Examine.dll</HintPath>
</Reference>
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
</Reference>
<Reference Include="ImageProcessor, Version=2.5.6.0, Culture=neutral, processorArchitecture=MSIL">
@@ -144,7 +142,6 @@
<HintPath>..\packages\log4net.2.0.8\lib\net45-full\log4net.dll</HintPath>
</Reference>
<Reference Include="Lucene.Net, Version=2.9.4.1, Culture=neutral, PublicKeyToken=85089178b9ac3181, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNet.Identity.Core">
@@ -335,8 +332,8 @@
<Name>umbraco.providers</Name>
</ProjectReference>
<Reference Include="System.Xml.Linq" />
<Reference Include="Umbraco.ModelsBuilder, Version=3.0.7.99, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Umbraco.ModelsBuilder.3.0.7\lib\Umbraco.ModelsBuilder.dll</HintPath>
<Reference Include="Umbraco.ModelsBuilder, Version=3.0.8.100, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Umbraco.ModelsBuilder.3.0.8\lib\Umbraco.ModelsBuilder.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
@@ -1026,9 +1023,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\"
<WebProjectProperties>
<UseIIS>True</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>7770</DevelopmentServerPort>
<DevelopmentServerPort>7790</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:7770</IISUrl>
<IISUrl>http://localhost:7790</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
@@ -248,7 +248,7 @@ img[id|dir|lang|longdesc|usemap|style|class|src|onmouseover|onmouseout|border|al
thead[id|class],tfoot[id|class],#td[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor|scope],
-th[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|scope],caption[id|lang|dir|class|style],-div[id|dir|class|align|style],
-span[class|align|style],-pre[class|align|style],address[class|align|style],-h1[id|dir|class|align|style],-h2[id|dir|class|align|style],
-h3[id|dir|class|align|style],-h4[id|dir|class|align|style],-h5[id|dir|class|align|style],-h6[id|style|dir|class|align|style],hr[class|style],
-h3[id|dir|class|align|style],-h4[id|dir|class|align|style],-h5[id|dir|class|align|style],-h6[id|style|dir|class|align|style],hr[class|style],small[class|style],
dd[id|class|title|style|dir|lang],dl[id|class|title|style|dir|lang],dt[id|class|title|style|dir|lang],object[class|id|width|height|codebase|*],
param[name|value|_value|class],embed[type|width|height|src|class|*],map[name|class],area[shape|coords|href|alt|target|class],bdo[class],button[class],iframe[*]]]>
</validElements>
@@ -248,7 +248,7 @@ img[id|dir|lang|longdesc|usemap|style|class|src|onmouseover|onmouseout|border|al
thead[id|class],tfoot[id|class],#td[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|bgcolor|background|bordercolor|scope],
-th[id|lang|dir|class|colspan|rowspan|width|height|align|valign|style|scope],caption[id|lang|dir|class|style],-div[id|dir|class|align|style],
-span[class|align|style],-pre[class|align|style],address[class|align|style],-h1[id|dir|class|align|style],-h2[id|dir|class|align|style],
-h3[id|dir|class|align|style],-h4[id|dir|class|align|style],-h5[id|dir|class|align|style],-h6[id|style|dir|class|align|style],hr[class|style],
-h3[id|dir|class|align|style],-h4[id|dir|class|align|style],-h5[id|dir|class|align|style],-h6[id|style|dir|class|align|style],hr[class|style],small[class|style],
dd[id|class|title|style|dir|lang],dl[id|class|title|style|dir|lang],dt[id|class|title|style|dir|lang],object[class|id|width|height|codebase|*],
param[name|value|_value|class],embed[type|width|height|src|class|*],map[name|class],area[shape|coords|href|alt|target|class],bdo[class],button[class],iframe[*]]]>
</validElements>
@@ -271,4 +271,4 @@ param[name|value|_value|class],embed[type|width|height|src|class|*],map[name|cla
}
</config>
</customConfig>
</tinymceConfig>
</tinymceConfig>
+3 -3
View File
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AutoMapper" version="3.3.1" targetFramework="net45" />
<package id="ClientDependency" version="1.9.2" targetFramework="net45" />
<package id="ClientDependency" version="1.9.5" targetFramework="net45" />
<package id="ClientDependency-Mvc5" version="1.8.0.0" targetFramework="net45" />
<package id="dotless" version="1.5.2" targetFramework="net45" />
<package id="Examine" version="0.1.88" targetFramework="net45" />
<package id="Examine" version="0.1.89" targetFramework="net45" />
<package id="ImageProcessor" version="2.5.6" targetFramework="net45" />
<package id="ImageProcessor.Web" version="4.8.7" targetFramework="net45" />
<package id="ImageProcessor.Web.Config" version="2.3.1" targetFramework="net45" />
@@ -37,5 +37,5 @@
<package id="SqlServerCE" version="4.0.0.1" targetFramework="net45" />
<package id="System.Collections.Immutable" version="1.1.36" targetFramework="net45" />
<package id="System.Reflection.Metadata" version="1.0.21" targetFramework="net45" />
<package id="Umbraco.ModelsBuilder" version="3.0.7" targetFramework="net45" />
<package id="Umbraco.ModelsBuilder" version="3.0.8" targetFramework="net45" />
</packages>
@@ -1442,7 +1442,7 @@ Mange hilsner fra Umbraco robotten
<key alias="documentType">Dokumenttype</key>
<key alias="editors">Redaktør</key>
<key alias="excerptField">Uddragsfelt</key>
<key alias="failedPasswordAttempts">Fejlet loginforsøg</key>
<key alias="failedPasswordAttempts">Fejlede loginforsøg</key>
<key alias="goToProfile">Gå til brugerprofil</key>
<key alias="groupsHelp">Tilføj grupper for at tildele adgang og tilladelser</key>
<key alias="inviteAnotherUser">Invitér anden bruger</key>
@@ -1450,7 +1450,7 @@ Mange hilsner fra Umbraco robotten
<key alias="language">Sprog</key>
<key alias="languageHelp">Indstil det sprog, du vil se i menuer og dialoger</key>
<key alias="lastLockoutDate">Seneste låst ude dato</key>
<key alias="lastLogin">Senest login</key>
<key alias="lastLogin">Seneste login</key>
<key alias="lastPasswordChangeDate">Kodeord sidst ændret</key>
<key alias="loginname">Brugernavn</key>
<key alias="mediastartnode">Startnode i mediearkivet</key>
@@ -1481,7 +1481,7 @@ Mange hilsner fra Umbraco robotten
<key alias="permissionsGranularHelp">Sæt rettigheder for specifikke noder</key>
<key alias="profile">Profil</key>
<key alias="searchAllChildren">Søg alle 'børn'</key>
<key alias="startnode">Start node</key>
<key alias="startnode">Startnode</key>
<key alias="stateActive">Aktiv</key>
<key alias="stateAll">Alle</key>
<key alias="stateDisabled">Deaktiveret</key>
@@ -32,11 +32,6 @@
<key alias="sort">מיין</key>
<key alias="translate">תרגם</key>
<key alias="update">עדכן</key>
<key alias="DeleteCMSImportAction">מחק</key>
<key alias="ExecuteCMSImportWizardAction">בצע</key>
<key alias="ScheduleCMSImportWizardAction">תזמן</key>
<key alias="StartCMSImportWizardAction">ייבא נתונים</key>
<key alias="StartCMSImportChildDefinitionAction">צור הגדרות ילדים</key>
<key alias="LastRunInfoAction">יומן משימות מתוזמנות</key>
</area>
<area alias="assignDomain">
@@ -452,7 +452,7 @@
<key alias="email">Email</key>
<key alias="error">Fout</key>
<key alias="findDocument">Vind</key>
<key alias="height">Hogte</key>
<key alias="height">Hoogte</key>
<key alias="help">Help</key>
<key alias="icon">Icoon</key>
<key alias="import">Import</key>
+90 -14
View File
@@ -12,9 +12,11 @@
<key alias="copy">Kopiuj</key>
<key alias="create">Utwórz</key>
<key alias="createPackage">Stwórz zbiór</key>
<key alias="createGroup">Stwórz grupę</key>
<key alias="delete">Usuń</key>
<key alias="disable">Deaktywuj</key>
<key alias="emptyTrashcan">Opróżnij kosz</key>
<key alias="enable">Aktywuj</key>
<key alias="exportDocumentType">Eksportuj typ dokumentu</key>
<key alias="importDocumentType">Importuj typ dokumentu</key>
<key alias="importPackage">Importuj zbiór</key>
@@ -27,16 +29,49 @@
<key alias="unpublish">Cofnij publikację</key>
<key alias="refreshNode">Odśwież węzeł</key>
<key alias="republish">Opublikuj ponownie całą stronę</key>
<key alias="rename" version="7.3.0">Zmień nazwę</key>
<key alias="restore" version="7.3.0">Przywróć</key>
<key alias="SetPermissionsForThePage">Ustaw uprawnienia dla strony %0%</key>
<key alias="chooseWhereToMove">Wybierz dokąd przenieść</key>
<key alias="toInTheTreeStructureBelow">W strukturze drzewa poniżej</key>
<key alias="rights">Uprawnienia</key>
<key alias="rollback">Cofnij</key>
<key alias="sendtopublish">Wyślij do publikacji</key>
<key alias="sendToTranslate">Wyślij do tłumaczenia</key>
<key alias="setGroup">Ustaw grupę</key>
<key alias="sort">Sortuj</key>
<key alias="translate">Przetłumacz</key>
<key alias="update">Aktualizuj</key>
<key alias="setPermissions">Ustaw uprawnienia</key>
<key alias="unlock">Odblokuj</key>
<key alias="createblueprint">Stwórz Szablon Zawartości</key>
</area>
<area alias="actionCategories">
<key alias="content">Zawartość</key>
<key alias="administration">Administracja</key>
<key alias="structure">Struktura</key>
<key alias="other">Inne</key>
</area>
<area alias="actionDescriptions">
<key alias="assignDomain">Zezwól na dostęp do przydzielenia języka i hostów</key>
<key alias="auditTrail">Zezwól na dostęp do wglądu w historię logów węzła</key>
<key alias="browse">Zezwól na dostęp do widoku węzła</key>
<key alias="changeDocType">Zezwól na dostęp do zmiany typu dokumentu dla węzła</key>
<key alias="copy">Zezwól na dostęp do skopiowania węzła</key>
<key alias="create">Zezwól na dostęp do stworzenia węzłów</key>
<key alias="delete">Zezwól na dostęp do usunięcia węzłóws</key>
<key alias="move">Zezwól na dostęp do przeniesienia węzła</key>
<key alias="protect">Zezwól na dostęp do ustawienia i zmiany publicznego dostępu węzła</key>
<key alias="publish">Zezwól na dostęp do publikacji węzła</key>
<key alias="rights">Zezwól na dostęp do zmiany uprawnień węzła</key>
<key alias="rollback">Zezwól na dostęp do cofnięcia węzła do poprzedniego stanu</key>
<key alias="sendtopublish">Zezwól na dostęp do wysłania węzła do akceptacji przed publikacją</key>
<key alias="sendToTranslate">Zezwól na dostęp do wysłania węzła do tłumaczenia</key>
<key alias="sort">Zezwól na dostęp do zmiany kolejności sortowania węzłów</key>
<key alias="translate">Zezwól na dostęp do tłumaczenia węzła</key>
<key alias="update">Zezwól na dostęp do zapisania węzła</key>
<key alias="createblueprint">Zezwól na dostęp do utworzenia Szablonu Zawartości</key>
</area>
<area alias="assignDomain">
<key alias="permissionDenied">Brak odpowiednich uprawnień</key>
<key alias="addNew">Dodaj nową domenę</key>
@@ -50,14 +85,18 @@
<key alias="domainDeleted">Domena '%0%' została skasowana</key>
<key alias="domainExists">Domena '%0%' jest aktualnie przypisana</key>
<key alias="domainUpdated">Domena '%0%' została zaktualizowana</key>
<key alias="domainHelp"><![CDATA[Poprawne domeny to: "example.com", "www.example.com", "example.com:8080" lub
"https://www.example.com/". Wspierane są jednopoziomowe ścieżki domen, np. "example.com/en" jednakże powinno się ich unikać.
Preferowane jest użycie powyższych ustawień języka.]]></key>
<key alias="orEdit">Edycja aktualnych domen</key>
<key alias="orEdit">Edytuj Aktualne Domeny</key>
<key alias="domainHelp">
<![CDATA[Poprawne domeny to: "example.com", "www.example.com", "example.com:8080" lub
"https://www.example.com/". Wspierane są jednopoziomowe ścieżki domen, np. "example.com/en" jednakże powinno się ich unikać.
Preferowane jest użycie powyższych ustawień języka.]]>
</key>
<key alias="inherit">Odziedziczona</key>
<key alias="setLanguage">Język</key>
<key alias="setLanguageHelp"><![CDATA[Wybierz język dla węzła,<br /> lub wybierz dziedziczenie języka z węzła rodzica. Zostanie to zastosowane<br />
także do obecnego węzła, o ile poniższa domena również do niego należy.]]></key>
<key alias="setLanguageHelp">
<![CDATA[Wybierz język dla węzła,<br /> lub wybierz dziedziczenie języka z węzła rodzica. Zostanie to zastosowane<br />
także do obecnego węzła, o ile poniższa domena również do niego należy.]]>
</key>
<key alias="setDomains">Domeny</key>
</area>
<area alias="auditTrails">
@@ -96,6 +135,7 @@ także do obecnego węzła, o ile poniższa domena również do niego należy.]]
<key alias="styleShow">Pokaż style</key>
<key alias="tableInsert">Wstaw tabelę</key>
<key alias="generateModels">Wygeneruj modele</key>
<key alias="saveAndGenerateModels">Zapisz i wygeneruj modele</key>
<key alias="undo">Cofnij</key>
<key alias="redo">Powtórz</key>
</area>
@@ -139,6 +179,8 @@ także do obecnego węzła, o ile poniższa domena również do niego należy.]]
<key alias="lastPublished">Opublikowane</key>
<key alias="noItemsToShow">Nie ma żadnych elementów do wyświetlenia</key>
<key alias="listViewNoItems" version="7.1.5">Nie ma żadnych elementów do wyświetlenia w liście.</key>
<key alias="listViewNoContent">Nie dodano żadnej zawartości</key>
<key alias="listViewNoMembers">Nie dodano żadnych członków</key>
<key alias="mediatype">Typ mediów</key>
<key alias="mediaLinks">Link do elementu(ów) mediów</key>
<key alias="membergroup">Członek grupy</key>
@@ -173,16 +215,30 @@ także do obecnego węzła, o ile poniższa domena również do niego należy.]]
<key alias="target" version="7.0">Cel</key>
<key alias="scheduledPublishServerTime">Oznacza to następującą godzinę na serwerze:</key>
<key alias="scheduledPublishDocumentation"><![CDATA[<a href="https://our.umbraco.org/documentation/Getting-Started/Data/Scheduled-Publishing/#timezones" target="_blank">Co to oznacza?</a>]]></key>
<key alias="nestedContentDeleteItem">Czy na pewno chcesz usunąć ten element?</key>
<key alias="nestedContentEditorNotSupported">Właściwość %0% używa edytora %1%, który nie jest wspierany przez Nested Content.</key>
<key alias="addTextBox">Dodaj kolejne pole tekstowe</key>
<key alias="removeTextBox">Usuń te pole tekstowe</key>
<key alias="contentRoot">Korzeń zawartości</key>
</area>
<area alias="blueprints">
<key alias="createBlueprintFrom">Stwórz nowy Szablon Zawartości z '%0%'</key>
<key alias="blankBlueprint">Pusty</key>
<key alias="selectBlueprint">Wybierz Szablon Zawartości</key>
<key alias="createdBlueprintHeading">Szablon Zawartości został stworzony</key>
<key alias="createdBlueprintMessage">Szablon Zawartości został stworzony z '%0%'</key>
<key alias="duplicateBlueprintMessage">Szablon Zawartości o tej samej nazwie już istnieje</key>
<key alias="blueprintDescription">Szablon Zawartości to predefiniowana zawartość, którą edytor może wybrać, aby użyć jej jako podstawę do stworzenia nowej zawartości</key>
</area>
<area alias="media">
<key alias="clickToUpload">Kliknij, aby załadować plik</key>
<key alias="dropFilesHere">Przerzuć swoje pliki tutaj...</key>
<key alias="urls">Link do mediów</key>
<key alias="urls">Link do mediów</key>
<key alias="orClickHereToUpload">lub kliknij tutaj, aby wybrać pliki</key>
<key alias="onlyAllowedFiles">Jedyne dozwolone typy plików to</key>
<key alias="disallowedFileType">Nie można załadować pliku, typ pliku nie jest akceptowany</key>
<key alias="maxFileSize">Maksymalny rozmiar pliku to</key>
<key alias="mediaRoot">Korzeń mediów</key>
</area>
<area alias="member">
<key alias="createNewMember">Stwórz nowego członka</key>
@@ -191,6 +247,7 @@ także do obecnego węzła, o ile poniższa domena również do niego należy.]]
<area alias="create">
<key alias="chooseNode">Gdzie chcesz stworzyć nowy %0%?</key>
<key alias="createUnder">Utwórz w</key>
<key alias="createContentBlueprint">Wybierz typ dokumentu, dla którego chcesz stworzyć szablon zawartości</key>
<key alias="updateData">Wybierz rodzaj oraz tytuł</key>
<key alias="noDocumentTypes" version="7.0"><![CDATA[Brak dostępnych dozwolonych typów dokumentów. Należy włączyć je w ustawieniach sekcji pod <strong>"typy dokumentów"</strong>.]]></key>
<key alias="noMediaTypes" version="7.0"><![CDATA[Brak dostępnych dozwolonych typów mediów. Należy włączyć je w ustawieniach sekcji pod <strong>"typy mediów"</strong>.]]></key>
@@ -249,6 +306,8 @@ także do obecnego węzła, o ile poniższa domena również do niego należy.]]
<key alias="copiedItemOfItems">Skopiowano %0% z %1% elementów</key>
</area>
<area alias="defaultdialogs">
<key alias="nodeNameLinkPicker">Tytuł linku</key>
<key alias="urlLinkPicker">Link</key>
<key alias="anchorInsert">Nazwa</key>
<key alias="assignDomain">Zarządzaj nazwami hostów</key>
<key alias="closeThisWindow">Zamknij to okno</key>
@@ -276,6 +335,9 @@ także do obecnego węzła, o ile poniższa domena również do niego należy.]]
<key alias="macroDoesNotHaveProperties">To makro nie posiada żadnych właściwości, które można edytować</key>
<key alias="paste">Wklej</key>
<key alias="permissionsEdit">Edytuj Uprawnienia dla</key>
<key alias="permissionsSet">Ustaw uprawnienia dla</key>
<key alias="permissionsSetForGroup">Ustaw uprawnienia dla %0% dla grupy użytkownika %1%</key>
<key alias="permissionsHelp">Wybierz grupy użytkowników, dla których chcesz ustawić uprawnienia</key>
<key alias="recycleBinDeleting">Zawartość kosza jest teraz usuwana. Proszę nie zamykać tego okna do momentu zakończenia procesu.</key>
<key alias="recycleBinIsEmpty">Zawartość kosza została usunięta</key>
<key alias="recycleBinWarning">Usunięcie elementów z kosza powoduje ich trwałe i nieodwracalne skasowanie</key>
@@ -288,10 +350,14 @@ także do obecnego węzła, o ile poniższa domena również do niego należy.]]
<key alias="siterepublishHelp">Cache strony zostanie odświeżone. Cała zawartość opublikowana będzie aktualna, lecz nieopublikowana zawartość pozostanie niewidoczna</key>
<key alias="tableColumns">Liczba kolumn</key>
<key alias="tableRows">Liczba wierszy</key>
<key alias="templateContentAreaHelp"><![CDATA[<strong>Ustaw zastępczy ID</strong> Ustawiając ID na tym elemencie możesz później łączyć treść z podrzędnych szablonów,
ustawiając dowiązanie do tego ID na elemencie <code>&lt;asp:treści /&gt;</code>]]></key>
<key alias="templateContentPlaceHolderHelp"><![CDATA[<strong>Wybierz zastępczy ID</strong> z poniższej listy. Możesz wybierać tylko
spośród ID na szablonie nadrzędnym tego formularza.]]></key>
<key alias="templateContentAreaHelp">
<![CDATA[<strong>Ustaw zastępczy ID</strong> Ustawiając ID na tym elemencie możesz później łączyć treść z podrzędnych szablonów,
ustawiając dowiązanie do tego ID na elemencie <code>&lt;asp:treści /&gt;</code>]]>
</key>
<key alias="templateContentPlaceHolderHelp">
<![CDATA[<strong>Wybierz zastępczy ID</strong> z poniższej listy. Możesz wybierać tylko
spośród ID na szablonie nadrzędnym tego formularza.]]>
</key>
<key alias="thumbnailimageclickfororiginal">Kliknij na obrazie, aby zobaczyć go w pełnym rozmiarze</key>
<key alias="treepicker">Wybierz element</key>
<key alias="viewCacheItem">Podgląd elementów Cache</key>
@@ -303,14 +369,19 @@ także do obecnego węzła, o ile poniższa domena również do niego należy.]]
<key alias="openInNewWindow">Otwórz zlinkowany dokument w nowym oknie lub zakładce</key>
<key alias="linkToMedia">Link do mediów</key>
<key alias="linkToFile">Link do plików</key>
<key alias="selectContentStartNode">Wybierz węzeł początkowy zawartości</key>
<key alias="selectMedia">Wybierz media</key>
<key alias="selectIcon">Wybierz ikonę</key>
<key alias="selectItem">Wybierz element</key>
<key alias="selectLink">Wybierz link</key>
<key alias="selectMacro">Wybierz makro</key>
<key alias="selectContent">Wybierz zawartość</key>
<key alias="selectMediaStartNode">Wybierz węzeł początkowy mediów</key>
<key alias="selectMember">Wybierz członka</key>
<key alias="selectMemberGroup">Wybierz członka grupy</key>
<key alias="selectNode">Wybierz węzeł</key>
<key alias="selectSections">Wybierz sekcje</key>
<key alias="selectUsers">Wybierz użytkowników</key>
<key alias="noIconsFound">Nie znaleziono ikon</key>
<key alias="noMacroParams">Te makro nie ma żadnych właściwości</key>
<key alias="noMacros">Brak dostępnych makro do wstawienia</key>
@@ -325,9 +396,11 @@ także do obecnego węzła, o ile poniższa domena również do niego należy.]]
<key alias="selectSnippet">Wybierz snippet</key>
</area>
<area alias="dictionaryItem">
<key alias="description"><![CDATA[
Edytuj różne wersje językowe dla elementu słownika '<em>%0%</em>' poniżej.<br/>
Możesz dodać dodatkowe języki w menu "Języki" po lewej stronie.]]></key>
<key alias="description">
<![CDATA[
Edytuj różne wersje językowe dla elementu słownika '<em>%0%</em>' poniżej.<br/>
Możesz dodać dodatkowe języki w menu "Języki" po lewej stronie.]]>
</key>
<key alias="displayName">Nazwa języka</key>
<key alias="changeKey">Edytuj klucz elementu słownika.</key>
<key alias="changeKeyError">
@@ -342,12 +415,15 @@ Możesz dodać dodatkowe języki w menu "Języki" po lewej stronie.]]></key>
<key alias="confirmPassword">Potwierdź hasło</key>
<key alias="nameentity">Nazwij %0%...</key>
<key alias="entername">Wpisz nazwę...</key>
<key alias="enteremail">Wpisz adres e-mail...</key>
<key alias="enterusername">Wpisz nazwę użytkownika...</key>
<key alias="label">Etykieta...</key>
<key alias="enterDescription">Wpisz opis...</key>
<key alias="search">Wpisz, aby wyszukać...</key>
<key alias="filter">Wpisz, aby filtrować...</key>
<key alias="enterTags">Wpisz, aby dodać tagi (naciśnij enter po każdym tagu)...</key>
<key alias="email">Wpisz adres e-mail</key>
<key alias="enterMessage">Wpisz wiadomość...</key>
<key alias="usernameHint">Twoja nazwa użytkownika to przeważnie Twój adres e-mail</key>
</area>
<area alias="editcontenttype">
+23 -7
View File
@@ -153,6 +153,7 @@
<key alias="listNumeric">Нумерованный список</key>
<key alias="macroInsert">Вставить макрос</key>
<key alias="pictureInsert">Вставить изображение</key>
<key alias="redo">Повторить</key>
<key alias="relations">Править связи</key>
<key alias="returnToList">Вернуться к списку</key>
<key alias="save">Сохранить</key>
@@ -168,6 +169,7 @@
<key alias="styleChoose">Выбрать стиль</key>
<key alias="styleShow">Показать стили</key>
<key alias="tableInsert">Вставить таблицу</key>
<key alias="undo">Отменить</key>
</area>
<area alias="changeDocType">
<key alias="changeDocTypeInstruction">Чтобы сменить тип документа для выбранного узла, сначала выберите тип из списка разрешенных для данного расположения.</key>
@@ -375,6 +377,7 @@
<key alias="macroContainerSettings">Свойства макроса</key>
<key alias="macroDoesNotHaveProperties">Этот макрос не имеет редактируемых свойств</key>
<key alias="nodeNameLinkPicker">Заголовок ссылки</key>
<key alias="noIconsFound">Ни одной пиктограммы не найдено</key>
<key alias="paste">Вставить</key>
<key alias="permissionsEdit">Изменить разрешения для</key>
<key alias="permissionsSet">Установить разрешения для</key>
@@ -596,6 +599,7 @@
<key alias="new">Новый</key>
<key alias="next">След</key>
<key alias="no">Нет</key>
<key alias="noItemsInList">Здесь пока нет элементов</key>
<key alias="of">из</key>
<key alias="off">Выкл</key>
<key alias="ok">Ok</key>
@@ -696,6 +700,8 @@
<key alias="chooseExtra">Выбрать дополнительно</key>
<key alias="chooseDefault">Выбрать по-умолчанию</key>
<key alias="areAdded">добавлены</key>
<key alias="maxItemsDescription">Оставьте пустым или задайте 0 для снятия лимита</key>
<key alias="maxItems">Максимальное количество</key>
</area>
<area alias="headers">
<key alias="page">Страница</key>
@@ -1049,7 +1055,7 @@
<area alias="packager">
<key alias="chooseLocalPackageText"><![CDATA[
Выберите файл пакета на своем компьютере, нажав на кнопку 'Обзор'<br />
и указав на нужный файл. Пакеты Umbraco обычно являются архивами с расширением ".umb" или ".zip".
и указав на нужный файл. Пакеты Umbraco обычно являются архивами с расширением '.zip'.
]]></key>
<key alias="dropHere">Перетащите сюда</key>
<key alias="orClickHereToUpload">или нажмите здесь для выбора файла пакета</key>
@@ -1215,12 +1221,12 @@
</area>
<area alias="relatedlinks">
<key alias="caption">Заголовок</key>
<key alias="captionPlaceholder">Укажите заголовок</key>
<key alias="captionPlaceholder">Укажите заголовок ссылки</key>
<key alias="chooseInternal">выбрать страницу сайта</key>
<key alias="enterExternal">указать внешнюю ссылку</key>
<key alias="externalLinkPlaceholder">Укажите ссылку</key>
<key alias="link">Ссылка</key>
<key alias="newWindow">В новом окне</key>
<key alias="newWindow">Открыть в новом окне</key>
</area>
<area alias="renamecontainer">
<key alias="renamed">Переименована</key>
@@ -1393,8 +1399,6 @@
<key alias="disableUserSuccess">'%0%' сейчас заблокирован</key>
<key alias="disableUserError">При блокировке пользователя произошла ошибка</key>
<key alias="setUserGroupOnUsersSuccess">Группы пользователей установлены</key>
<key alias="deleteUserGroupsSuccess">Удалено %0% групп пользователей</key>
<key alias="deleteUserGroupSuccess">'%0%' была удалена</key>
<key alias="unlockUsersSuccess">Разблокировано %0% пользователей</key>
<key alias="unlockUsersError">При разблокировке пользователей произошла ошибка</key>
<key alias="unlockUserSuccess">'%0%' сейчас разблокирован</key>
@@ -1517,8 +1521,8 @@
<key alias="fallbackField">Поле замены</key>
<key alias="addDefaultValue">Добавить значение по-умолчанию</key>
<key alias="defaultValue">Значение по-умолчанию</key>
<key alias="alternativeField">Альтернативное поле</key>
<key alias="alternativeText">Текст по-умолчанию</key>
<key alias="alternativeField">Поле замены</key>
<key alias="alternativeText">Значение по-умолчанию</key>
<key alias="casing">Регистр</key>
<key alias="chooseField">Выбрать поле</key>
<key alias="convertLineBreaks">Преобразовать переводы строк</key>
@@ -1715,11 +1719,22 @@
<key alias="profile">Профиль</key>
<key alias="resetPassword">Сбросить пароль</key>
<key alias="searchAllChildren">Поиск всех дочерних документов</key>
<key alias="selectUserGroups">Выбрать группы пользователей</key>
<key alias="sendInvite">Отправить приглашение</key>
<key alias="sessionExpires" version="7.0">Сессия истекает через</key>
<key alias="sectionsHelp">Разделы, доступные пользователю</key>
<key alias="noStartNode">Начальный узел не задан</key>
<key alias="noStartNodes">Начальные узлы не заданы</key>
<key alias="sortNameAscending">Имя (А-Я)</key>
<key alias="sortNameDescending">Имя (Я-А)</key>
<key alias="sortCreateDateDescending">Сначала новые</key>
<key alias="sortCreateDateAscending">Сначала старые</key>
<key alias="sortLastLoginDateDescending">Недавно зашедшие</key>
<key alias="stateActive">Активные</key>
<key alias="stateAll">Все</key>
<key alias="stateDisabled">Отключенные</key>
<key alias="stateLockedOut">Заблокированные</key>
<key alias="stateInvited">Приглашенные</key>
<key alias="startnode">Начальный узел содержимого</key>
<key alias="startnodehelp">Можно ограничить доступ к дереву содержимого (какой-либо его части), задав начальный узел</key>
<key alias="startnodes">Начальные узлы содержимого</key>
@@ -1736,6 +1751,7 @@
<key alias="userInvitedSuccessHelp">Новому пользователю было отправлено приглашение, в котором содержатся инструкции для входа в панель Umbraco.</key>
<key alias="userinviteWelcomeMessage">Здравствуйте и добро пожаловать в Umbraco! Все будет готово в течении пары минут, нам лишь нужно задать Ваш пароль для входа и добавить аватар.</key>
<key alias="userinviteAvatarMessage">Загрузите изображение, это поможет другим пользователям идентифицировать Вас.</key>
<key alias="userManagement">Управление пользователями</key>
<key alias="userPermissions">Разрешения для пользователя</key>
<key alias="writer">Автор</key>
<key alias="yourHistory" version="7.0">Ваша недавняя история</key>
@@ -7,6 +7,7 @@
<style type="text/css">
.gridHeader{border-bottom:2px solid #D9D7D7;}
.gridItem{border-color: #D9D7D7;}
html, body {overflow: initial;}
</style>
<umb:CssInclude ID="CssInclude2" runat="server" FilePath="Tree/treeIcons.css" PathNameAlias="UmbracoClient" />
@@ -805,13 +805,13 @@ namespace Umbraco.Web.Cache
/// <summary>
/// Used to cache all found event handlers
/// </summary>
private static readonly ConcurrentDictionary<IEventDefinition, MethodInfo> FoundHandlers = new ConcurrentDictionary<IEventDefinition, MethodInfo>();
private static readonly ConcurrentDictionary<string, MethodInfo> FoundHandlers = new ConcurrentDictionary<string, MethodInfo>();
internal static MethodInfo FindHandler(IEventDefinition eventDefinition)
{
var name = eventDefinition.Sender.GetType().Name + "_" + eventDefinition.EventName;
return FoundHandlers.GetOrAdd(eventDefinition, _ => CandidateHandlers.Value.FirstOrDefault(x => x.Name == name));
return FoundHandlers.GetOrAdd(name, n => CandidateHandlers.Value.FirstOrDefault(x => x.Name == n));
}
}
}
@@ -1,11 +1,7 @@
using System;
using System.Linq;
using System.Web.Mvc;
using System.Web.Security;
using umbraco.BusinessLogic;
using umbraco.cms.businesslogic.member;
using Umbraco.Core;
using Umbraco.Core.Security;
using Umbraco.Web.Models;
using Umbraco.Web.Mvc;
@@ -21,6 +17,13 @@ namespace Umbraco.Web.Controllers
return CurrentUmbracoPage();
}
// U4-10762 Server error with "Register Member" snippet (Cannot save member with empty name)
// If name field is empty, add the email address instead
if (string.IsNullOrEmpty(model.Name) && string.IsNullOrEmpty(model.Email) == false)
{
model.Name = model.Email;
}
MembershipCreateStatus status;
var member = Members.RegisterMember(model, out status, model.LoginOnSuccess);
@@ -36,7 +39,6 @@ namespace Umbraco.Web.Controllers
return Redirect(model.RedirectUrl);
}
//redirect to current page by default
return RedirectToCurrentUmbracoPage();
case MembershipCreateStatus.InvalidUserName:
ModelState.AddModelError((model.UsernameIsEmail || model.Username == null)
@@ -532,6 +532,7 @@ namespace Umbraco.Web.Editors
/// <returns></returns>
[FileUploadCleanupFilter]
[ContentPostValidate]
[OutgoingEditorModelEvent]
public ContentItemDisplay PostSave(
[ModelBinder(typeof(ContentItemBinder))]
ContentItemSave contentItem)
@@ -847,6 +848,7 @@ namespace Umbraco.Web.Editors
/// <param name="id"></param>
/// <returns></returns>
[EnsureUserPermissionForContent("id", 'U')]
[OutgoingEditorModelEvent]
public ContentItemDisplay PostUnPublish(int id)
{
var foundContent = GetObjectFromRequest(() => Services.ContentService.GetById(id));
@@ -464,6 +464,7 @@ namespace Umbraco.Web.Editors
/// <returns></returns>
[FileUploadCleanupFilter]
[MediaPostValidate]
[OutgoingEditorModelEvent]
public MediaItemDisplay PostSave(
[ModelBinder(typeof(MediaItemBinder))]
MediaItemSave contentItem)
+2 -1
View File
@@ -256,6 +256,7 @@ namespace Umbraco.Web.Editors
/// </summary>
/// <returns></returns>
[FileUploadCleanupFilter]
[OutgoingEditorModelEvent]
public MemberDisplay PostSave(
[ModelBinder(typeof(MemberBinder))]
MemberSave contentItem)
@@ -555,7 +556,7 @@ namespace Umbraco.Web.Editors
var builtInAliases = Constants.Conventions.Member.GetStandardPropertyTypeStubs().Select(x => x.Key).ToArray();
foreach (var p in contentItem.PersistedContent.Properties)
{
var valueMapped = currProps.SingleOrDefault(x => x.Alias == p.Alias);
var valueMapped = currProps.FirstOrDefault(x => x.Alias == p.Alias);
if (builtInAliases.Contains(p.Alias) == false && valueMapped != null)
{
p.Value = valueMapped.Value;
+208
View File
@@ -0,0 +1,208 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Examine;
using Examine.Config;
using Examine.LuceneEngine;
using Examine.LuceneEngine.Providers;
using Examine.Providers;
using Lucene.Net.Index;
using Lucene.Net.Store;
using Umbraco.Core;
using Umbraco.Core.Logging;
using UmbracoExamine;
namespace Umbraco.Web
{
/// <summary>
/// Used to configure Examine during startup for the web application
/// </summary>
internal class ExamineStartup
{
private readonly List<BaseIndexProvider> _indexesToRebuild = new List<BaseIndexProvider>();
private readonly ApplicationContext _appCtx;
private readonly ProfilingLogger _profilingLogger;
private static bool _isConfigured = false;
//this is used if we are not the MainDom, in which case we need to ensure that if indexes need rebuilding that this
//doesn't occur since that should only occur when we are MainDom
private bool _disableExamineIndexing = false;
public ExamineStartup(ApplicationContext appCtx)
{
_appCtx = appCtx;
_profilingLogger = appCtx.ProfilingLogger;
}
/// <summary>
/// Called during the initialize operation of the boot manager process
/// </summary>
public void Initialize()
{
//We want to manage Examine's appdomain shutdown sequence ourselves so first we'll disable Examine's default behavior
//and then we'll use MainDom to control Examine's shutdown
ExamineManager.DisableDefaultHostingEnvironmentRegistration();
//we want to tell examine to use a different fs lock instead of the default NativeFSFileLock which could cause problems if the appdomain
//terminates and in some rare cases would only allow unlocking of the file if IIS is forcefully terminated. Instead we'll rely on the simplefslock
//which simply checks the existence of the lock file
DirectoryTracker.DefaultLockFactory = d =>
{
var simpleFsLockFactory = new NoPrefixSimpleFsLockFactory(d);
return simpleFsLockFactory;
};
//This is basically a hack for this item: http://issues.umbraco.org/issue/U4-5976
// when Examine initializes it will try to rebuild if the indexes are empty, however in many cases not all of Examine's
// event handlers will be assigned during bootup when the rebuilding starts which is a problem. So with the examine 0.1.58.2941 build
// it has an event we can subscribe to in order to cancel this rebuilding process, but what we'll do is cancel it and postpone the rebuilding until the
// boot process has completed. It's a hack but it works.
ExamineManager.Instance.BuildingEmptyIndexOnStartup += OnInstanceOnBuildingEmptyIndexOnStartup;
//let's deal with shutting down Examine with MainDom
var examineShutdownRegistered = _appCtx.MainDom.Register(() =>
{
using (_profilingLogger.TraceDuration<ExamineStartup>("Examine shutting down"))
{
//Due to the way Examine's own IRegisteredObject works, we'll first run it with immediate=false and then true so that
//it's correct subroutines are executed (otherwise we'd have to run this logic manually ourselves)
ExamineManager.Instance.Stop(false);
ExamineManager.Instance.Stop(true);
}
});
if (examineShutdownRegistered)
{
_profilingLogger.Logger.Debug<ExamineStartup>("Examine shutdown registered with MainDom");
}
else
{
_profilingLogger.Logger.Debug<ExamineStartup>("Examine shutdown not registered, this appdomain is not the MainDom");
//if we could not register the shutdown examine ourselves, it means we are not maindom! in this case all of examine should be disabled
//from indexing anything on startup!!
_disableExamineIndexing = true;
Suspendable.ExamineEvents.SuspendIndexers();
}
}
/// <summary>
/// Called during the Complete operation of the boot manager process
/// </summary>
public void Complete()
{
EnsureUnlockedAndConfigured();
//Ok, now that everything is complete we'll check if we've stored any references to index that need rebuilding and run them
// (see the initialize method for notes) - we'll ensure we remove the event handler too in case examine manager doesn't actually
// initialize during startup, in which case we want it to rebuild the indexes itself.
ExamineManager.Instance.BuildingEmptyIndexOnStartup -= OnInstanceOnBuildingEmptyIndexOnStartup;
//don't do anything if we have disabled this
if (_disableExamineIndexing == false)
{
foreach (var indexer in _indexesToRebuild)
{
indexer.RebuildIndex();
}
}
}
/// <summary>
/// Called to perform the rebuilding indexes on startup if the indexes don't exist
/// </summary>
public void RebuildIndexes()
{
//don't do anything if we have disabled this
if (_disableExamineIndexing) return;
EnsureUnlockedAndConfigured();
//If the developer has explicitly opted out of rebuilding indexes on startup then we
// should adhere to that and not do it, this means that if they are load balancing things will be
// out of sync if they are auto-scaling but there's not much we can do about that.
if (ExamineSettings.Instance.RebuildOnAppStart == false) return;
foreach (var indexer in GetIndexesForColdBoot())
{
indexer.RebuildIndex();
}
}
/// <summary>
/// The method used to create indexes on a cold boot
/// </summary>
/// <remarks>
/// A cold boot is when the server determines it will not (or cannot) process instructions in the cache table and
/// will rebuild it's own caches itself.
/// </remarks>
public IEnumerable<BaseIndexProvider> GetIndexesForColdBoot()
{
// NOTE: This is IMPORTANT! ... we don't want to rebuild any index that is already flagged to be re-indexed
// on startup based on our _indexesToRebuild variable and how Examine auto-rebuilds when indexes are empty.
// This callback is used above for the DatabaseServerMessenger startup options.
// all indexes
IEnumerable<BaseIndexProvider> indexes = ExamineManager.Instance.IndexProviderCollection;
// except those that are already flagged
// and are processed in Complete()
if (_indexesToRebuild.Any())
indexes = indexes.Except(_indexesToRebuild);
// return
foreach (var index in indexes)
yield return index;
}
/// <summary>
/// Must be called to configure each index and ensure it's unlocked before any indexing occurs
/// </summary>
/// <remarks>
/// Indexing rebuilding can occur on a normal boot if the indexes are empty or on a cold boot by the database server messenger. Before
/// either of these happens, we need to configure the indexes.
/// </remarks>
private void EnsureUnlockedAndConfigured()
{
if (_isConfigured) return;
_isConfigured = true;
foreach (var luceneIndexer in ExamineManager.Instance.IndexProviderCollection.OfType<LuceneIndexer>())
{
//We now need to disable waiting for indexing for Examine so that the appdomain is shutdown immediately and doesn't wait for pending
//indexing operations. We used to wait for indexing operations to complete but this can cause more problems than that is worth because
//that could end up halting shutdown for a very long time causing overlapping appdomains and many other problems.
luceneIndexer.WaitForIndexQueueOnShutdown = false;
//we should check if the index is locked ... it shouldn't be! We are using simple fs lock now and we are also ensuring that
//the indexes are not operational unless MainDom is true so if _disableExamineIndexing is false then we should be in charge
if (_disableExamineIndexing == false)
{
var dir = luceneIndexer.GetLuceneDirectory();
if (IndexWriter.IsLocked(dir))
{
_profilingLogger.Logger.Info<ExamineStartup>("Forcing index " + luceneIndexer.IndexSetName + " to be unlocked since it was left in a locked state");
IndexWriter.Unlock(dir);
}
}
}
}
private void OnInstanceOnBuildingEmptyIndexOnStartup(object sender, BuildingEmptyIndexOnStartupEventArgs args)
{
//store the indexer that needs rebuilding because it's empty for when the boot process
// is complete and cancel this current event so the rebuild process doesn't start right now.
args.Cancel = true;
_indexesToRebuild.Add((BaseIndexProvider)args.Indexer);
//check if the index is rebuilding due to an error and log it
if (args.IsHealthy == false)
{
var baseIndex = args.Indexer as BaseIndexProvider;
var name = baseIndex != null ? baseIndex.Name : "[UKNOWN]";
_profilingLogger.Logger.Error<ExamineStartup>(string.Format("The index {0} is rebuilding due to being unreadable/corrupt", name), args.UnhealthyException);
}
}
}
}
@@ -13,7 +13,7 @@ namespace Umbraco.Web
{
internal static class ImageCropperBaseExtensions
{
internal static ImageCropDataSet SerializeToCropDataSet(this string json)
internal static ImageCropDataSet DeserializeToCropDataSet(this string json)
{
var imageCrops = new ImageCropDataSet();
if (json.DetectIsJson())
@@ -232,7 +232,7 @@ namespace Umbraco.Web
ImageCropDataSet cropDataSet = null;
if (string.IsNullOrEmpty(imageCropperValue) == false && imageCropperValue.DetectIsJson() && (imageCropMode == ImageCropMode.Crop || imageCropMode == null))
{
cropDataSet = imageCropperValue.SerializeToCropDataSet();
cropDataSet = imageCropperValue.DeserializeToCropDataSet();
}
return GetCropUrl(
imageUrl, cropDataSet, width, height, cropAlias, quality, imageCropMode,
@@ -52,7 +52,7 @@ namespace Umbraco.Web.Models.Mapping
.ForMember(display => display.Alias, expression => expression.Ignore())
.ForMember(display => display.Tabs, expression => expression.ResolveUsing(new TabsAndPropertiesResolver(applicationContext.Services.TextService)))
.ForMember(display => display.AllowedActions, expression => expression.ResolveUsing(
new ActionButtonsResolver(new Lazy<IUserService>(() => applicationContext.Services.UserService))))
new ActionButtonsResolver(new Lazy<IUserService>(() => applicationContext.Services.UserService), new Lazy<IContentService>(() => applicationContext.Services.ContentService))))
.AfterMap((content, display) => AfterMap(content, display, applicationContext.Services.DataTypeService, applicationContext.Services.TextService,
applicationContext.Services.ContentTypeService));
@@ -219,10 +219,14 @@ namespace Umbraco.Web.Models.Mapping
private class ActionButtonsResolver : ValueResolver<IContent, IEnumerable<string>>
{
private readonly Lazy<IUserService> _userService;
private readonly Lazy<IContentService> _contentService;
public ActionButtonsResolver(Lazy<IUserService> userService)
public ActionButtonsResolver(Lazy<IUserService> userService, Lazy<IContentService> contentService)
{
if (userService == null) throw new ArgumentNullException("userService");
if (contentService == null) throw new ArgumentNullException("contentService");
_userService = userService;
_contentService = contentService;
}
protected override IEnumerable<string> ResolveCore(IContent source)
@@ -234,14 +238,21 @@ namespace Umbraco.Web.Models.Mapping
}
var svc = _userService.Value;
var permissions = svc.GetPermissions(
string path;
if (source.HasIdentity)
path = source.Path;
else
{
var parent = _contentService.Value.GetById(source.ParentId);
path = parent == null ? "-1" : parent.Path;
}
var permissions = svc.GetPermissionsForPath(
//TODO: This is certainly not ideal usage here - perhaps the best way to deal with this in the future is
// with the IUmbracoContextAccessor. In the meantime, if used outside of a web app this will throw a null
// refrence exception :(
UmbracoContext.Current.Security.CurrentUser,
// Here we need to do a special check since this could be new content, in which case we need to get the permissions
// from the parent, not the existing one otherwise permissions would be coming from the root since Id is 0.
source.HasIdentity ? source.Id : source.ParentId)
path)
.GetAllPermissions();
return permissions;
@@ -65,6 +65,8 @@ namespace Umbraco.Web.Models.Mapping
if (source.DefaultTemplate != null)
dest.SetDefaultTemplate(applicationContext.Services.FileService.GetTemplate(source.DefaultTemplate));
else
dest.SetDefaultTemplate(null);
ContentTypeModelMapperExtensions.AfterMapContentTypeSaveToEntity(source, dest, applicationContext);
});
@@ -201,10 +201,24 @@ namespace Umbraco.Web.Models.Mapping
var allContentPermissions = applicationContext.Services.UserService.GetPermissions(@group, true)
.ToDictionary(x => x.EntityId, x => x);
var contentEntities = allContentPermissions.Keys.Count == 0
? new IUmbracoEntity[0]
: applicationContext.Services.EntityService.GetAll(UmbracoObjectTypes.Document, allContentPermissions.Keys.ToArray());
IEnumerable<IUmbracoEntity> contentEntities;
if (allContentPermissions.Keys.Count == 0)
{
contentEntities = new IUmbracoEntity[0];
}
else
{
// a group can end up with way more than 2000 assigned permissions,
// so we need to break them into groups in order to avoid breaking
// the entity service due to too many Sql parameters.
var list = new List<IUmbracoEntity>();
contentEntities = list;
var entityService = applicationContext.Services.EntityService;
foreach (var idGroup in allContentPermissions.Keys.InGroupsOf(2000))
list.AddRange(entityService.GetAll(UmbracoObjectTypes.Document, idGroup.ToArray()));
}
var allAssignedPermissions = new List<AssignedContentPermissions>();
foreach (var entity in contentEntities)
@@ -229,7 +243,7 @@ namespace Umbraco.Web.Models.Mapping
});
//Important! Currently we are never mapping to multiple UserDisplay objects but if we start doing that
// this will cause an N+1 and we'll need to change how this works.
// this will cause an N+1 and we'll need to change how this works.
config.CreateMap<IUser, UserDisplay>()
.ForMember(detail => detail.Avatars, opt => opt.MapFrom(user => user.GetCurrentUserAvatarUrls(applicationContext.Services.UserService, applicationContext.ApplicationCache.RuntimeCache)))
.ForMember(detail => detail.Username, opt => opt.MapFrom(user => user.Username))
@@ -253,7 +267,7 @@ namespace Umbraco.Web.Models.Mapping
"media/mediaRoot")))
.ForMember(
detail => detail.StartContentIds,
opt => opt.MapFrom(user => GetStartNodeValues(
opt => opt.MapFrom(user => GetStartNodeValues(
user.StartContentIds.ToArray(),
applicationContext.Services.TextService,
applicationContext.Services.EntityService,
@@ -261,7 +275,7 @@ namespace Umbraco.Web.Models.Mapping
"content/contentRoot")))
.ForMember(
detail => detail.StartMediaIds,
opt => opt.MapFrom(user => GetStartNodeValues(
opt => opt.MapFrom(user => GetStartNodeValues(
user.StartMediaIds.ToArray(),
applicationContext.Services.TextService,
applicationContext.Services.EntityService,
@@ -328,7 +342,7 @@ namespace Umbraco.Web.Models.Mapping
//the best we can do here is to return the user's first user group as a IUserType object
//but we should attempt to return any group that is the built in ones first
var groups = user.Groups.ToArray();
detail.UserGroups = user.Groups.Select(x => x.Alias).ToArray();
detail.UserGroups = user.Groups.Select(x => x.Alias).ToArray();
if (groups.Length == 0)
{
@@ -369,8 +383,8 @@ namespace Umbraco.Web.Models.Mapping
}
private IEnumerable<EntityBasic> GetStartNodeValues(int[] startNodeIds,
ILocalizedTextService textService, IEntityService entityService, UmbracoObjectTypes objectType,
private IEnumerable<EntityBasic> GetStartNodeValues(int[] startNodeIds,
ILocalizedTextService textService, IEntityService entityService, UmbracoObjectTypes objectType,
string localizedKey)
{
if (startNodeIds.Length > 0)
@@ -385,7 +399,7 @@ namespace Umbraco.Web.Models.Mapping
return startNodes;
}
return Enumerable.Empty<EntityBasic>();
}
}
private void MapUserGroupBasic(ServiceContext services, dynamic group, UserGroupBasic display)
{
@@ -85,6 +85,9 @@ namespace Umbraco.Web.PropertyEditors.ValueConverters
/// </returns>
public override object ConvertDataToSource(PublishedPropertyType propertyType, object source, bool preview)
{
if (source == null)
return null;
if (IsMultipleDataType(propertyType.DataTypeId, propertyType.PropertyEditorAlias))
{
var nodeIds =
@@ -251,7 +251,7 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
// move to parent node
e = (XmlElement) e.ParentNode;
id = int.Parse(e.GetAttribute("id"));
id = int.Parse(e.GetAttribute("id"), CultureInfo.InvariantCulture);
hasDomains = id != -1 && domainHelper.NodeHasDomains(id);
}
@@ -74,11 +74,47 @@ namespace Umbraco.Web.PublishedCache.XmlPublishedCache
public virtual IEnumerable<IPublishedContent> GetAtRoot(UmbracoContext umbracoContext, bool preview)
{
//TODO: We should be able to look these ids first in Examine!
var searchProvider = GetSearchProviderSafe();
if (searchProvider != null)
{
try
{
// first check in Examine for the cache values
// +(+parentID:-1) +__IndexType:media
var criteria = searchProvider.CreateSearchCriteria("media");
var filter = criteria.ParentId(-1).Not().Field(UmbracoContentIndexer.IndexPathFieldName, "-1,-21,".MultipleCharacterWildcard());
var result = searchProvider.Search(filter.Compile());
if (result != null)
return result.Select(x => CreateFromCacheValues(ConvertFromSearchResult(x)));
}
catch (Exception ex)
{
if (ex is FileNotFoundException)
{
//Currently examine is throwing FileNotFound exceptions when we have a loadbalanced filestore and a node is published in umbraco
//See this thread: http://examine.cdodeplex.com/discussions/264341
//Catch the exception here for the time being, and just fallback to GetMedia
//TODO: Need to fix examine in LB scenarios!
LogHelper.Error<PublishedMediaCache>("Could not load data from Examine index for media", ex);
}
else if (ex is AlreadyClosedException)
{
//If the app domain is shutting down and the site is under heavy load the index reader will be closed and it really cannot
//be re-opened since the app domain is shutting down. In this case we have no option but to try to load the data from the db.
LogHelper.Error<PublishedMediaCache>("Could not load data from Examine index for media, the app domain is most likely in a shutdown state", ex);
}
else throw;
}
}
//something went wrong, fetch from the db
var rootMedia = _applicationContext.Services.MediaService.GetRootMedia();
return rootMedia.Select(m => GetUmbracoMedia(m.Id));
}
return rootMedia.Select(m => CreateFromCacheValues(ConvertFromIMedia(m)));
}
public virtual IPublishedContent GetSingleByXPath(UmbracoContext umbracoContext, bool preview, string xpath, XPathVariable[] vars)
{
+1 -1
View File
@@ -230,7 +230,7 @@ namespace Umbraco.Web
{
// todo: in v8, implement in a more efficient way
var legacyXml = UmbracoConfig.For.UmbracoSettings().Content.UseLegacyXmlSchema;
var xpath = legacyXml ? "//node [@key=$guid]" : "//* [@isDoc and @key=$guid]";
var xpath = legacyXml ? "//node [@key=$guid]" : "//* [@key=$guid]";
var doc = cache.GetSingleByXPath(xpath, new XPathVariable("guid", id.ToString()));
return doc;
}
+5 -7
View File
@@ -105,15 +105,14 @@
<HintPath>..\packages\AutoMapper.3.3.1\lib\net40\AutoMapper.Net4.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="ClientDependency.Core, Version=1.9.2.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ClientDependency.1.9.2\lib\net45\ClientDependency.Core.dll</HintPath>
<Private>True</Private>
<Reference Include="ClientDependency.Core, Version=1.9.5.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ClientDependency.1.9.5\lib\net45\ClientDependency.Core.dll</HintPath>
</Reference>
<Reference Include="dotless.Core, Version=1.5.2.0, Culture=neutral, PublicKeyToken=96b446c9e63eae34, processorArchitecture=MSIL">
<HintPath>..\packages\dotless.1.5.2\lib\dotless.Core.dll</HintPath>
</Reference>
<Reference Include="Examine, Version=0.1.88.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.88\lib\net45\Examine.dll</HintPath>
<Reference Include="Examine, Version=0.1.89.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.89\lib\net45\Examine.dll</HintPath>
</Reference>
<Reference Include="HtmlAgilityPack, Version=1.4.9.5, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a, processorArchitecture=MSIL">
<HintPath>..\packages\HtmlAgilityPack.1.4.9.5\lib\Net45\HtmlAgilityPack.dll</HintPath>
@@ -121,11 +120,9 @@
</Reference>
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
<HintPath>..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Lucene.Net, Version=2.9.4.1, Culture=neutral, PublicKeyToken=85089178b9ac3181, processorArchitecture=MSIL">
<HintPath>..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="MarkdownSharp, Version=1.14.5.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Markdown.1.14.7\lib\net45\MarkdownSharp.dll</HintPath>
@@ -333,6 +330,7 @@
<Compile Include="Editors\UserGroupEditorAuthorizationHelper.cs" />
<Compile Include="Editors\UserGroupsController.cs" />
<Compile Include="Editors\UserGroupValidateAttribute.cs" />
<Compile Include="ExamineStartup.cs" />
<Compile Include="Extensions\UdiExtensions.cs" />
<Compile Include="HealthCheck\Checks\Config\AbstractConfigCheck.cs" />
<Compile Include="HealthCheck\Checks\Config\AcceptableConfiguration.cs" />
+1 -10
View File
@@ -97,17 +97,8 @@ namespace Umbraco.Web.WebApi.Binders
if (member == null)
{
throw new InvalidOperationException("Could not find member with key " + key);
}
}
var standardProps = Constants.Conventions.Member.GetStandardPropertyTypeStubs();
//remove all membership properties, these values are set with the membership provider.
var exclude = standardProps.Select(x => x.Value.Alias).ToArray();
foreach (var remove in exclude)
{
member.Properties.Remove(remove);
}
return member;
}
+58 -106
View File
@@ -2,19 +2,17 @@
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.Configuration;
using System.Web.Http;
using System.Web.Http.Dispatcher;
using System.Web.Mvc;
using System.Web.Routing;
using ClientDependency.Core.CompositeFiles.Providers;
using ClientDependency.Core.Config;
using Examine;
using Examine.Config;
using Examine.Providers;
using umbraco;
using Umbraco.Core;
using Umbraco.Core.Configuration;
using Umbraco.Core.Dictionary;
@@ -27,25 +25,18 @@ using Umbraco.Core.PropertyEditors.ValueConverters;
using Umbraco.Core.Sync;
using Umbraco.Web.Dictionary;
using Umbraco.Web.Install;
using Umbraco.Web.Macros;
using Umbraco.Web.Media;
using Umbraco.Web.Media.ThumbnailProviders;
using Umbraco.Web.Models;
using Umbraco.Web.Mvc;
using Umbraco.Web.PropertyEditors;
using Umbraco.Web.PropertyEditors.ValueConverters;
using Umbraco.Web.PublishedCache;
using Umbraco.Web.Routing;
using Umbraco.Web.Security;
using Umbraco.Web.Scheduling;
using Umbraco.Web.UI.JavaScript;
using Umbraco.Web.WebApi;
using umbraco.BusinessLogic;
using Umbraco.Core.Cache;
using Umbraco.Core.Events;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.UnitOfWork;
using Umbraco.Core.Publishing;
using Umbraco.Core.Scoping;
using Umbraco.Core.Services;
using Umbraco.Web.Editors;
@@ -64,8 +55,9 @@ namespace Umbraco.Web
public class WebBootManager : CoreBootManager
{
private readonly bool _isForTesting;
//NOTE: see the Initialize method for what this is used for
private static readonly List<BaseIndexProvider> IndexesToRebuild = new List<BaseIndexProvider>();
//needs to be static because we have the public static method GetIndexesForColdBoot
private static ExamineStartup _examineStartup;
public WebBootManager(UmbracoApplicationBase umbracoApplication)
: base(umbracoApplication)
@@ -109,25 +101,12 @@ namespace Umbraco.Web
/// <returns></returns>
public override IBootManager Initialize()
{
//This is basically a hack for this item: http://issues.umbraco.org/issue/U4-5976
// when Examine initializes it will try to rebuild if the indexes are empty, however in many cases not all of Examine's
// event handlers will be assigned during bootup when the rebuilding starts which is a problem. So with the examine 0.1.58.2941 build
// it has an event we can subscribe to in order to cancel this rebuilding process, but what we'll do is cancel it and postpone the rebuilding until the
// boot process has completed. It's a hack but it works.
ExamineManager.Instance.BuildingEmptyIndexOnStartup += OnInstanceOnBuildingEmptyIndexOnStartup;
base.Initialize();
// Backwards compatibility - set the path and URL type for ClientDependency 1.5.1 [LK]
ClientDependency.Core.CompositeFiles.Providers.XmlFileMapper.FileMapVirtualFolder = "~/App_Data/TEMP/ClientDependency";
ClientDependency.Core.CompositeFiles.Providers.BaseCompositeFileProcessingProvider.UrlTypeDefault = ClientDependency.Core.CompositeFiles.Providers.CompositeUrlType.Base64QueryStrings;
_examineStartup = new ExamineStartup(ApplicationContext);
_examineStartup.Initialize();
var section = ConfigurationManager.GetSection("system.web/httpRuntime") as HttpRuntimeSection;
if (section != null)
{
//set the max url length for CDF to be the smallest of the max query length, max request length
ClientDependency.Core.CompositeFiles.CompositeDependencyHandler.MaxHandlerUrlLength = Math.Min(section.MaxQueryStringLength, section.MaxRequestLength);
}
ConfigureClientDependency();
//set master controller factory
ControllerBuilder.Current.SetControllerFactory(
@@ -144,14 +123,6 @@ namespace Umbraco.Web
////add the profiling action filter
//GlobalFilters.Filters.Add(new ProfilingActionFilter());
//Register a custom renderer - used to process property editor dependencies
var renderer = new DependencyPathRenderer();
renderer.Initialize("Umbraco.DependencyPathRenderer", new NameValueCollection
{
{ "compositeFileHandlerPath", ClientDependencySettings.Instance.CompositeFileHandlerPath }
});
ClientDependencySettings.Instance.MvcRendererCollection.Add(renderer);
// Disable the X-AspNetMvc-Version HTTP Header
MvcHandler.DisableMvcResponseHeader = true;
@@ -214,25 +185,15 @@ namespace Umbraco.Web
//Now, startup all of our legacy startup handler
ApplicationEventsResolver.Current.InstantiateLegacyStartupHandlers();
//Ok, now that everything is complete we'll check if we've stored any references to index that need rebuilding and run them
// (see the initialize method for notes) - we'll ensure we remove the event handler too in case examine manager doesn't actually
// initialize during startup, in which case we want it to rebuild the indexes itself.
ExamineManager.Instance.BuildingEmptyIndexOnStartup -= OnInstanceOnBuildingEmptyIndexOnStartup;
if (IndexesToRebuild.Any())
{
foreach (var indexer in IndexesToRebuild)
{
indexer.RebuildIndex();
}
}
_examineStartup.Complete();
//Now ensure webapi is initialized after everything
GlobalConfiguration.Configuration.EnsureInitialized();
return this;
}
internal static void ConfigureGlobalFilters()
{
@@ -298,6 +259,45 @@ namespace Umbraco.Web
RoutePluginControllers();
}
private void ConfigureClientDependency()
{
// Backwards compatibility - set the path and URL type for ClientDependency 1.5.1 [LK]
XmlFileMapper.FileMapDefaultFolder = "~/App_Data/TEMP/ClientDependency";
BaseCompositeFileProcessingProvider.UrlTypeDefault = CompositeUrlType.Base64QueryStrings;
// Now we need to detect if we are running umbracoLocalTempStorage as EnvironmentTemp and in that case we want to change the CDF file
// location to be there
if (GlobalSettings.LocalTempStorageLocation == LocalTempStorage.EnvironmentTemp)
{
var appDomainHash = HttpRuntime.AppDomainAppId.ToSHA1();
var cachePath = Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData",
//include the appdomain hash is just a safety check, for example if a website is moved from worker A to worker B and then back
// to worker A again, in theory the %temp% folder should already be empty but we really want to make sure that its not
// utilizing an old path
appDomainHash);
//set the file map and composite file default location to the %temp% location
BaseCompositeFileProcessingProvider.CompositeFilePathDefaultFolder
= XmlFileMapper.FileMapDefaultFolder
= Path.Combine(cachePath, "ClientDependency");
}
var section = ConfigurationManager.GetSection("system.web/httpRuntime") as HttpRuntimeSection;
if (section != null)
{
//set the max url length for CDF to be the smallest of the max query length, max request length
ClientDependency.Core.CompositeFiles.CompositeDependencyHandler.MaxHandlerUrlLength = Math.Min(section.MaxQueryStringLength, section.MaxRequestLength);
}
//Register a custom renderer - used to process property editor dependencies
var renderer = new DependencyPathRenderer();
renderer.Initialize("Umbraco.DependencyPathRenderer", new NameValueCollection
{
{ "compositeFileHandlerPath", ClientDependencySettings.Instance.CompositeFileHandlerPath }
});
ClientDependencySettings.Instance.MvcRendererCollection.Add(renderer);
}
private void RoutePluginControllers()
{
var umbracoPath = GlobalSettings.UmbracoMvcArea;
@@ -377,11 +377,11 @@ namespace Umbraco.Web
{
base.InitializeResolvers();
SearchableTreeResolver.Current = new SearchableTreeResolver(ServiceProvider, LoggerResolver.Current.Logger, ApplicationContext.Services.ApplicationTreeService, () => PluginManager.ResolveSearchableTrees());
SearchableTreeResolver.Current = new SearchableTreeResolver(ServiceProvider, LoggerResolver.Current.Logger, ApplicationContext.Services.ApplicationTreeService, () => PluginManager.ResolveSearchableTrees());
XsltExtensionsResolver.Current = new XsltExtensionsResolver(ServiceProvider, LoggerResolver.Current.Logger, () => PluginManager.ResolveXsltExtensions());
EditorValidationResolver.Current= new EditorValidationResolver(ServiceProvider, LoggerResolver.Current.Logger, () => PluginManager.ResolveTypes<IEditorValidator>());
EditorValidationResolver.Current = new EditorValidationResolver(ServiceProvider, LoggerResolver.Current.Logger, () => PluginManager.ResolveTypes<IEditorValidator>());
//set the default RenderMvcController
DefaultRenderMvcControllerResolver.Current = new DefaultRenderMvcControllerResolver(typeof(RenderMvcController));
@@ -421,23 +421,6 @@ namespace Umbraco.Web
}
else
{
//We are using a custom action here so we can check the examine settings value first, we don't want to
// put that check into the CreateIndexesOnColdBoot method because developers may choose to use this
// method directly and they will be in charge of this check if they need it
Action rebuildIndexes = () =>
{
//If the developer has explicitly opted out of rebuilding indexes on startup then we
// should adhere to that and not do it, this means that if they are load balancing things will be
// out of sync if they are auto-scaling but there's not much we can do about that.
if (ExamineSettings.Instance.RebuildOnAppStart == false) return;
foreach (var indexer in GetIndexesForColdBoot())
{
indexer.RebuildIndex();
}
};
ServerMessengerResolver.Current.SetServerMessenger(new BatchedDatabaseServerMessenger(
ApplicationContext,
true,
@@ -453,7 +436,7 @@ namespace Umbraco.Web
//rebuild indexes if the server is not synced
// NOTE: This will rebuild ALL indexes including the members, if developers want to target specific
// indexes then they can adjust this logic themselves.
rebuildIndexes
() => _examineStartup.RebuildIndexes()
}
}));
}
@@ -489,9 +472,9 @@ namespace Umbraco.Web
// add all known factories, devs can then modify this list on application
// startup either by binding to events or in their own global.asax
new[]
{
typeof (RenderControllerFactory)
});
{
typeof (RenderControllerFactory)
});
UrlProviderResolver.Current = new UrlProviderResolver(
ServiceProvider, LoggerResolver.Current.Logger,
@@ -559,42 +542,11 @@ namespace Umbraco.Web
/// <remarks>
/// A cold boot is when the server determines it will not (or cannot) process instructions in the cache table and
/// will rebuild it's own caches itself.
/// TODO: Does this method need to exist? Is it used publicly elsewhere (i.e. outside of core?)
/// </remarks>
public static IEnumerable<BaseIndexProvider> GetIndexesForColdBoot()
{
// NOTE: This is IMPORTANT! ... we don't want to rebuild any index that is already flagged to be re-indexed
// on startup based on our _indexesToRebuild variable and how Examine auto-rebuilds when indexes are empty.
// This callback is used above for the DatabaseServerMessenger startup options.
// all indexes
IEnumerable<BaseIndexProvider> indexes = ExamineManager.Instance.IndexProviderCollection;
// except those that are already flagged
// and are processed in Complete()
if (IndexesToRebuild.Any())
indexes = indexes.Except(IndexesToRebuild);
// return
foreach (var index in indexes)
yield return index;
}
private void OnInstanceOnBuildingEmptyIndexOnStartup(object sender, BuildingEmptyIndexOnStartupEventArgs args)
{
//store the indexer that needs rebuilding because it's empty for when the boot process
// is complete and cancel this current event so the rebuild process doesn't start right now.
args.Cancel = true;
IndexesToRebuild.Add((BaseIndexProvider)args.Indexer);
//check if the index is rebuilding due to an error and log it
if (args.IsHealthy == false)
{
var baseIndex = args.Indexer as BaseIndexProvider;
var name = baseIndex != null ? baseIndex.Name : "[UKNOWN]";
ProfilingLogger.Logger.Error<WebBootManager>(string.Format("The index {0} is rebuilding due to being unreadable/corrupt", name), args.UnhealthyException);
}
return _examineStartup.GetIndexesForColdBoot();
}
}
}
@@ -8,7 +8,9 @@ using Examine;
using Examine.LuceneEngine;
using Examine.LuceneEngine.Providers;
using Examine.Providers;
using Lucene.Net.Index;
using Lucene.Net.Search;
using Lucene.Net.Store;
using Umbraco.Core;
using Umbraco.Core.Logging;
using Umbraco.Web.Search;
@@ -189,20 +191,39 @@ namespace Umbraco.Web.WebServices
{
indexer.RebuildIndex();
}
catch (LockObtainFailedException)
{
//this will occur if the index is locked (which it should defo not be!) so in this case we'll forcibly unlock it and try again
try
{
IndexWriter.Unlock(indexer.GetLuceneDirectory());
indexer.RebuildIndex();
}
catch (Exception e)
{
return HandleException(e, indexer);
}
}
catch (Exception ex)
{
//ensure it's not listening
indexer.IndexOperationComplete -= Indexer_IndexOperationComplete;
LogHelper.Error<ExamineManagementApiController>("An error occurred rebuilding index", ex);
var response = Request.CreateResponse(HttpStatusCode.Conflict);
response.Content = new StringContent(string.Format("The index could not be rebuilt at this time, most likely there is another thread currently writing to the index. Error: {0}", ex));
response.ReasonPhrase = "Could Not Rebuild";
return response;
return HandleException(ex, indexer);
}
}
return msg;
}
private HttpResponseMessage HandleException(Exception ex, LuceneIndexer indexer)
{
//ensure it's not listening
indexer.IndexOperationComplete -= Indexer_IndexOperationComplete;
LogHelper.Error<ExamineManagementApiController>("An error occurred rebuilding index", ex);
var response = Request.CreateResponse(HttpStatusCode.Conflict);
response.Content = new StringContent(string.Format("The index could not be rebuilt at this time, most likely there is another thread currently writing to the index. Error: {0}", ex));
response.ReasonPhrase = "Could Not Rebuild";
return response;
}
//static listener so it's not GC'd
private static void Indexer_IndexOperationComplete(object sender, EventArgs e)
{
+2 -2
View File
@@ -1,9 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AutoMapper" version="3.3.1" targetFramework="net45" />
<package id="ClientDependency" version="1.9.2" targetFramework="net45" />
<package id="ClientDependency" version="1.9.5" targetFramework="net45" />
<package id="dotless" version="1.5.2" targetFramework="net45" />
<package id="Examine" version="0.1.88" targetFramework="net45" />
<package id="Examine" version="0.1.89" targetFramework="net45" />
<package id="HtmlAgilityPack" version="1.4.9.5" targetFramework="net45" />
<package id="Lucene.Net" version="2.9.4.1" targetFramework="net45" />
<package id="Markdown" version="1.14.7" targetFramework="net45" />
@@ -7,6 +7,7 @@
<style type="text/css">
.gridHeader{border-bottom:2px solid #D9D7D7;}
.gridItem{border-color: #D9D7D7;}
html, body {overflow: initial;}
</style>
<umb:CssInclude ID="CssInclude2" runat="server" FilePath="Tree/treeIcons.css" PathNameAlias="UmbracoClient" />
+8 -3
View File
@@ -150,7 +150,7 @@ namespace UmbracoExamine
{
//By default, we will be using the UmbracoDataService
//generally this would only need to be set differently for unit testing
DataService = new UmbracoDataService();
DataService = CreateDefaultUmbracoDataService();
}
DataService.LogService.LogLevel = LoggingLevel.Normal;
@@ -206,10 +206,15 @@ namespace UmbracoExamine
}
}
}
}
#endregion
protected virtual IDataService CreateDefaultUmbracoDataService()
{
return new UmbracoDataService();
}
/// <summary>
/// Used to aquire the internal searcher
/// </summary>
@@ -13,10 +13,12 @@ namespace UmbracoExamine.Config
/// </summary>
public static class IndexSetExtensions
{
internal static IIndexCriteria ToIndexCriteria(this IndexSet set, IDataService svc,
StaticFieldCollection indexFieldPolicies)
internal static IIndexCriteria ToIndexCriteria(this IndexSet set,
IDataService svc,
StaticFieldCollection indexFieldPolicies,
IEnumerable<IndexField> additionalUserFields = null)
{
return new LazyIndexCriteria(set, svc, indexFieldPolicies);
return new LazyIndexCriteria(set, svc, indexFieldPolicies, additionalUserFields);
}
/// <summary>
+17 -3
View File
@@ -12,7 +12,8 @@ namespace UmbracoExamine.Config
public LazyIndexCriteria(
IndexSet set,
IDataService svc,
StaticFieldCollection indexFieldPolicies)
StaticFieldCollection indexFieldPolicies,
IEnumerable<IndexField> additionalUserFields = null)
{
if (set == null) throw new ArgumentNullException("set");
if (indexFieldPolicies == null) throw new ArgumentNullException("indexFieldPolicies");
@@ -21,7 +22,7 @@ namespace UmbracoExamine.Config
_lazyCriteria = new Lazy<IIndexCriteria>(() =>
{
var attributeFields = set.IndexAttributeFields.Cast<IIndexField>().ToArray();
var userFields = set.IndexUserFields.Cast<IIndexField>().ToArray();
var userFields = set.IndexUserFields.Cast<IIndexField>().ToList();
var includeNodeTypes = set.IncludeNodeTypes.Cast<IIndexField>().Select(x => x.Name).ToArray();
var excludeNodeTypes = set.ExcludeNodeTypes.Cast<IIndexField>().Select(x => x.Name).ToArray();
var parentId = set.IndexParentId;
@@ -44,7 +45,7 @@ namespace UmbracoExamine.Config
}
fields.Add(field);
}
userFields = fields.ToArray();
userFields = fields.ToList();
}
//if there are no attribute fields defined, we'll populate them from the data source (include them all)
@@ -68,6 +69,19 @@ namespace UmbracoExamine.Config
attributeFields = fields.ToArray();
}
//merge in the additional user fields if any are defined
if (additionalUserFields != null)
{
foreach (var field in additionalUserFields)
{
var f = field; //copy local
if (userFields.Any(x => x.Name == f.Name) == false)
{
userFields.Add(f);
}
}
}
return new IndexCriteria(
attributeFields,
@@ -13,7 +13,7 @@ namespace UmbracoExamine.DataServices
{
public class UmbracoContentService : IContentService
{
private readonly ApplicationContext _applicationContext;
protected ApplicationContext ApplicationContext { get; private set; }
public UmbracoContentService()
: this(ApplicationContext.Current)
@@ -21,7 +21,7 @@ namespace UmbracoExamine.DataServices
public UmbracoContentService(ApplicationContext applicationContext)
{
_applicationContext = applicationContext;
ApplicationContext = applicationContext;
}
/// <summary>
@@ -60,11 +60,11 @@ namespace UmbracoExamine.DataServices
using (var scope = ApplicationContext.Current.ScopeProvider.CreateScope())
{
var xmlContent = XDocument.Parse("<content></content>");
var rootContent = _applicationContext.Services.ContentService.GetRootContent();
var rootContent = ApplicationContext.Services.ContentService.GetRootContent();
foreach (var c in rootContent)
{
// not sure this uses the database, but better be save
xmlContent.Root.Add(c.ToDeepXml(_applicationContext.Services.PackagingService));
xmlContent.Root.Add(c.ToDeepXml(ApplicationContext.Services.PackagingService));
}
var result = ((IEnumerable)xmlContent.XPathEvaluate(xpath)).Cast<XElement>();
scope.Complete();
@@ -82,7 +82,7 @@ namespace UmbracoExamine.DataServices
{
using (var scope = ApplicationContext.Current.ScopeProvider.CreateScope())
{
var ret = _applicationContext.Services.PublicAccessService.IsProtected(path.EnsureEndsWith("," + nodeId));
var ret = ApplicationContext.Services.PublicAccessService.IsProtected(path.EnsureEndsWith("," + nodeId));
scope.Complete();
return ret;
}
@@ -93,14 +93,26 @@ namespace UmbracoExamine.DataServices
/// </summary>
/// <returns></returns>
public IEnumerable<string> GetAllUserPropertyNames()
public virtual IEnumerable<string> GetAllUserPropertyNames()
{
using (var scope = ApplicationContext.Current.ScopeProvider.CreateScope())
{
try
{
var result = _applicationContext.DatabaseContext.Database.Fetch<string>("select distinct alias from cmsPropertyType order by alias");
scope.Complete();
{
//only return the property type aliases for media and content
var result = ApplicationContext.DatabaseContext.Database.Fetch<string>(
@"select distinct cmsPropertyType.alias from cmsPropertyType
inner join cmsContentType on cmsContentType.nodeId = cmsPropertyType.contentTypeId
inner join umbracoNode on umbracoNode.id = cmsContentType.nodeId
where umbracoNode.nodeObjectType = @contentNodeObjectType OR umbracoNode.nodeObjectType = @mediaNodeObjectType
order by alias", new
{
contentNodeObjectType = Constants.ObjectTypes.DocumentType,
mediaNodeObjectType = Constants.ObjectTypes.MediaType
});
scope.Complete();
return result;
}
catch (Exception ex)
@@ -0,0 +1,37 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core;
using Umbraco.Core.Logging;
namespace UmbracoExamine.DataServices
{
public class UmbracoMemberContentService : UmbracoContentService
{
public override IEnumerable<string> GetAllUserPropertyNames()
{
using (var scope = ApplicationContext.Current.ScopeProvider.CreateScope())
{
try
{
//only return the property type aliases for members
var result = ApplicationContext.DatabaseContext.Database.Fetch<string>(
@"select distinct cmsPropertyType.alias from cmsPropertyType
inner join cmsContentType on cmsContentType.nodeId = cmsPropertyType.contentTypeId
inner join umbracoNode on umbracoNode.id = cmsContentType.nodeId
where umbracoNode.nodeObjectType = @nodeObjectType
order by alias", new {nodeObjectType = Constants.ObjectTypes.MemberType});
scope.Complete();
return result;
}
catch (Exception ex)
{
LogHelper.Error<UmbracoMemberContentService>("EXCEPTION OCCURRED reading GetAllUserPropertyNames", ex);
return Enumerable.Empty<string>();
}
}
}
}
}
@@ -0,0 +1,10 @@
namespace UmbracoExamine.DataServices
{
public class UmbracoMemberDataService : UmbracoDataService
{
public UmbracoMemberDataService()
{
ContentService = new UmbracoMemberContentService();
}
}
}
@@ -0,0 +1,26 @@
using System.IO;
using Examine;
using Examine.LuceneEngine;
using Lucene.Net.Store;
namespace UmbracoExamine
{
/// <summary>
/// A custom <see cref="SimpleFSLockFactory"/> that ensures a prefixless lock prefix
/// </summary>
/// <remarks>
/// This is a work around for the Lucene APIs. By default Lucene will use a null prefix however when we set a custom
/// lock factory the null prefix is overwritten.
/// </remarks>
public class NoPrefixSimpleFsLockFactory : SimpleFSLockFactory
{
public NoPrefixSimpleFsLockFactory(DirectoryInfo lockDir) : base(lockDir)
{
}
public override void SetLockPrefix(string lockPrefix)
{
base.SetLockPrefix(null);
}
}
}
+7 -3
View File
@@ -410,7 +410,11 @@ namespace UmbracoExamine
{
if (SupportedTypes.Contains(type) == false)
return;
//if the app is shutting down do not continue
if (IsCancellationRequested)
return;
var pageIndex = 0;
DataService.LogService.AddInfoLog(-1, string.Format("PerformIndexAll - Start data queries - {0}", type));
@@ -530,7 +534,7 @@ namespace UmbracoExamine
content, notPublished).WhereNotNull(), type);
pageIndex++;
} while (currentPageSize == PageSize);
} while (currentPageSize == PageSize && IsCancellationRequested == false); //do not continue if app is shutting down
}
break;
@@ -628,7 +632,7 @@ namespace UmbracoExamine
AddNodesToIndex(xElements, type);
pageIndex++;
} while (more);
} while (more && IsCancellationRequested == false); //don't continue if the app is shutting down
}
internal static IEnumerable<XElement> GetSerializedContent(
+5 -4
View File
@@ -82,16 +82,14 @@
<AssemblyOriginatorKeyFile>..\Solution Items\TheFARM-Public.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>
<ItemGroup>
<Reference Include="Examine, Version=0.1.88.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.88\lib\net45\Examine.dll</HintPath>
<Reference Include="Examine, Version=0.1.89.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.89\lib\net45\Examine.dll</HintPath>
</Reference>
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
<HintPath>..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Lucene.Net, Version=2.9.4.1, Culture=neutral, PublicKeyToken=85089178b9ac3181, processorArchitecture=MSIL">
<HintPath>..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="System" />
@@ -119,6 +117,8 @@
<Compile Include="DataServices\UmbracoDataService.cs" />
<Compile Include="DataServices\UmbracoContentService.cs" />
<Compile Include="DataServices\UmbracoMediaService.cs" />
<Compile Include="DataServices\UmbracoMemberContentService.cs" />
<Compile Include="DataServices\UmbracoMemberDataService.cs" />
<Compile Include="DeletePolicyTracker.cs" />
<Compile Include="ExamineHelper.cs" />
<Compile Include="IndexTypes.cs" />
@@ -134,6 +134,7 @@
<Compile Include="LocalStorage\MultiIndexLockFactory.cs" />
<Compile Include="LocalStorage\MultiIndexOutput.cs" />
<Compile Include="LoggingLevel.cs" />
<Compile Include="NoPrefixSimpleFsLockFactory.cs" />
<Compile Include="StaticField.cs" />
<Compile Include="StaticFieldCollection.cs" />
<Compile Include="UmbracoMemberIndexer.cs" />
+26 -27
View File
@@ -19,6 +19,8 @@ using Lucene.Net.Analysis;
namespace UmbracoExamine
{
/// <summary>
/// Custom indexer for members
/// </summary>
@@ -101,6 +103,11 @@ namespace UmbracoExamine
_memberTypeService = memberTypeService;
}
protected override IDataService CreateDefaultUmbracoDataService()
{
return new UmbracoMemberDataService();
}
/// <summary>
/// Ensures that the'_searchEmail' is added to the user fields so that it is indexed - without having to modify the config
/// </summary>
@@ -108,34 +115,26 @@ namespace UmbracoExamine
/// <returns></returns>
protected override IIndexCriteria GetIndexerData(IndexSet indexSet)
{
var indexerData = base.GetIndexerData(indexSet);
if (CanInitialize())
{
//If the fields are missing a custom _searchEmail, then add it
if (indexerData.UserFields.Any(x => x.Name == "_searchEmail") == false)
//Add a custom _searchEmail to the index criteria no matter what is in config
var field = new IndexField { Name = "_searchEmail" };
StaticField policy;
if (IndexFieldPolicies.TryGetValue("_searchEmail", out policy))
{
var field = new IndexField { Name = "_searchEmail" };
StaticField policy;
if (IndexFieldPolicies.TryGetValue("_searchEmail", out policy))
{
field.Type = policy.Type;
field.EnableSorting = policy.EnableSorting;
}
return new IndexCriteria(
indexerData.StandardFields,
indexerData.UserFields.Concat(new[] { field }),
indexerData.IncludeNodeTypes,
indexerData.ExcludeNodeTypes,
indexerData.ParentNodeId
);
field.Type = policy.Type;
field.EnableSorting = policy.EnableSorting;
}
}
return indexerData;
return indexSet.ToIndexCriteria(DataService, IndexFieldPolicies,
//add additional explicit fields
new []{field});
}
else
{
return base.GetIndexerData(indexSet);
}
}
/// <summary>
@@ -198,7 +197,7 @@ namespace UmbracoExamine
AddNodesToIndex(GetSerializedMembers(members), type);
pageIndex++;
} while (members.Length == pageSize);
} while (members.Length == pageSize && IsCancellationRequested == false); //don't continue if the app is shutting down
}
}
else
@@ -212,7 +211,7 @@ namespace UmbracoExamine
AddNodesToIndex(GetSerializedMembers(members), type);
pageIndex++;
} while (members.Length == pageSize);
} while (members.Length == pageSize && IsCancellationRequested == false); //don't continue if the app is shutting down
}
}
}
@@ -233,8 +232,8 @@ namespace UmbracoExamine
protected override XDocument GetXDocument(string xPath, string type)
{
throw new NotSupportedException();
}
}
/// <summary>
/// Add the special __key and _searchEmail fields
/// </summary>
+1 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Examine" version="0.1.88" targetFramework="net45" />
<package id="Examine" version="0.1.89" targetFramework="net45" />
<package id="Lucene.Net" version="2.9.4.1" targetFramework="net45" />
<package id="SharpZipLib" version="0.86.0" targetFramework="net45" />
</packages>

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