Compare commits

...

173 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
Sebastiaan Jansssen b6b7b9f433 Bump version to 7.7.7 2017-12-11 13:57:31 +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
Mikkel Holck Madsen fb99b101d8 Merge pull request #2340 from umbraco/temp-U4-10610
U4-10610 Cannot restore content templates
2017-12-05 13:47:11 +01:00
Claus 0ce7efc978 U4-10610 Cannot restore content templates 2017-12-05 10:19:12 +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
Mikkel Holck Madsen 11bdfbba19 Merge pull request #2338 from umbraco/temp-u4-10715
U4-10715 - scheduled publishing and LB issue
2017-11-30 10:57:12 +01:00
Stephan 9694831638 U4-10715 - scheduled publishing and LB issue 2017-11-30 08:54:16 +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
bjarnef 8d14a3ef2c added number validation in embed overlay 2017-11-20 12:36:12 +01:00
bjarnef 2f3d9c9509 localize texts 2017-11-20 12:32:09 +01:00
Robert 6e8f3b6e13 Merge pull request #2324 from umbraco/temp-UAASSSCRUM-1254
Added custom RollingFileAppender and changed rollingStyle to "size"
2017-11-17 13:03:48 +01:00
mikkelhm b9cbdbd9a7 Add rename of Appender to csproj 2017-11-17 12:01:32 +01:00
mikkelhm ebf35356a8 Updates the CustomRollingFileAppender to read config settings to control it 2017-11-17 12:00:42 +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
Sebastiaan Janssen 7eca99e249 Bump version to 7.7.6 2017-11-15 15:21:25 +01:00
Sebastiaan Janssen 837bb83d48 Merge remote-tracking branch 'origin/dev-v7.6' into dev-v7 2017-11-15 14:40:19 +01:00
Sebastiaan Janssen 054ac78970 Revert "Position changed from "target" to "center""
This reverts commit c1769aa299.
2017-11-15 14:39:09 +01:00
Robert 5982a868ea Added custom RollingFileAppender and changed rollingStyle to "size"
OpenFile method has been overiden, this means that everytime a log will be opened, it will check the last access time of all existing logs, and delete the ones that haven't been accessed in more than 1 month.

Changing the rollingStyle to "size" will make sure that logs will roll once the maximumFileSize reaches its set limit.
2017-11-14 12:01:11 +01:00
Sebastiaan Janssen 69a42e26a9 Merge remote-tracking branch 'origin/dev-v7.6' into dev-v7 2017-11-14 11:42:00 +01:00
Sebastiaan Janssen d9ed420ed4 U4-10492 Users failing to list with MySQL 2017-11-14 11:38:45 +01:00
Sebastiaan Janssen 2b3397120f Disambiguate events by explicitly naming them 2017-11-14 11:23:48 +01:00
Sebastiaan Janssen 1f41aa7d81 Merge branch 'dev-v7.6' into dev-v7
# Conflicts:
#	src/SolutionInfo.cs
#	src/Umbraco.Core/Configuration/UmbracoVersion.cs
#	src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
#	src/Umbraco.Web.UI/packages.config
2017-11-14 07:19:08 +01:00
Sebastiaan Janssen dad77fc506 Bump version to 7.7.5 2017-11-14 07:17:19 +01:00
Sebastiaan Janssen 350f5c88c7 Bump version to 7.6.12 2017-11-14 07:16:14 +01:00
Stephan 928c0dc535 Merge pull request #2314 from umbraco/temp-U4-10646
U4-10646 Sorting nodes in edge cases can lead to blanking out of property data
2017-11-13 17:33:27 +01:00
Sebastiaan Janssen cc7a28db65 Update to latest ImageProcessor 2017-11-13 15:39:29 +01:00
Sebastiaan Janssen 065e764957 Update to latest Examine 2017-11-13 15:39:28 +01:00
Sebastiaan Janssen 000ba73887 Merge branch 'dev-v7.6' into dev-v7
# Conflicts:
#	build/NuSpecs/UmbracoCms.Core.nuspec
#	src/Umbraco.Tests/Umbraco.Tests.csproj
#	src/Umbraco.Tests/packages.config
#	src/Umbraco.Web.UI/Umbraco.Web.UI.csproj
#	src/Umbraco.Web.UI/packages.config
#	src/Umbraco.Web/Umbraco.Web.csproj
#	src/Umbraco.Web/packages.config
#	src/UmbracoExamine/UmbracoExamine.csproj
#	src/UmbracoExamine/packages.config
#	src/umbraco.MacroEngines/packages.config
#	src/umbraco.MacroEngines/umbraco.MacroEngines.csproj
2017-11-13 15:38:59 +01:00
Sebastiaan Janssen 08b81d991b Update to latest ImageProcessor 2017-11-13 15:33:54 +01:00
Sebastiaan Janssen 4937f87c0d Update to latest Examine 2017-11-13 15:27:15 +01:00
Claus dc67d82671 adding trim. 2017-11-08 12:08:30 +01:00
Claus c7d9683fc4 Merge pull request #2277 from umbraco/temp-U4-10589
U4-10589 Login should be sanitized and/or cause validation errors if trying to save with
2017-11-08 12:07:34 +01:00
Mads Rasmussen ed7675bdcd Merge pull request #1584 from readingdancer/U4-9144
Style changes to the developer dashboard area.
2017-11-08 11:49:48 +01:00
Mads Rasmussen 3c7c6b4ad7 Update thumbnails.less
Use new color variables
2017-11-08 11:38:32 +01:00
Mads Rasmussen 838d7975c9 Update healthcheck.less
prevent UI from "jumping" on hover
2017-11-08 11:36:23 +01:00
Mads Rasmussen 5af9712d51 Merge branch 'dev-v7' into U4-9144 2017-11-08 10:43:58 +01:00
Marcin Zajkowski e14aba3875 More no-dirty-checks and code polishment 2017-11-07 23:21:50 +01:00
Sebastiaan Janssen 579c572dd8 Oops, missed that I was passing a string array into the int array param 2017-11-07 18:36:37 +01:00
Sebastiaan Janssen bbf4c18825 U4-10646 Sorting nodes in edge cases can lead to blanking out of property data 2017-11-07 17:12:04 +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
Robert 73b2d31298 Moved username trimming to service level, also added email trimming 2017-11-01 13:08:17 +01:00
Robert 8676a99b3a Trimming login input on the server-side as well 2017-11-01 09:00:05 +01:00
Robert 0b2cfe956d Triming login field to avoid validation errors 2017-10-31 15:19:06 +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
Chris Houston a4f83e0125 Style changes to the developer dashboard area. 2016-11-03 14:41:41 +00:00
Shane Marsden 59b8b397b7 Renamed SerializeToCropDataSet to DeserializeToCropDataSet 2016-11-03 11:33:00 +00:00
129 changed files with 1995 additions and 1143 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
}
}
+3 -3
View File
@@ -29,17 +29,17 @@
<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.85, 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)" />
<!-- Markdown can not be updated due to: https://github.com/hey-red/markdownsharp/issues/71#issuecomment-233585487 -->
<dependency id="Markdown" version="[1.14.7, 2.0.0)" />
<dependency id="System.Threading.Tasks.Dataflow" version="[4.7.0, 5.0.0)" />
<dependency id="System.Threading.Tasks.Dataflow" version="[4.7.0, 5.0.0)" />
</dependencies>
</metadata>
<files>
+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.4")]
[assembly: AssemblyInformationalVersion("7.7.4")]
[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.4");
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;
}
}
@@ -0,0 +1,95 @@
using System;
using System.IO;
using log4net.Appender;
using log4net.Util;
namespace Umbraco.Core.Logging
{
/// <summary>
/// This class will do the exact same thing as the RollingFileAppender that comes from log4net
/// With the extension, that it is able to do automatic cleanup of the logfiles in the directory where logging happens
///
/// By specifying the properties MaxLogFileDays and BaseFilePattern, the files will automaticly get deleted when
/// the logger is configured(typically when the app starts). To utilize this appender swap out the type of the rollingFile appender
/// that ships with Umbraco, to be Umbraco.Core.Logging.RollingFileCleanupAppender, and add the maxLogFileDays and baseFilePattern elements
/// to the configuration i.e.:
///
/// <example>
/// <appender name="rollingFile" type="Log4netAwesomeness.CustomRollingFileAppender, Log4netAwesomeness">
/// <file type="log4net.Util.PatternString" value="App_Data\Logs\UmbracoTraceLog.%property{log4net:HostName}.txt" />
/// <lockingModel type="log4net.Appender.FileAppender+MinimalLock" />
/// <appendToFile value="true" />
/// <rollingStyle value="Date" />
/// <maximumFileSize value="5MB" />
/// <maxLogFileDays value="5"/>
/// <basefilePattern value="UmbracoTraceLog.*.txt.*"/>
/// <layout type="log4net.Layout.PatternLayout">
/// <conversionPattern value=" %date [P%property{processId}/D%property{appDomainId}/T%thread] %-5level %logger - %message%newline" />
/// </layout>
/// <layout type="log4net.Layout.PatternLayout">
/// <conversionPattern value=" %date [P%property{processId}/D%property{appDomainId}/T%thread] %-5level %logger - %message%newline" />
/// </layout>
/// <encoding value="utf-8" />
/// </appender>
/// </example>
/// </summary>
public class RollingFileCleanupAppender : RollingFileAppender
{
public int MaxLogFileDays { get; set; }
public string BaseFilePattern { get; set; }
/// <summary>
/// This override will delete logs older than the specified amount of days
/// </summary>
/// <param name="fileName"></param>
/// <param name="append"></param>
protected override void OpenFile(string fileName, bool append)
{
bool cleanup = true;
// Validate settings and input
if (MaxLogFileDays <= 0)
{
LogLog.Warn(typeof(RollingFileCleanupAppender), "Parameter 'MaxLogFileDays' needs to be a positive integer, aborting cleanup");
cleanup = false;
}
if (string.IsNullOrWhiteSpace(BaseFilePattern))
{
LogLog.Warn(typeof(RollingFileCleanupAppender), "Parameter 'BaseFilePattern' is empty, aborting cleanup");
cleanup = false;
}
// grab the directory we are logging to, as this is were we will search for older logfiles
var logFolder = Path.GetDirectoryName(fileName);
if (Directory.Exists(logFolder) == false)
{
LogLog.Warn(typeof(RollingFileCleanupAppender), string.Format("Directory '{0}' for logfiles does not exist, aborting cleanup", logFolder));
cleanup = false;
}
// If everything is validated, we can do the actual cleanup
if (cleanup)
{
Cleanup(logFolder);
}
base.OpenFile(fileName, append);
}
private void Cleanup(string directoryPath)
{
// only take files that matches the pattern we are using i.e. UmbracoTraceLog.*.txt.*
string[] logFiles = Directory.GetFiles(directoryPath, BaseFilePattern);
LogLog.Debug(typeof(RollingFileCleanupAppender), string.Format("Found {0} files that matches the baseFilePattern: '{1}'", logFiles.Length, BaseFilePattern));
foreach (var logFile in logFiles)
{
DateTime lastAccessTime = System.IO.File.GetLastWriteTimeUtc(logFile);
// take the value from the config file
if (lastAccessTime < DateTime.Now.AddDays(-MaxLogFileDays))
{
LogLog.Debug(typeof(RollingFileCleanupAppender), string.Format("Deleting file {0} as its lastAccessTime is older than {1} days speficied by MaxLogFileDays", logFile, MaxLogFileDays));
base.DeleteFile(logFile);
}
}
}
}
}
+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;
}
}
@@ -188,7 +188,7 @@ namespace Umbraco.Core.Models
Language,
/// <summary>
/// Document
/// Document Blueprint
/// </summary>
[UmbracoObjectType(Constants.ObjectTypes.DocumentBlueprint, typeof(IContent))]
[FriendlyName("DocumentBlueprint")]
@@ -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;
}
}
}
@@ -191,11 +191,11 @@ ORDER BY colName";
return new Dictionary<UserState, int>
{
{UserState.All, result[0].num},
{UserState.Active, result[1].num},
{UserState.Disabled, result[2].num},
{UserState.LockedOut, result[3].num},
{UserState.Invited, result[4].num}
{UserState.All, (int)result[0].num},
{UserState.Active, (int)result[1].num},
{UserState.Disabled, (int)result[2].num},
{UserState.LockedOut, (int)result[3].num},
{UserState.Invited, (int)result[4].num}
};
}
@@ -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();
+92 -3
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;
}
@@ -2009,6 +2008,96 @@ namespace Umbraco.Core.Services
return true;
}
/// <summary>
/// Sorts a collection of <see cref="IContent"/> objects by updating the SortOrder according
/// to the ordering of node Ids passed in.
/// </summary>
/// <remarks>
/// Using this method will ensure that the Published-state is maintained upon sorting
/// so the cache is updated accordingly - as needed.
/// </remarks>
/// <param name="ids"></param>
/// <param name="userId"></param>
/// <param name="raiseEvents"></param>
/// <returns>True if sorting succeeded, otherwise False</returns>
public bool Sort(int[] ids, int userId = 0, bool raiseEvents = true)
{
var shouldBePublished = new List<IContent>();
var shouldBeSaved = new List<IContent>();
using (new WriteLock(Locker))
{
var allContent = GetByIds(ids).ToDictionary(x => x.Id, x => x);
var items = ids.Select(x => allContent[x]);
using (var uow = UowProvider.GetUnitOfWork())
{
var asArray = items.ToArray();
var saveEventArgs = new SaveEventArgs<IContent>(asArray);
if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, saveEventArgs, "Saving"))
{
uow.Commit();
return false;
}
var repository = RepositoryFactory.CreateContentRepository(uow);
var i = 0;
foreach (var content in asArray)
{
//If the current sort order equals that of the content
//we don't need to update it, so just increment the sort order
//and continue.
if (content.SortOrder == i)
{
i++;
continue;
}
content.SortOrder = i;
content.WriterId = userId;
i++;
if (content.Published)
{
//TODO: This should not be an inner operation, but if we do this, it cannot raise events and cannot be cancellable!
var published = _publishingStrategy.Publish(uow, content, userId).Success;
shouldBePublished.Add(content);
}
else
shouldBeSaved.Add(content);
repository.AddOrUpdate(content);
//add or update a preview
repository.AddOrUpdatePreviewXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, _userService, c));
}
foreach (var content in shouldBePublished)
{
//Create and Save ContentXml DTO
repository.AddOrUpdateContentXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, _userService, c));
}
if (raiseEvents)
{
saveEventArgs.CanCancel = false;
uow.Events.Dispatch(Saved, this, saveEventArgs, "Saved");
}
if (shouldBePublished.Any())
{
//TODO: This should not be an inner operation, but if we do this, it cannot raise events and cannot be cancellable!
_publishingStrategy.PublishingFinalized(uow, shouldBePublished, false);
}
Audit(uow, AuditType.Sort, "Sorting content performed by user", userId, 0);
uow.Commit();
}
}
return true;
}
public IEnumerable<IContent> GetBlueprintsForContentTypes(params int[] documentTypeIds)
{
using (var uow = UowProvider.GetUnitOfWork(readOnly: true))
@@ -2749,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 ?
+15 -1
View File
@@ -642,7 +642,21 @@ namespace Umbraco.Core.Services
/// <param name="userId"></param>
/// <param name="raiseEvents"></param>
/// <returns>True if sorting succeeded, otherwise False</returns>
bool Sort(IEnumerable<IContent> items, int userId = 0, bool raiseEvents = true);
bool Sort(IEnumerable<IContent> items, int userId = 0, bool raiseEvents = true);
/// <summary>
/// Sorts a collection of <see cref="IContent"/> objects by updating the SortOrder according
/// to the ordering of node Ids passed in.
/// </summary>
/// <remarks>
/// Using this method will ensure that the Published-state is maintained upon sorting
/// so the cache is updated accordingly - as needed.
/// </remarks>
/// <param name="ids"></param>
/// <param name="userId"></param>
/// <param name="raiseEvents"></param>
/// <returns>True if sorting succeeded, otherwise False</returns>
bool Sort(int[] ids, int userId = 0, bool raiseEvents = true);
/// <summary>
/// Gets the parent of the current content as an <see cref="IContent"/> item.
+6 -2
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);
@@ -986,7 +986,11 @@ namespace Umbraco.Core.Services
/// <param name="raiseEvents">Optional parameter to raise events.
/// Default is <c>True</c> otherwise set to <c>False</c> to not raise events</param>
public void Save(IMember entity, bool raiseEvents = true)
{
{
//trimming username and email to make sure we have no trailing space
entity.Username = entity.Username.Trim();
entity.Email = entity.Email.Trim();
using (var uow = UowProvider.GetUnitOfWork())
{
var saveEventArgs = new SaveEventArgs<IMember>(entity);
@@ -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('/');
}
}
}
+4
View File
@@ -117,6 +117,8 @@ namespace Umbraco.Core
{
case UmbracoObjectTypes.Document:
return Document;
case UmbracoObjectTypes.DocumentBlueprint:
return DocumentBluePrint;
case UmbracoObjectTypes.Media:
return Media;
case UmbracoObjectTypes.Member:
@@ -161,6 +163,8 @@ namespace Umbraco.Core
{
case Document:
return UmbracoObjectTypes.Document;
case DocumentBluePrint:
return UmbracoObjectTypes.DocumentBlueprint;
case Media:
return UmbracoObjectTypes.Media;
case Member:
+4 -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" />
@@ -366,6 +357,7 @@
<Compile Include="HashGenerator.cs" />
<Compile Include="IEmailSender.cs" />
<Compile Include="IHttpContextAccessor.cs" />
<Compile Include="Logging\RollingFileCleanupAppender.cs" />
<Compile Include="Models\EntityBase\EntityPath.cs" />
<Compile Include="Models\EntityBase\IDeletableEntity.cs" />
<Compile Include="Models\IUserControl.cs" />
+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.85.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.85\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.85" 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" />
@@ -31,15 +31,17 @@
display: block;
padding: 4px;
line-height: @baseLineHeight;
border: 1px solid #ddd;
border: 1px solid @gray-8;
.border-radius(@baseBorderRadius);
.box-shadow(0 1px 3px rgba(0,0,0,.055));
.transition(all .2s ease-in-out);
}
// Add a hover/focus state for linked versions only
a.thumbnail:hover,
a.thumbnail:focus {
border-color: @linkColor;
// Add a hover/focus state for linked versions only.
a.thumbnail:hover,
a.thumbnail:focus,
a div.thumbnail:hover,
a div.thumbnail:focus {
border-color: @turquoise;
.box-shadow(0 1px 4px rgba(0,105,214,.25));
}
+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;
});
});
}
};
}
@@ -242,8 +242,8 @@
var propGroups = _.find(genericTab.properties, function (item) {
return item.alias === "_umb_membergroup";
});
saveModel.email = propEmail.value;
saveModel.username = propLogin.value;
saveModel.email = propEmail.value.trim();
saveModel.username = propLogin.value.trim();
saveModel.password = this.formatChangePasswordModel(propPass.value);
@@ -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;
@@ -29,12 +29,12 @@
padding: 15px 10px;
box-sizing: border-box;
text-align: center;
border: 2px solid transparent;
border: 1px solid @gray-8;
height: 100%;
}
.umb-healthcheck-group:hover {
border: 2px solid @turquoise;
border: 1px solid @turquoise;
cursor: pointer;
}
@@ -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>
@@ -2,7 +2,7 @@
<umb-control-group label="@general_url">
<input id="url" class="umb-editor input-block-level" type="text" style="margin-bottom: 10px;" ng-model="model.embed.url" ng-keyup="$event.keyCode == 13 ? vm.showPreview() : null" required />
<input type="button" ng-click="vm.showPreview()" class="btn" localize="value" value="@general_retrieve" />
<input type="button" ng-click="vm.showPreview()" class="btn" value="@general_retrieve" localize="value" />
</umb-control-group>
<umb-control-group>
@@ -12,15 +12,15 @@
<div ng-show="model.embed.supportsDimensions">
<umb-control-group label="@general_width">
<input type="text" ng-model="model.embed.width" on-blur="vm.changeSize('width')" />
<input type="number" pattern="[0-9]*" min="0" ng-model="model.embed.width" on-blur="vm.changeSize('width')" />
</umb-control-group>
<umb-control-group label="@general_height">
<input type="text" ng-model="model.embed.height" on-blur="vm.changeSize('height')" />
<input type="number" pattern="[0-9]*" min="0" ng-model="model.embed.height" on-blur="vm.changeSize('height')" />
</umb-control-group>
<umb-control-group label="@general_constrain">
<input id="constrain" type="checkbox" ng-model="model.embed.constrain" />
<input id="constrain" type="checkbox" ng-model="model.embed.constrain" />
</umb-control-group>
</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,5 +1,5 @@
<h3>Hours of Umbraco training videos are only a click away</h3>
<p>Want to master Umbraco? Spend a couple of minutes learning some best practices by watching one of these videos about using Umbraco. And visit <a class="btn-link -underline" href="http://umbraco.tv" target="_blank">umbraco.tv</a> for even more Umbraco videos</p>
<p>Want to master Umbraco? Spend a couple of minutes learning some best practices by watching one of these videos about using Umbraco, then visit <a class="btn-link -underline" href="http://umbraco.tv" target="_blank">umbraco.tv</a> for even more Umbraco videos.</p>
<div class="row-fluid"
ng-init="init('http://umbraco.tv/videos/developer/chapterrss?sort=no')"
@@ -7,14 +7,12 @@
<ul class="thumbnails" >
<li class="span2" ng-repeat="video in videos">
<div class="thumbnail" style="margin-right: 20px; padding: 20px;">
<a class="btn-link -underline" target="_blank" href="{{video.link}}" title="{{video.title}}">
<img ng-src="{{video.thumbnail}}" alt="{{video.title}}">
</a>
<a target="_blank" href="{{video.link}}" title="{{video.title}}">
<div style="font-weight: bold; text-align: center; margin: 20px 0 0;">{{video.title}}</div>
</a>
</div>
<a class="btn-link" target="_blank" href="{{video.link}}" title="{{video.title}}">
<div class="thumbnail" style="margin-right: 20px; padding: 20px;">
<img ng-src="{{video.thumbnail}}" alt="{{video.title}}">
<div style="font-weight: bold; text-align: center; margin: 20px 0 0;">{{video.title}}</div>
</div>
</a>
</li>
</ul>
</div>
@@ -36,7 +36,7 @@
<umb-overlay
ng-if="vm.childNodeSelectorOverlay.show"
model="vm.childNodeSelectorOverlay"
position="center"
position="target"
view="vm.childNodeSelectorOverlay.view">
</umb-overlay>
@@ -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) {
@@ -299,7 +299,7 @@
ng-if="editorOverlay.show"
model="editorOverlay"
view="editorOverlay.view"
position="center">
position="target">
</umb-overlay>
<umb-overlay
@@ -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.85.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Examine.0.1.85\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>7740</DevelopmentServerPort>
<DevelopmentServerPort>7790</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:7740</IISUrl>
<IISUrl>http://localhost:7790</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
+12 -1
View File
@@ -422,7 +422,7 @@
<key alias="showPageOnSend">Hvilken side skal vises etter at skjemaet er sendt</key>
<key alias="size">Størrelse</key>
<key alias="sort">Sorter</key>
<key alias="submit">Submit</key> <!-- TODO: Translate this -->
<key alias="submit">Send</key>
<key alias="type">Type</key>
<key alias="typeToSearch">Søk...</key>
<key alias="up">Opp</key>
@@ -439,6 +439,17 @@
<key alias="yes">Ja</key>
<key alias="folder">Mappe</key>
<key alias="searchResults">Søkeresultater</key>
<key alias="reorder">Sorter</key>
<key alias="reorderDone">Avslutt sortering</key>
<key alias="preview">Eksempel</key>
<key alias="changePassword">Bytt passord</key>
<key alias="to">til</key>
<key alias="listView">Listevisning</key>
<key alias="saving">Lagrer...</key>
<key alias="current">nåværende</key>
<key alias="embed">Innbygging</key>
<key alias="retrieve">Hent</key>
<key alias="selected">valgt</key>
</area>
<area alias="graphicheadline">
<key alias="backgroundcolor">Bakgrunnsfarge</key>
@@ -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.85" 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>
@@ -586,7 +586,6 @@
<key alias="sort">Sortér</key>
<key alias="status">Status</key>
<key alias="submit">Indsend</key>
<!-- TODO: Translate this -->
<key alias="type">Type</key>
<key alias="typeToSearch">Skriv for at søge...</key>
<key alias="up">Op</key>
@@ -612,6 +611,7 @@
<key alias="saving">Gemmer...</key>
<key alias="current">nuværende</key>
<key alias="embed">Indlejring</key>
<key alias="retrieve">Hent</key>
<key alias="selected">valgt</key>
</area>
@@ -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>
@@ -637,6 +637,7 @@
<key alias="saving">Saving...</key>
<key alias="current">current</key>
<key alias="embed">Embed</key>
<key alias="retrieve">Retrieve</key>
<key alias="selected">selected</key>
</area>
@@ -637,6 +637,7 @@
<key alias="saving">Saving...</key>
<key alias="current">current</key>
<key alias="embed">Embed</key>
<key alias="retrieve">Retrieve</key>
<key alias="selected">selected</key>
</area>
<area alias="colors">
@@ -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>
+12 -3
View File
@@ -411,7 +411,7 @@
<key alias="showPageOnSend">Vilken sida skall visas när formuläret är skickat</key>
<key alias="size">Storlek</key>
<key alias="sort">Sortera</key>
<key alias="submit">Submit</key> <!-- TODO: Translate this -->
<key alias="submit">Skicka</key>
<key alias="type">Skriv</key>
<key alias="typeToSearch">Skriv för att söka...</key>
<key alias="up">Upp</key>
@@ -426,8 +426,17 @@
<key alias="width">Bredd</key>
<key alias="view">Titta på</key>
<key alias="yes">Ja</key>
<key alias="reorder">Reorder</key>
<key alias="reorderDone">I am done reordering</key>
<key alias="reorder">Sortera</key>
<key alias="reorderDone">Avsluta sortering</key>
<key alias="preview">Förhandsvisning</key>
<key alias="changePassword">Ändra lösenord</key>
<key alias="to">till</key>
<key alias="listView">Listvy</key>
<key alias="saving">Sparar...</key>
<key alias="current">nuvarande</key>
<key alias="embed">Inbäddning</key>
<key alias="retrieve">Hämta</key>
<key alias="selected">valgt</key>
</area>
<area alias="graphicheadline">
<key alias="backgroundcolor">Bakgrundsfärg</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)
+3 -4
View File
@@ -532,6 +532,7 @@ namespace Umbraco.Web.Editors
/// <returns></returns>
[FileUploadCleanupFilter]
[ContentPostValidate]
[OutgoingEditorModelEvent]
public ContentItemDisplay PostSave(
[ModelBinder(typeof(ContentItemBinder))]
ContentItemSave contentItem)
@@ -792,11 +793,8 @@ namespace Umbraco.Web.Editors
{
var contentService = Services.ContentService;
// content service GetByIds does order the content items based on the order of Ids passed in
var content = contentService.GetByIds(sorted.IdSortOrder);
// Save content with new sort order and update content xml in db accordingly
if (contentService.Sort(content) == false)
if (contentService.Sort(sorted.IdSortOrder) == false)
{
LogHelper.Warn<ContentController>("Content sorting failed, this was probably caused by an event being cancelled");
return Request.CreateValidationErrorResponse("Content sorting failed, this was probably caused by an event being cancelled");
@@ -850,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)
+3 -2
View File
@@ -256,6 +256,7 @@ namespace Umbraco.Web.Editors
/// </summary>
/// <returns></returns>
[FileUploadCleanupFilter]
[OutgoingEditorModelEvent]
public MemberDisplay PostSave(
[ModelBinder(typeof(MemberBinder))]
MemberSave contentItem)
@@ -393,7 +394,7 @@ namespace Umbraco.Web.Editors
UpdateName(contentItem);
//map the custom properties - this will already be set for new entities in our member binder
contentItem.PersistedContent.Email = contentItem.Email;
contentItem.PersistedContent.Email = contentItem.Email;
contentItem.PersistedContent.Username = contentItem.Username;
//use the base method to map the rest of the properties
@@ -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;
}
@@ -86,7 +86,16 @@ namespace Umbraco.Web.Scheduling
finally
{
if (tempContext != null)
{
// because we created an http context and assigned it to UmbracoContext,
// the batched messenger does batch instructions, but since there is no
// request, we need to explicitely tell it to flush the batch of instrs.
var batchedMessenger = ServerMessengerResolver.Current.Messenger as BatchedDatabaseServerMessenger;
if (batchedMessenger != null)
batchedMessenger.FlushBatch();
tempContext.Dispose(); // nulls the ThreadStatic context
}
}
return true; // repeat

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