Compare commits

...

129 Commits

Author SHA1 Message Date
Sebastiaan Janssen f100d82e2c Bump version 2015-06-03 14:03:04 +02:00
Shannon 60ce993c09 Fixes change password dashboard to have autocomplete = off and to not show plain text passwords. 2015-06-03 12:20:20 +02:00
Shannon c07021d2a0 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-06-02 22:41:06 +02:00
Shannon 744ee39904 Changes the IIS header removal to BeginRequest instead of PreSendRequestHeaders since that is not a recommended practice 2015-06-02 22:40:57 +02:00
Shannon Deminick d669bf64c0 Merge pull request #698 from Nicholas-Westby/dev-v7
Fixes U4-6665 (Localization Bug)
2015-06-02 21:29:16 +02:00
Shannon ff277cd99c Fixes: U4-6654 NullReferenceException downloading translation xml 2015-06-02 21:13:29 +02:00
Shannon Deminick 30cd303a13 Merge pull request #697 from wp-manaosoftware/dev-7-angularthrowexception
U4-6621 - fix issue AngularJS throws exception that locationEvent was…
2015-06-02 21:04:08 +02:00
Shannon 60ce987507 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-06-02 20:53:55 +02:00
Shannon a231899052 Fixes: U4-6635 with label overlaying the folder icon when the folder icons are small. 2015-06-02 20:53:46 +02:00
Shannon Deminick 7ddcccb0c5 Merge pull request #685 from gavinfaux/U4-6618
Back office insecure content warning loading Google Web Fonts when running over HTTPS
2015-06-02 20:16:12 +02:00
Nicholas-Westby db824d8daf Fixes U4-6665 (Localization Bug)
Fix for localization not working some of the time: http://issues.umbraco.org/issue/U4-6665
2015-05-29 21:02:07 -07:00
Warm a1a30240f6 U4-6621 - fix issue AngularJS throws exception that locationEvent was not defined when leaved a page without saving 2015-05-29 10:40:48 +07:00
Shannon Deminick 7c4a189aa3 Merge pull request #696 from tomfulton/fix/u4-6655
Fix U4-6655:  RTE Macro not rendering in backoffice when "macroAlias" is not first attribute
2015-05-26 08:01:40 +10:00
Tom Fulton 4ec66bc868 Fix U4-6655: RTE Macro not rendering in backoffice when "macroAlias" is not first attribute
Loosens UMBRACO_MACRO regex parsing to fix, add tests
2015-05-22 20:40:30 -06:00
Stephan fa8fe8ec66 BackgroundTaskRunner - few fixes 2015-05-21 21:54:30 +02:00
Stephan a76ba9a0a7 BackgroundTaskRunner - more fixes 2015-05-21 19:37:22 +02:00
Stephan b804ff6107 Explicit exception on cache reentry 2015-05-21 16:09:20 +02:00
Shannon 72046a6ab9 removes test - expected behavior 2015-05-21 16:36:09 +10:00
Shannon ea2303c327 commits cache tests with recursive key lookup 2015-05-21 16:13:58 +10:00
Shannon 4c4117a052 Fixes BackgroundTaskRunner - moves the OnStopped call to where it should be. Un-ignores tests - these need to execute and cannot be ignored. They are not long running but if there are issues then they will timeout - DO NOT IGNORE. if the build server has issues with these then it's our logic that is at fault. 2015-05-21 13:05:58 +10:00
Stephan 521b8076d2 U4-6638 - bugfix BackgroundTaskRunner 2015-05-20 20:56:05 +02:00
Stephan 1def88d764 U4-6626 2015-05-20 18:26:08 +02:00
Stephan 910c349f7c Bugfix StyleSheet concatenation causing LOH GC issues 2015-05-20 17:00:32 +02:00
Shannon 6cfb5bc678 Have made the buttons always left aligned with the editing section, seems better since it's consistent on all screens and less right hand motion to click a button 2015-05-20 16:13:36 +10:00
Shannon a3b5996372 Fixes save/publish button placement on small screens 2015-05-20 16:01:44 +10:00
Shannon 31b4560daa Merge branch 'sebastian-claesson-dev-v7' into dev-v7 2015-05-20 15:08:45 +10:00
Shannon 2f2dd9c9b6 Merge branch 'dev-v7' of https://github.com/sebastian-claesson/Umbraco-CMS into sebastian-claesson-dev-v7 2015-05-20 15:07:48 +10:00
Shannon Deminick 02599e1254 Merge pull request #694 from Alain-es/datepicker-custom-format
Datepicker custom format
2015-05-20 14:48:36 +10:00
Stephan ac7ff31a67 U4-6626 - XmlCache, bugfix locks 2015-05-19 20:08:52 +02:00
Stephan 009f071f48 XmlCache - comments 2015-05-19 14:04:32 +02:00
Stephan e0ecb3291d XmlCache - bugfix running with file cache disabled 2015-05-19 10:20:36 +02:00
Stephan dbaf7c0190 U4-6597 - fix issue with caches that would cache exceptions 2015-05-19 09:24:38 +02:00
Stephan 16e06b6d4d Revert 444a028, 0e5a469 and 9d8f33e 2015-05-19 09:24:25 +02:00
Shannon 444a028e30 adds tests for caching exceptions and only caching one time and fixes HttpRequestCacheProvider to work with them. 2015-05-19 15:57:11 +10:00
Shannon 0e5a469577 Fixes: U4-6597 Umbraco fails to reconnect to a SQL Server if it started up when SQL server was offline - however this requires some review. 2015-05-19 14:29:25 +10:00
Shannon 9d8f33e98e Fixes: U4-6597 Umbraco fails to reconnect to a SQL Server if it started up when SQL server was offline - however this requires some review. 2015-05-19 14:25:31 +10:00
Alain-es 2abb3177af Datepicker custom format 2015-05-18 15:57:27 +01:00
Alain-es 43f99e11a5 Datepicker custom format 2015-05-18 15:54:50 +01:00
Sebastian Claesson Hoffback d1d9878ab6 Fix content-edit-view on mobile devices
The content editing view did not work at all on small screens. The label
took to much space, leaving the controller with almost none. Now the
label and the controller get its own row on smaller screens. Much
cleaner look and you can acctually edit a page on a small screen. Note:
Grids still don't work well.
2015-05-18 13:59:42 +02:00
Sebastian Claesson Hoffback e9753c72a7 Merge pull request #1 from umbraco/dev-v7
Merge Shannons changes
2015-05-18 12:13:33 +02:00
Shannon 3b791c75f6 Fixes: U4-5020 Login view on mobile screen is too big 2015-05-18 20:09:03 +10:00
Shannon Deminick 35cb4d5690 Merge pull request #693 from sebastian-claesson/dev-v7
Fixed login-view on mobile devices
2015-05-18 19:37:33 +10:00
Sebastian Claesson Hoffback adde7c2f50 Fixed login-view on mobile devices
On smaller screens the login-view was too far to the right.

Related issue: http://issues.umbraco.org/issue/U4-5020
2015-05-18 11:34:13 +02:00
Shannon Deminick 62943d391f Merge pull request #692 from bjarnef/dev-v7-U4-6629
Fix changes in user section labels
2015-05-18 13:47:13 +10:00
Shannon Deminick 0942eb839d Merge pull request #691 from Vrijdagonline/dev-v7
Updating Dutch Translations
2015-05-18 11:38:29 +10:00
bjarnef 21a4dfe33e Fix changes in user section labels
Fixed translation in da.xml according to change in en.xml  from 7.2.4 to
7.2.5
2015-05-17 22:16:39 +02:00
Stephan 8121fc42e5 U4-6626 - fix log level 2015-05-17 21:47:31 +02:00
Stephan c356ed1df8 Logger - add AppDomain.Id to log 2015-05-17 18:48:26 +02:00
Stephan 92f56ccedd U4-6626 - XmlCache, bugfix locks 2015-05-17 18:48:25 +02:00
Stephan 7cbe2410e4 Do not flood the log when installing a new version 2015-05-17 18:48:21 +02:00
Arjan Woldring 1dda3ce45d Updating Dutch Translations
Missing keys added, deleted keys deleted, reorderded some keys based on
the english one and corrected couple of wrong translations.
2015-05-16 19:06:04 +02:00
Shannon Deminick 1e29a4a8ca Merge pull request #688 from sebastian-claesson/dev-v7
Swedish was using the wrong format for variables
2015-05-15 15:46:17 +10:00
Sebastian Claesson Hoffback 01de0bd6a1 Swedish was using the wrong format for variables
The swedish translation was using {0} instead of %0%. Leading to alot of
texts being weirdly formated.
2015-05-15 07:22:11 +02:00
Shannon Deminick 4d0d29c004 Merge pull request #686 from Aaen/dev-v7
Change translation for add row for fix issue U4-6564
2015-05-14 07:57:12 +10:00
Shannon Deminick 741c2bb085 Merge pull request #687 from sebastian-claesson/dev-v7
Swedish translation for the grid-editor
2015-05-14 07:54:16 +10:00
Sebastian Claesson Hoffback 2c809857af Swedish translation for the grid-editor
Swedish translation was completly missing for the grid-editor
2015-05-13 14:59:27 +02:00
Dennis Aaen 236d6ee302 Change translation for add row for fix issue U4-6564 2015-05-13 13:27:37 +02:00
Gavin Faux 3094dea5d4 Back office insecure content warning loading Google Web Fonts when running over HTTPS
Amend to use https://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js
2015-05-13 09:45:20 +01:00
Shannon f829b0b16c Fixes text not overlayed on top of icon for folders in folder browser 2015-05-13 10:56:25 +10:00
Sebastiaan Janssen a42526b890 This file just keeps being marked as "changed" by git, committing it so I don't have to discard changes all the time 2015-05-12 11:15:02 +02:00
Shannon 3a36513307 Fixes: U4-6609 SQL Exception when trying to delete a template that isn't assigned to any doc type 2015-05-12 17:59:06 +10:00
Shannon 0548a32405 adds some simple docs to umb settings 2015-05-12 17:32:26 +10:00
Shannon 433950dd59 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2015-05-12 12:39:57 +10:00
Shannon ad8926668e Fixes: U4-6588 UmbracoSettings Error404 support Guids and Xpath - To achieve this, had to create an Id -> Key and Key -> Id method on EntityService including a cache for it which means updating all relavent cache refreshers to clear this cache when things are removed. Moved the logic for parsing an Umbraco XPath query (with tokens) to a stand-alone testable class (though haven't written tests), move the logic for looking up a not found page to the NotFoundHandlerHelper (instead of legacy 'library'). Fixes the $root query, since I don't think that ever worked. I've tested $root now for both MNTP and for the not found handler and it works. 2015-05-12 12:39:46 +10:00
Sebastiaan Janssen 4ebc0fe4cf U4-6383 Download all translation tasks as XML Error
#U4-6383 Fixed Due in version 7.2.5
2015-05-11 21:33:52 +02:00
Shannon 1b1455067e Fixes: U4-6606 maxInvalidPasswordAttempts work for the UsersMembershipProvider doesn't work any more 2015-05-11 19:44:59 +10:00
Shannon 795de94a5f Fixes: U4-6102 After renaming Grid row configurations all data is lost for renames. So now we have warnings for both deletes and renames. 2015-05-11 18:46:26 +10:00
Shannon d6699ab3b3 Fixes: U4-6102 After renaming Grid row configurations all data is lost, also ensures that all events are unsubscribed on destroy 2015-05-11 16:18:35 +10:00
Shannon d94b334375 Moves login logging to the provider level 2015-05-11 12:22:56 +10:00
Shannon a4a49b1466 Revert "Fixes MVC 4.0.0.1 problem once and for all." - All MVC ref's are 4.0.0.0, no web config transforms (also there was never a 4.0.0.1 version of System.Net.Http). Everything works on my machine now, even with 4.0.0.1 installed in the GAC. 2015-05-11 11:45:13 +10:00
Shannon Deminick 2c92cd9ca9 Merge pull request #683 from umbraco/U4-6603
U4-6603 Log failed login attempts
2015-05-11 09:07:24 +10:00
Sebastiaan Janssen c34605937c U4-6603 Log failed login attempts
#U4-6603 Fixed
2015-05-10 17:47:32 +02:00
Shannon Deminick 2a9d3df822 Merge pull request #682 from hfloyd/dev-v7
English Language file updates (Umbraco/config/lang)
2015-05-08 08:48:38 +10:00
Heather Floyd 3b849987bf Small fixes to 'en' language file. Update of 'en-us' language file to match 'en' language file. 2015-05-07 16:41:12 -04:00
Shannon 8443513b2b fixes sorting with multipletextbox 2015-05-07 13:39:28 +10:00
Shannon fec9d066f0 Merge branch 'property-editor-fixes' of https://github.com/pynej/Umbraco-CMS into pynej-property-editor-fixes
Conflicts:
	src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js
	src/Umbraco.Web.UI.Client/src/views/propertyeditors/markdowneditor/markdowneditor.controller.js
	src/Umbraco.Web.UI.Client/src/views/propertyeditors/multipletextbox/multipletextbox.html
	src/Umbraco.Web/PropertyEditors/ContentPickerPropertyEditor.cs
2015-05-07 13:24:59 +10:00
Shannon a69c7dd1fc Manually merges PR: 564 2015-05-07 13:09:29 +10:00
Shannon 4e6a3458d0 Fixes: U4-6600 Label on files not just folders in file browser (media) and fixes up the last image rendered in the photo browser, as well as the overlays, whitespace and overflow and vertical alignment. 2015-05-07 12:57:23 +10:00
Shannon a5bb8ba8ee Merge branch 'iamphill-media-label' into dev-v7 2015-05-07 12:01:44 +10:00
Shannon d4f3dbcfc0 Merge branch 'media-label' of https://github.com/iamphill/Umbraco-CMS into iamphill-media-label 2015-05-07 12:01:31 +10:00
Shannon 6a0656fbb0 fixes spacing for radio/check boxes (U4-6036) tested in ie, ff and chrome 2015-05-07 11:59:10 +10:00
Shannon Deminick 9dc0999ebd Merge pull request #595 from redmorello/U4-6036
U4 6036 - Checkbox and Radio button styling incorrect in backend
2015-05-07 11:49:30 +10:00
Shannon 813f1a1f2d Fixes: U4-6035 Properrty.WasDirty() always returns false 2015-05-07 11:43:53 +10:00
Shannon e45b0a53b8 Merge branch 'aaronpowell-master-v7' into dev-v7 2015-05-07 11:07:16 +10:00
Shannon 685635c568 Merge branch 'master-v7' of https://github.com/aaronpowell/Umbraco-CMS into aaronpowell-master-v7 2015-05-07 11:06:55 +10:00
Shannon Deminick a3e37de1ad Merge pull request #633 from bjarnef/dev-v7-U4-4507
U4-4507 - Make expand arrow in sections as a toggle
2015-05-07 11:02:08 +10:00
Shannon Deminick 692a8f807e Merge pull request #638 from bjarnef/dev-v7-U4-6276
Fix for U4-6276 - Keep headline at same position
2015-05-07 10:51:32 +10:00
Shannon f4bdcae411 Fixes: U4-6236 umbraco 7 macro parameters saving "null" 2015-05-07 10:47:36 +10:00
Shannon Deminick 3a726348d2 Merge pull request #673 from kgiszewski/dev-v7
Fix for U4-6530
2015-05-07 10:21:42 +10:00
Shannon Deminick d8b029eba6 Merge pull request #680 from WebCentrum/dev-v7-gridsort
U4-6593 - After sort, reset the TinyMCE editors with previous settings
2015-05-07 10:13:29 +10:00
Shannon 7c01670caf fixes mem leaks by not unsubscribing from events 2015-05-07 09:11:39 +10:00
Shannon 3ce5ff882e Fixes U4-5213 in a better way using a query string so it's clear where it redirects to 2015-05-07 09:11:25 +10:00
Shannon 6e7aa19073 Fixes U4-5213 in a better way using a query string so it's clear where it redirects to 2015-05-07 09:00:43 +10:00
Shannon 1cac4ed075 Fixes MVC 4.0.0.1 problem once and for all. 2015-05-07 08:10:45 +10:00
Stephan e358390211 Bugfix Xml cache - bad, bad Stephan 2015-05-06 11:10:04 +02:00
Sebastiaan Janssen 2e6c643dde Bump version 2015-05-06 11:08:25 +02:00
Sebastiaan Janssen d84b8aa675 Fix duplication of the mysql DbProviderFactory when using NuGet 2015-05-06 11:04:09 +02:00
Shannon Deminick 41a0c1f491 Merge pull request #679 from WebCentrum/dev-v7-loginredir
U4-5213 - Login redirect to originally requested URL
2015-05-06 17:46:07 +10:00
Shannon e8d4777d74 re-formatted some of the PR 2015-05-06 17:36:46 +10:00
Shannon e03ef76fcd Merge branch 'Jeavon-U4-5480' into dev-v7 2015-05-06 17:35:13 +10:00
Shannon 781ca34e34 Merge branch 'U4-5480' of https://github.com/Jeavon/Umbraco-CMS into Jeavon-U4-5480 2015-05-06 17:34:59 +10:00
Shannon d01e963365 Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7
Conflicts:
	src/Umbraco.Web.UI/packages.config
2015-05-06 17:28:05 +10:00
Shannon 821daa82c4 Fixes: U4-6474 Update to latest examine v0.1.63 2015-05-06 17:14:10 +10:00
Sebastiaan Janssen a51dd93ffe Expressed version range was wrong 2015-05-06 08:58:45 +02:00
Allyen 8299243129 U4-6593 - After sort, reset the TinyMCE editors with previous settings 2015-05-05 22:07:18 +02:00
Sebastiaan Janssen 4144590189 Upgrade to latest MySql.Data and loosen up NuGet dependency 2015-05-05 12:15:28 +02:00
Allyen 2f4ff6aaae Login redirect to originally requested URL 2015-05-04 11:49:07 +02:00
Sebastiaan Janssen ab0e549c70 We got rid of macroRenderings project ages ago, why is this file still here? 2015-05-01 14:27:49 +02:00
Sebastiaan Janssen be065b2fa3 Generate symbols nupkg (apparently you can create it from an existing NuSpec file, very cool)
Making sure that all pdbs ARE actually generated in Release mode (the AllBinaries file was missing loads of files)
Generate all and include all xml doc files too
Corrects WebPI zip, also shouldn't include dotLess.Core.dll
2015-05-01 14:27:26 +02:00
Sebastiaan Janssen f0dfd0dce2 U4-6568 NuGet 7.2.4 missing Microsoft.Threading.Tasks.dll and Microsoft.Threading.Tasks.Extensions.dll
#U4-6568 Fixed Due in version 7.2.5
2015-04-29 16:15:24 +02:00
Shannon da579c91e1 Fixes: U4-6460 7.2.2 -> 7.2.4 update fails with "an item with the same key has already been added" error 2015-04-27 13:40:41 +10:00
Shannon 550d690a31 Fixes: U4-6559 ServerVariables parsing - An Item with the same key has already been added 2015-04-27 12:41:19 +10:00
Shannon Deminick 40b75b7cf5 Merge pull request #672 from alecrt/dev-v7
U4-6295 - Fix for BusinessLogic.Log.CleanLogs task error
2015-04-27 10:56:33 +10:00
Shannon Deminick 0b28a68678 Merge pull request #675 from abjerner/patch-6
listview.html: the arrows for symbolizing ascending and descending are wrong
2015-04-27 10:53:52 +10:00
Anders Bjerner 5f27355247 listview.html: the arrows for symbolizing ascending and descending are wrong 2015-04-26 14:44:25 +02:00
Sebastiaan Janssen 356ea6824f U4-6547 Re: U4-6096 German Translator file broken again in V7.2.4
#U4-6547 Fixed Due in version 7.2.5
2015-04-23 16:59:57 +02:00
kgiszewski dc3e144493 Fix for U4-6530 2015-04-20 10:28:35 -04:00
alecrt f20fed3ce8 Fix for U4-6295 - BusinessLogic.Log.CleanLogs task error 2015-04-18 19:00:03 +02:00
bjarnef df5c5e78ff Headline was cuttet off in Firefox
In Firefox 35.0.1 the headline was cuttet off. The 1.4 line-height in
commit 824212f6c9 ensure the headline
isn't cuttet off. However line-height: normal act as fallback as 1em it
too little and cause the text might be cuttet off.
2015-02-16 20:58:40 +01:00
bjarnef 5579823b2d Remove padding-left from h1 in modal-left
Removed left-padding from h1 in umb-modal-left to align it with the
other text in the modal.
2015-02-16 00:11:41 +01:00
bjarnef 824212f6c9 Keep headline at same position
I made a small change to make sure the headline is in same position
regardless it is editable or readonly.
2015-02-15 22:20:34 +01:00
bjarnef 7091cb6012 Change code for help videos
Change code for in help.controller.js as it was.
2015-02-05 10:52:55 +01:00
bjarnef a721f6836f Pointer cursor for sections in IE10
IE10 displayed a text cursor for tray and help section. Added cursor:
pointer; to make sure a pointer cursor is displayed.
2015-02-05 03:31:41 +01:00
bjarnef 83840ba6dd U4-4507 - Make expand arrow in sections as a toggle
I have made some suggestions, so the right arrow act as a toggle button,
so you easily can collapse the extra overflow-sections. Furthermore I
have made some changes, so when you click userDialog or helpDialog other
open dialogs close and also sections. When you click a section or expand
it also close dialogs, so you don't have to close those dialogs first.
2015-02-04 21:55:19 +01:00
Aaron Powell b8097219fb Implementing a test for U4-6035 2014-12-21 17:56:33 +11:00
redmorello e5ec935128 Update forms.less
Removed negative left margin from checkbox and radio button inputs.
2014-12-18 11:08:44 +00:00
redmorello 3ea16e66d4 Update forms.less
Removed negative left margin from input and radio button inputs.
2014-12-18 11:07:08 +00:00
Phil Hughes 562367e9a2 Label on files not just folders 2014-12-16 15:25:13 +00:00
Jeavon Leopold ee386d06da Fix for U4-5480 "Bad value for attribute rel on element img in Richtext editor" by removing the attributes in the RTE value converter so they don't render on the front end site but still exist in the Umbraco UI 2014-10-01 18:48:23 +01:00
157 changed files with 2968 additions and 1598 deletions
+1 -2
View File
@@ -49,12 +49,11 @@ ECHO Setting node_modules folder to hidden to prevent VS13 from crashing on it w
attrib +h ..\src\Umbraco.Web.UI.Client\node_modules
ECHO Adding Web.config transform files to the NuGet package
REN .\_BuildOutput\WebApp\MacroScripts\Web.config Web.config.transform
REN .\_BuildOutput\WebApp\Views\Web.config Web.config.transform
REN .\_BuildOutput\WebApp\Xslt\Web.config Web.config.transform
ECHO Packing the NuGet release files
..\src\.nuget\NuGet.exe Pack NuSpecs\UmbracoCms.Core.nuspec -Version %version%
..\src\.nuget\NuGet.exe Pack NuSpecs\UmbracoCms.Core.nuspec -Version %version% -Symbols
..\src\.nuget\NuGet.exe Pack NuSpecs\UmbracoCms.nuspec -Version %version%
IF ERRORLEVEL 1 GOTO :showerror
+1 -1
View File
@@ -145,7 +145,7 @@
DestinationFiles="@(WebPiFiles->'$(WebPiFolder)%(RecursiveDir)%(Filename)%(Extension)')" />
<!-- Zip the files -->
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipFileNameWebPi)%22 %22$(WebPiFolderAbsolutePath)*%22" />
<Exec Command="..\tools\7zip\7za.exe a -r %22$(BuildZipFileNameWebPi)%22 %22$(WebPiFolderAbsolutePath)*%22 -x!dotLess.Core.dll" />
</Target>
<Target Name="ZipWebApp" DependsOnTargets="CreateSystemFolders" >
@@ -1,73 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>UmbracoCms.Core.AllBinaries</id>
<version>6.1.2</version>
<title>Umbraco Cms Core All Binaries</title>
<authors>Morten Christensen</authors>
<owners>Umbraco HQ</owners>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
<projectUrl>http://umbraco.com/</projectUrl>
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Contains the core assemblies and all of the dependant assemblies needed to run Umbraco Cms. This package only contains assemblies and can be used for package development. Use the UmbracoCms-package to setup Umbraco in Visual Studio as an ASP.NET project.</description>
<summary>Contains the core assemblies and all of the dependant assemblies needed to run Umbraco Cms</summary>
<language>en-US</language>
<tags>umbraco</tags>
</metadata>
<files>
<file src="..\_BuildOutput\bin\businesslogic.dll" target="lib\businesslogic.dll" />
<file src="..\_BuildOutput\bin\AutoMapper.dll" target="lib\AutoMapper.dll" />
<file src="..\_BuildOutput\bin\AutoMapper.Net4.dll" target="lib\AutoMapper.Net4.dll" />
<file src="..\_BuildOutput\bin\businesslogic.dll" target="lib\businesslogic.dll" />
<file src="..\_BuildOutput\bin\ClientDependency.Core.dll" target="lib\ClientDependency.Core.dll" />
<file src="..\_BuildOutput\bin\ClientDependency.Core.Mvc.dll" target="lib\ClientDependency.Core.Mvc.dll" />
<file src="..\_BuildOutput\bin\cms.dll" target="lib\cms.dll" />
<file src="..\_BuildOutput\bin\controls.dll" target="lib\controls.dll" />
<file src="..\_BuildOutput\bin\CookComputing.XmlRpcV2.dll" target="lib\CookComputing.XmlRpcV2.dll" />
<file src="..\_BuildOutput\bin\Examine.dll" target="lib\Examine.dll" />
<file src="..\_BuildOutput\bin\HtmlAgilityPack.dll" target="lib\HtmlAgilityPack.dll" />
<file src="..\_BuildOutput\bin\ICSharpCode.SharpZipLib.dll" target="lib\ICSharpCode.SharpZipLib.dll" />
<file src="..\_BuildOutput\bin\ImageProcessor.dll" target="lib\ImageProcessor.dll" />
<file src="..\_BuildOutput\bin\ImageProcessor.Web.dll" target="lib\ImageProcessor.Web.dll" />
<file src="..\_BuildOutput\bin\interfaces.dll" target="lib\interfaces.dll" />
<file src="..\_BuildOutput\bin\log4net.dll" target="lib\log4net.dll" />
<file src="..\_BuildOutput\bin\Lucene.Net.dll" target="lib\Lucene.Net.dll" />
<file src="..\_BuildOutput\bin\Microsoft.ApplicationBlocks.Data.dll" target="lib\Microsoft.ApplicationBlocks.Data.dll" />
<file src="..\_BuildOutput\bin\Microsoft.Threading.Tasks.dll" target="lib\Microsoft.Threading.Tasks.dll" />
<file src="..\_BuildOutput\bin\Microsoft.Threading.Tasks.Extensions.dll" target="lib\Microsoft.Threading.Tasks.Extensions.dll" />
<file src="..\_BuildOutput\bin\Microsoft.Web.Infrastructure.dll" target="lib\Microsoft.Web.Infrastructure.dll" />
<file src="..\_BuildOutput\bin\Microsoft.Web.Mvc.FixedDisplayModes.dll" target="lib\Microsoft.Web.Mvc.FixedDisplayModes.dll" />
<file src="..\_BuildOutput\bin\MiniProfiler.dll" target="lib\MiniProfiler.dll" />
<file src="..\_BuildOutput\bin\MySql.Data.dll" target="lib\MySql.Data.dll" />
<file src="..\_BuildOutput\bin\Newtonsoft.Json.dll" target="lib\Newtonsoft.Json.dll" />
<file src="..\_BuildOutput\bin\NuGet.Core.dll" target="lib\NuGet.Core.dll" />
<file src="..\_BuildOutput\bin\SQLCE4Umbraco.dll" target="lib\SQLCE4Umbraco.dll" />
<file src="..\_BuildOutput\bin\System.Data.SqlServerCe.dll" target="lib\System.Data.SqlServerCe.dll" />
<file src="..\_BuildOutput\bin\System.Data.SqlServerCe.Entity.dll" target="lib\System.Data.SqlServerCe.Entity.dll" />
<file src="..\_BuildOutput\bin\System.Net.Http.dll" target="lib\System.Net.Http.dll" />
<file src="..\_BuildOutput\bin\System.Net.Http.Extensions.dll" target="lib\System.Net.Http.Extensions.dll" />
<file src="..\_BuildOutput\bin\System.Net.Http.Formatting.dll" target="lib\System.Net.Http.Formatting.dll" />
<file src="..\_BuildOutput\bin\System.Net.Http.Primitives.dll" target="lib\System.Net.Http.Primitives.dll" />
<file src="..\_BuildOutput\bin\System.Net.Http.WebRequest.dll" target="lib\System.Net.Http.WebRequest.dll" />
<file src="..\_BuildOutput\bin\System.Web.Helpers.dll" target="lib\System.Web.Helpers.dll" />
<file src="..\_BuildOutput\bin\System.Web.Http.dll" target="lib\System.Web.Http.dll" />
<file src="..\_BuildOutput\bin\System.Web.Http.WebHost.dll" target="lib\System.Web.Http.WebHost.dll" />
<file src="..\_BuildOutput\bin\System.Web.Mvc.dll" target="lib\System.Web.Mvc.dll" />
<file src="..\_BuildOutput\bin\System.Web.Razor.dll" target="lib\System.Web.Razor.dll" />
<file src="..\_BuildOutput\bin\System.Web.WebPages.Administration.dll" target="lib\System.Web.WebPages.Administration.dll" />
<file src="..\_BuildOutput\bin\System.Web.WebPages.Deployment.dll" target="lib\System.Web.WebPages.Deployment.dll" />
<file src="..\_BuildOutput\bin\System.Web.WebPages.dll" target="lib\System.Web.WebPages.dll" />
<file src="..\_BuildOutput\bin\System.Web.WebPages.Razor.dll" target="lib\System.Web.WebPages.Razor.dll" />
<file src="..\_BuildOutput\bin\TidyNet.dll" target="lib\TidyNet.dll" />
<file src="..\_BuildOutput\bin\Umbraco.Core.dll" target="lib\Umbraco.Core.dll" />
<file src="..\_BuildOutput\bin\umbraco.DataLayer.dll" target="lib\umbraco.DataLayer.dll" />
<file src="..\_BuildOutput\bin\umbraco.dll" target="lib\umbraco.dll" />
<file src="..\_BuildOutput\bin\umbraco.editorControls.dll" target="lib\umbraco.editorControls.dll" />
<file src="..\_BuildOutput\bin\umbraco.MacroEngines.dll" target="lib\umbraco.MacroEngines.dll" />
<file src="..\_BuildOutput\bin\umbraco.providers.dll" target="lib\umbraco.providers.dll" />
<file src="..\_BuildOutput\bin\Umbraco.Web.UI.dll" target="lib\Umbraco.Web.UI.dll" />
<file src="..\_BuildOutput\bin\UmbracoExamine.dll" target="lib\UmbracoExamine.dll" />
<file src="..\_BuildOutput\bin\UrlRewritingNet.UrlRewriter.dll" target="lib\UrlRewritingNet.UrlRewriter.dll" />
</files>
</package>
@@ -1,71 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<package xmlns="http://schemas.microsoft.com/packaging/2010/07/nuspec.xsd">
<metadata>
<id>UmbracoCms.Core</id>
<version>7.0.0</version>
<title>Umbraco Cms Core Binaries</title>
<authors>Umbraco HQ</authors>
<owners>Umbraco HQ</owners>
<licenseUrl>http://opensource.org/licenses/MIT</licenseUrl>
<projectUrl>http://umbraco.com/</projectUrl>
<iconUrl>http://umbraco.com/media/357769/100px_transparent.png</iconUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
<description>Contains the core assemblies needed to run Umbraco Cms. This package only contains assemblies and can be used for package development. Use the UmbracoCms-package to setup Umbraco in Visual Studio as an ASP.NET project.</description>
<summary>Contains the core assemblies needed to run Umbraco Cms</summary>
<language>en-US</language>
<tags>umbraco</tags>
</metadata>
<files>
<file src="..\..\src\SQLCE4Umbraco\obj\Debug\SQLCE4Umbraco.dll" target="lib" />
<file src="..\..\src\SQLCE4Umbraco\obj\Debug\SQLCE4Umbraco.pdb" target="lib" />
<file src="..\..\src\SQLCE4Umbraco\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\SQLCE4Umbraco" />
<file src="..\..\src\umbraco.businesslogic\obj\Debug\businesslogic.dll" target="lib" />
<file src="..\..\src\umbraco.businesslogic\obj\Debug\businesslogic.pdb" target="lib" />
<file src="..\..\src\umbraco.businesslogic\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.businesslogic" />
<file src="..\..\src\umbraco.cms\obj\Debug\cms.dll" target="lib" />
<file src="..\..\src\umbraco.cms\obj\Debug\cms.pdb" target="lib" />
<file src="..\..\src\umbraco.cms\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.cms" />
<file src="..\..\src\umbraco.controls\obj\Debug\controls.dll" target="lib" />
<file src="..\..\src\umbraco.controls\obj\Debug\controls.pdb" target="lib" />
<file src="..\..\src\umbraco.controls\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.controls" />
<file src="..\..\src\umbraco.interfaces\obj\Debug\interfaces.dll" target="lib" />
<file src="..\..\src\umbraco.interfaces\obj\Debug\interfaces.pdb" target="lib" />
<file src="..\..\src\umbraco.interfaces\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.interfaces" />
<file src="..\..\src\Umbraco.Core\obj\Debug\Umbraco.Core.dll" target="lib" />
<file src="..\..\src\Umbraco.Core\obj\Debug\Umbraco.Core.pdb" target="lib" />
<file src="..\..\src\Umbraco.Core\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Core" />
<file src="..\..\src\umbraco.datalayer\obj\Debug\umbraco.DataLayer.dll" target="lib" />
<file src="..\..\src\umbraco.datalayer\obj\Debug\umbraco.DataLayer.pdb" target="lib" />
<file src="..\..\src\umbraco.datalayer\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.datalayer" />
<file src="..\..\src\umbraco.editorControls\obj\Debug\umbraco.editorControls.dll" target="lib" />
<file src="..\..\src\umbraco.editorControls\obj\Debug\umbraco.editorControls.pdb" target="lib" />
<file src="..\..\src\umbraco.editorControls\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.editorControls" />
<file src="..\..\src\umbraco.MacroEngines\obj\Debug\umbraco.MacroEngines.dll" target="lib" />
<file src="..\..\src\umbraco.MacroEngines\obj\Debug\umbraco.MacroEngines.pdb" target="lib" />
<file src="..\..\src\umbraco.MacroEngines\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.MacroEngines" />
<file src="..\..\src\umbraco.providers\obj\Debug\umbraco.providers.dll" target="lib" />
<file src="..\..\src\umbraco.providers\obj\Debug\umbraco.providers.pdb" target="lib" />
<file src="..\..\src\umbraco.providers\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.providers" />
<file src="..\..\src\Umbraco.Web\obj\Debug\umbraco.dll" target="lib" />
<file src="..\..\src\Umbraco.Web\obj\Debug\umbraco.pdb" target="lib" />
<file src="..\..\src\Umbraco.Web\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Web" />
<file src="..\..\src\bin\Debug\Umbraco.Web.UI.dll" target="lib" />
<file src="..\..\src\bin\Debug\Umbraco.Web.UI.pdb" target="lib" />
<file src="..\..\src\Umbraco.Web.UI\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Web.UI" />
<file src="..\..\src\UmbracoExamine\obj\Debug\UmbracoExamine.dll" target="lib" />
<file src="..\..\src\UmbracoExamine\obj\Debug\UmbracoExamine.pdb" target="lib" />
<file src="..\..\src\UmbracoExamine\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\UmbracoExamine" />
</files>
</package>
+33 -2
View File
@@ -26,13 +26,13 @@
<dependency id="HtmlAgilityPack" version="[1.4.6, 2.0.0)" />
<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.6.5]" />
<dependency id="MySql.Data" version="[6.9.6, 7.0.0)" />
<dependency id="xmlrpcnet" version="[2.5.0, 3.0.0)" />
<dependency id="ClientDependency" version="[1.8.3.1, 2.0.0)" />
<dependency id="ClientDependency-Mvc" version="[1.8.0, 2.0.0)" />
<dependency id="AutoMapper" version="[3.0.0, 4.0.0)" />
<dependency id="Newtonsoft.Json" version="[6.0.5, 7.0.0)" />
<dependency id="Examine" version="[0.1.62, 1.0.0)" />
<dependency id="Examine" version="[0.1.63, 1.0.0)" />
<dependency id="ImageProcessor" version="[1.9.5, 3.0.0)" />
<dependency id="ImageProcessor.Web" version="[3.3.1, 5.0.0)" />
</dependencies>
@@ -49,6 +49,7 @@
<file src="..\_BuildOutput\WebApp\bin\log4net.dll" target="lib\log4net.dll" />
<file src="..\_BuildOutput\WebApp\bin\Microsoft.ApplicationBlocks.Data.dll" target="lib\Microsoft.ApplicationBlocks.Data.dll" />
<file src="..\_BuildOutput\WebApp\bin\SQLCE4Umbraco.dll" target="lib\SQLCE4Umbraco.dll" />
<file src="..\_BuildOutput\WebApp\bin\SQLCE4Umbraco.xml" target="lib\SQLCE4Umbraco.xml" />
<file src="..\_BuildOutput\WebApp\bin\System.Data.SqlServerCe.dll" target="lib\System.Data.SqlServerCe.dll" />
<file src="..\_BuildOutput\WebApp\bin\System.Data.SqlServerCe.Entity.dll" target="lib\System.Data.SqlServerCe.Entity.dll" />
<file src="..\_BuildOutput\WebApp\bin\TidyNet.dll" target="lib\TidyNet.dll" />
@@ -65,8 +66,38 @@
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.dll" target="lib\umbraco.providers.dll" />
<file src="..\_BuildOutput\WebApp\bin\umbraco.providers.xml" target="lib\umbraco.providers.xml" />
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Web.UI.dll" target="lib\Umbraco.Web.UI.dll" />
<file src="..\_BuildOutput\WebApp\bin\Umbraco.Web.UI.xml" target="lib\Umbraco.Web.UI.xml" />
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.dll" target="lib\UmbracoExamine.dll" />
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.xml" target="lib\UmbracoExamine.xml" />
<file src="..\_BuildOutput\WebApp\bin\UrlRewritingNet.UrlRewriter.dll" target="lib\UrlRewritingNet.UrlRewriter.dll" />
<file src="tools\install.core.ps1" target="tools\install.ps1" />
<!-- Added to be able to produce a symbols package -->
<file src="..\_BuildOutput\bin\SQLCE4Umbraco.pdb" target="lib" />
<file src="..\..\src\SQLCE4Umbraco\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\SQLCE4Umbraco" />
<file src="..\_BuildOutput\bin\businesslogic.pdb" target="lib" />
<file src="..\..\src\umbraco.businesslogic\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.businesslogic" />
<file src="..\_BuildOutput\bin\cms.pdb" target="lib" />
<file src="..\..\src\umbraco.cms\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.cms" />
<file src="..\_BuildOutput\bin\controls.pdb" target="lib" />
<file src="..\..\src\umbraco.controls\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.controls" />
<file src="..\_BuildOutput\bin\interfaces.pdb" target="lib" />
<file src="..\..\src\umbraco.interfaces\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.interfaces" />
<file src="..\_BuildOutput\bin\Umbraco.Core.pdb" target="lib" />
<file src="..\..\src\Umbraco.Core\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Core" />
<file src="..\_BuildOutput\bin\umbraco.DataLayer.pdb" target="lib" />
<file src="..\..\src\umbraco.datalayer\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.datalayer" />
<file src="..\_BuildOutput\bin\umbraco.editorControls.pdb" target="lib" />
<file src="..\..\src\umbraco.editorControls\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.editorControls" />
<file src="..\_BuildOutput\bin\umbraco.MacroEngines.pdb" target="lib" />
<file src="..\..\src\umbraco.MacroEngines\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.MacroEngines" />
<file src="..\_BuildOutput\bin\umbraco.providers.pdb" target="lib" />
<file src="..\..\src\umbraco.providers\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\umbraco.providers" />
<file src="..\_BuildOutput\bin\umbraco.pdb" target="lib" />
<file src="..\..\src\Umbraco.Web\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Web" />
<file src="..\_BuildOutput\bin\Umbraco.Web.UI.pdb" target="lib" />
<file src="..\..\src\Umbraco.Web.UI\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Web.UI" />
<file src="..\_BuildOutput\bin\UmbracoExamine.pdb" target="lib" />
<file src="..\..\src\UmbracoExamine\**\*.cs" exclude="..\..\src\**\TemporaryGeneratedFile*.cs" target="src\UmbracoExamine" />
</files>
</package>
+4 -2
View File
@@ -37,8 +37,10 @@
<DbProviderFactories xdt:Transform="InsertIfMissing">
<remove invariant="System.Data.SqlServerCe.4.0" xdt:Locator="Match(invariant)" xdt:Transform="InsertIfMissing" />
<add name="Microsoft SQL Server Compact Data Provider 4.0" invariant="System.Data.SqlServerCe.4.0" description=".NET Framework Data Provider for Microsoft SQL Server Compact" type="System.Data.SqlServerCe.SqlCeProviderFactory, System.Data.SqlServerCe" xdt:Locator="Match(invariant)" xdt:Transform="SetAttributes(invariant,description,type)" />
<remove invariant="MySql.Data.MySqlClient" xdt:Locator="Match(invariant)" xdt:Transform="InsertIfMissing" />
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data" xdt:Locator="Match(invariant)" xdt:Transform="SetAttributes(invariant,description,type)" />
<remove invariant="MySql.Data.MySqlClient" xdt:Locator="Match(invariant)" xdt:Transform="InsertIfMissing" />
<add invariant="MySql.Data.MySqlClient" xdt:Locator="Match(invariant)" xdt:Transform="Remove" />
<add name="MySQL Data Provider" invariant="MySql.Data.MySqlClient" description=".Net Framework Data Provider for MySQL" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data" xdt:Locator="Match(invariant)" xdt:Transform="InsertIfMissing" />
<add invariant="MySql.Data.MySqlClient" type="MySql.Data.MySqlClient.MySqlClientFactory, MySql.Data" xdt:Locator="Match(invariant)" xdt:Transform="SetAttributes(type)" />
</DbProviderFactories>
</system.data>
<clientDependency xdt:Transform="RemoveAttributes(version)" />
+1 -2
View File
@@ -1,3 +1,2 @@
# Usage: on line 2 put the release version, on line 3 put the version comment (example: beta)
7.2.5
RC
7.2.6
+2 -2
View File
@@ -11,5 +11,5 @@ using System.Resources;
[assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyFileVersion("7.2.5")]
[assembly: AssemblyInformationalVersion("7.2.5-RC")]
[assembly: AssemblyFileVersion("7.2.6")]
[assembly: AssemblyInformationalVersion("7.2.6")]
+11 -7
View File
@@ -165,6 +165,8 @@ namespace Umbraco.Core
/// </remarks>
internal string OriginalRequestUrl { get; set; }
private bool _versionsDifferenceReported;
/// <summary>
/// Checks if the version configured matches the assembly version
/// </summary>
@@ -174,17 +176,19 @@ namespace Umbraco.Core
{
try
{
string configStatus = ConfigurationStatus;
string currentVersion = UmbracoVersion.Current.ToString(3);
var configStatus = ConfigurationStatus;
var currentVersion = UmbracoVersion.Current.ToString(3);
var ok = configStatus == currentVersion;
if (currentVersion != configStatus)
if (ok == false && _versionsDifferenceReported == false)
{
LogHelper.Info<ApplicationContext>("CurrentVersion different from configStatus: '" + currentVersion + "','" + configStatus + "'");
// remember it's been reported so we don't flood the log
// no thread-safety so there may be a few log entries, doesn't matter
_versionsDifferenceReported = true;
LogHelper.Info<ApplicationContext>("CurrentVersion different from configStatus: '" + currentVersion + "','" + configStatus + "'");
}
return (configStatus == currentVersion);
return ok;
}
catch
{
+9
View File
@@ -11,6 +11,15 @@ namespace Umbraco.Core
// - this is NOT a reader/writer lock
// - this is NOT a recursive lock
//
// using a named Semaphore here and not a Mutex because mutexes have thread
// affinity which does not work with async situations
//
// it is important that managed code properly release the Semaphore before
// going down else it will maintain the lock - however note that when the
// whole process (w3wp.exe) goes down and all handles to the Semaphore have
// been closed, the Semaphore system object is destroyed - so in any case
// an iisreset should clean up everything
//
internal class AsyncLock
{
private readonly SemaphoreSlim _semaphore;
+3
View File
@@ -54,5 +54,8 @@ namespace Umbraco.Core.Cache
public const string DataTypeCacheKey = "UmbracoDataTypeDefinition";
public const string DataTypePreValuesCacheKey = "UmbracoPreVal";
public const string IdToKeyCacheKey = "UI2K";
public const string KeyToIdCacheKey = "UK2I";
}
}
@@ -12,7 +12,7 @@ namespace Umbraco.Core.Cache
protected const string CacheItemPrefix = "umbrtmche";
// an object that represent a value that has not been created yet
protected readonly object ValueNotCreated = new object();
protected internal static readonly object ValueNotCreated = new object();
// manupulate the underlying cache entries
// these *must* be called from within the appropriate locks
@@ -30,21 +30,58 @@ namespace Umbraco.Core.Cache
return string.Format("{0}-{1}", CacheItemPrefix, key);
}
protected object GetSafeLazyValue(Lazy<object> lazy, bool onlyIfValueIsCreated = false)
protected internal static Lazy<object> GetSafeLazy(Func<object> getCacheItem)
{
// try to generate the value and if it fails,
// wrap in an ExceptionHolder - would be much simpler
// to just use lazy.IsValueFaulted alas that field is
// internal
return new Lazy<object>(() =>
{
try
{
return getCacheItem();
}
catch (Exception e)
{
return new ExceptionHolder(e);
}
});
}
protected internal static object GetSafeLazyValue(Lazy<object> lazy, bool onlyIfValueIsCreated = false)
{
// if onlyIfValueIsCreated, do not trigger value creation
// must return something, though, to differenciate from null values
if (onlyIfValueIsCreated && lazy.IsValueCreated == false) return ValueNotCreated;
// if execution has thrown then lazy.IsValueCreated is false
// and lazy.IsValueFaulted is true (but internal) so we use our
// own exception holder (see Lazy<T> source code) to return null
if (lazy.Value is ExceptionHolder) return null;
// we have a value and execution has not thrown so returning
// here does not throw - unless we're re-entering, take care of it
try
{
// if onlyIfValueIsCreated, do not trigger value creation
// must return something, though, to differenciate from null values
if (onlyIfValueIsCreated && lazy.IsValueCreated == false) return ValueNotCreated;
return lazy.Value;
}
catch
catch (InvalidOperationException e)
{
return null;
throw new InvalidOperationException("The method that computes a value for the cache has tried to read that value from the cache.", e);
}
}
internal class ExceptionHolder
{
public ExceptionHolder(Exception e)
{
Exception = e;
}
public Exception Exception { get; private set; }
}
#region Clear
public virtual void ClearAllCache()
@@ -105,15 +105,22 @@ namespace Umbraco.Core.Cache
if (result == null || GetSafeLazyValue(result, true) == null) // get non-created as NonCreatedValue & exceptions as null
{
result = new Lazy<object>(getCacheItem);
result = GetSafeLazy(getCacheItem);
ContextItems[cacheKey] = result;
}
}
// this may throw if getCacheItem throws, but this is the only place where
// it would throw as everywhere else we use GetLazySaveValue() to hide exceptions
// and pretend exceptions were never inserted into cache to begin with.
return result.Value;
// using GetSafeLazy and GetSafeLazyValue ensures that we don't cache
// exceptions (but try again and again) and silently eat them - however at
// some point we have to report them - so need to re-throw here
// this does not throw anymore
//return result.Value;
var value = result.Value; // will not throw (safe lazy)
var eh = value as ExceptionHolder;
if (eh != null) throw eh.Exception; // throw once!
return value;
}
#endregion
@@ -129,7 +129,7 @@ namespace Umbraco.Core.Cache
if (result == null || GetSafeLazyValue(result, true) == null) // get non-created as NonCreatedValue & exceptions as null
{
result = new Lazy<object>(getCacheItem);
result = GetSafeLazy(getCacheItem);
var absolute = isSliding ? System.Web.Caching.Cache.NoAbsoluteExpiration : (timeout == null ? System.Web.Caching.Cache.NoAbsoluteExpiration : DateTime.Now.Add(timeout.Value));
var sliding = isSliding == false ? System.Web.Caching.Cache.NoSlidingExpiration : (timeout ?? System.Web.Caching.Cache.NoSlidingExpiration);
@@ -138,10 +138,17 @@ namespace Umbraco.Core.Cache
}
}
// this may throw if getCacheItem throws, but this is the only place where
// it would throw as everywhere else we use GetLazySaveValue() to hide exceptions
// and pretend exceptions were never inserted into cache to begin with.
return result.Value;
// using GetSafeLazy and GetSafeLazyValue ensures that we don't cache
// exceptions (but try again and again) and silently eat them - however at
// some point we have to report them - so need to re-throw here
// this does not throw anymore
//return result.Value;
value = result.Value; // will not throw (safe lazy)
var eh = value as ExceptionHolder;
if (eh != null) throw eh.Exception; // throw once!
return value;
}
public object GetCacheItem(string cacheKey, Func<object> getCacheItem, TimeSpan? timeout, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null)
@@ -173,7 +180,7 @@ namespace Umbraco.Core.Cache
// NOTE - here also we must insert a Lazy<object> but we can evaluate it right now
// and make sure we don't store a null value.
var result = new Lazy<object>(getCacheItem);
var result = GetSafeLazy(getCacheItem);
var value = result.Value; // force evaluation now - this may throw if cacheItem throws, and then nothing goes into cache
if (value == null) return; // do not store null values (backward compat)
@@ -19,29 +19,11 @@ namespace Umbraco.Core.Cache
private readonly ReaderWriterLockSlim _locker = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
internal ObjectCache MemoryCache;
// an object that represent a value that has not been created yet
protected readonly object ValueNotCreated = new object();
public ObjectCacheRuntimeCacheProvider()
{
MemoryCache = new MemoryCache("in-memory");
}
protected object GetSafeLazyValue(Lazy<object> lazy, bool onlyIfValueIsCreated = false)
{
try
{
// if onlyIfValueIsCreated, do not trigger value creation
// must return something, though, to differenciate from null values
if (onlyIfValueIsCreated && lazy.IsValueCreated == false) return ValueNotCreated;
return lazy.Value;
}
catch
{
return null;
}
}
#region Clear
public virtual void ClearAllCache()
@@ -72,7 +54,7 @@ namespace Umbraco.Core.Cache
// x.Value is Lazy<object> and not null, its value may be null
// remove null values as well, does not hurt
// get non-created as NonCreatedValue & exceptions as null
var value = GetSafeLazyValue((Lazy<object>)x.Value, true);
var value = DictionaryCacheProviderBase.GetSafeLazyValue((Lazy<object>)x.Value, true);
return value == null || value.GetType().ToString().InvariantEquals(typeName);
})
.Select(x => x.Key)
@@ -92,7 +74,7 @@ namespace Umbraco.Core.Cache
// x.Value is Lazy<object> and not null, its value may be null
// remove null values as well, does not hurt
// get non-created as NonCreatedValue & exceptions as null
var value = GetSafeLazyValue((Lazy<object>)x.Value, true);
var value = DictionaryCacheProviderBase.GetSafeLazyValue((Lazy<object>)x.Value, true);
return value == null || value.GetType() == typeOfT;
})
.Select(x => x.Key)
@@ -112,7 +94,7 @@ namespace Umbraco.Core.Cache
// x.Value is Lazy<object> and not null, its value may be null
// remove null values as well, does not hurt
// get non-created as NonCreatedValue & exceptions as null
var value = GetSafeLazyValue((Lazy<object>)x.Value, true);
var value = DictionaryCacheProviderBase.GetSafeLazyValue((Lazy<object>)x.Value, true);
if (value == null) return true;
return value.GetType() == typeOfT
&& predicate(x.Key, (T) value);
@@ -161,7 +143,7 @@ namespace Umbraco.Core.Cache
.ToArray(); // evaluate while locked
}
return entries
.Select(x => GetSafeLazyValue((Lazy<object>)x.Value)) // return exceptions as null
.Select(x => DictionaryCacheProviderBase.GetSafeLazyValue((Lazy<object>)x.Value)) // return exceptions as null
.Where(x => x != null) // backward compat, don't store null values in the cache
.ToList();
}
@@ -176,7 +158,7 @@ namespace Umbraco.Core.Cache
.ToArray(); // evaluate while locked
}
return entries
.Select(x => GetSafeLazyValue((Lazy<object>)x.Value)) // return exceptions as null
.Select(x => DictionaryCacheProviderBase.GetSafeLazyValue((Lazy<object>)x.Value)) // return exceptions as null
.Where(x => x != null) // backward compat, don't store null values in the cache
.ToList();
}
@@ -188,7 +170,7 @@ namespace Umbraco.Core.Cache
{
result = MemoryCache.Get(cacheKey) as Lazy<object>; // null if key not found
}
return result == null ? null : GetSafeLazyValue(result); // return exceptions as null
return result == null ? null : DictionaryCacheProviderBase.GetSafeLazyValue(result); // return exceptions as null
}
public object GetCacheItem(string cacheKey, Func<object> getCacheItem)
@@ -205,9 +187,9 @@ namespace Umbraco.Core.Cache
using (var lck = new UpgradeableReadLock(_locker))
{
result = MemoryCache.Get(cacheKey) as Lazy<object>;
if (result == null || GetSafeLazyValue(result, true) == null) // get non-created as NonCreatedValue & exceptions as null
if (result == null || DictionaryCacheProviderBase.GetSafeLazyValue(result, true) == null) // get non-created as NonCreatedValue & exceptions as null
{
result = new Lazy<object>(getCacheItem);
result = DictionaryCacheProviderBase.GetSafeLazy(getCacheItem);
var policy = GetPolicy(timeout, isSliding, removedCallback, dependentFiles);
lck.UpgradeToWriteLock();
@@ -215,7 +197,12 @@ namespace Umbraco.Core.Cache
}
}
return result.Value;
//return result.Value;
var value = result.Value; // will not throw (safe lazy)
var eh = value as DictionaryCacheProviderBase.ExceptionHolder;
if (eh != null) throw eh.Exception; // throw once!
return value;
}
#endregion
@@ -227,7 +214,7 @@ namespace Umbraco.Core.Cache
// NOTE - here also we must insert a Lazy<object> but we can evaluate it right now
// and make sure we don't store a null value.
var result = new Lazy<object>(getCacheItem);
var result = DictionaryCacheProviderBase.GetSafeLazy(getCacheItem);
var value = result.Value; // force evaluation now
if (value == null) return; // do not store null values (backward compat)
@@ -34,7 +34,7 @@ namespace Umbraco.Core.Configuration
{
get
{
var converted = ObjectExtensions.TryConvertTo<T>(RawValue);
var converted = RawValue.TryConvertTo<T>();
if (converted.Success == false)
throw new InvalidCastException("Could not convert value " + RawValue + " to type " + typeof(T));
return converted.Result;
@@ -1,8 +1,9 @@
using System.Xml.Linq;
using System;
using System.Xml.Linq;
namespace Umbraco.Core.Configuration.UmbracoSettings
{
internal class ContentErrorPageElement : InnerTextConfigurationElement<int>, IContentErrorPage
internal class ContentErrorPageElement : InnerTextConfigurationElement<string>, IContentErrorPage
{
public ContentErrorPageElement(XElement rawXml)
: base(rawXml)
@@ -14,7 +15,43 @@ namespace Umbraco.Core.Configuration.UmbracoSettings
}
public bool HasContentId
{
get { return ContentId != int.MinValue; }
}
public bool HasContentKey
{
get { return ContentKey != Guid.Empty; }
}
public int ContentId
{
get
{
int parsed;
if (int.TryParse(Value, out parsed))
{
return parsed;
}
return int.MinValue;
}
}
public Guid ContentKey
{
get
{
Guid parsed;
if (Guid.TryParse(Value, out parsed))
{
return parsed;
}
return Guid.Empty;
}
}
public string ContentXPath
{
get { return Value; }
}
@@ -1,8 +1,14 @@
namespace Umbraco.Core.Configuration.UmbracoSettings
using System;
namespace Umbraco.Core.Configuration.UmbracoSettings
{
public interface IContentErrorPage
{
int ContentId { get; }
Guid ContentKey { get; }
string ContentXPath { get; }
bool HasContentId { get; }
bool HasContentKey { get; }
string Culture { get; set; }
}
}
@@ -5,7 +5,7 @@ namespace Umbraco.Core.Configuration
{
public class UmbracoVersion
{
private static readonly Version Version = new Version("7.2.5");
private static readonly Version Version = new Version("7.2.6");
/// <summary>
/// Gets the current version of Umbraco.
@@ -23,7 +23,7 @@ namespace Umbraco.Core.Configuration
/// Gets the version comment (like beta or RC).
/// </summary>
/// <value>The version comment.</value>
public static string CurrentComment { get { return "RC"; } }
public static string CurrentComment { get { return ""; } }
// Get the version of the umbraco.dll by looking at a class in that dll
// Had to do it like this due to medium trust issues, see: http://haacked.com/archive/2010/11/04/assembly-location-and-medium-trust.aspx
+1 -1
View File
@@ -66,7 +66,7 @@ namespace Umbraco.Core
InitializeProfilerResolver();
_timer = DisposableTimer.DebugDuration<CoreBootManager>("Umbraco application starting", "Umbraco application startup complete");
_timer = DisposableTimer.TraceDuration<CoreBootManager>("Umbraco application starting", "Umbraco application startup complete");
CreateApplicationCache();
+45
View File
@@ -0,0 +1,45 @@
using System.Web;
namespace Umbraco.Core
{
public static class HttpContextExtensions
{
public static string GetCurrentRequestIpAddress(this HttpContextBase httpContext)
{
if (httpContext == null)
{
return "Unknown, httpContext is null";
}
if (httpContext.Request == null)
{
return "Unknown, httpContext.Request is null";
}
if (httpContext.Request.ServerVariables == null)
{
return "Unknown, httpContext.Request.ServerVariables is null";
}
// From: http://stackoverflow.com/a/740431/5018
try
{
var ipAddress = httpContext.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
if (string.IsNullOrEmpty(ipAddress))
return httpContext.Request.ServerVariables["REMOTE_ADDR"];
var addresses = ipAddress.Split(',');
if (addresses.Length != 0)
return addresses[0];
return httpContext.Request.ServerVariables["REMOTE_ADDR"];
}
catch (System.Exception ex)
{
//This try catch is to just always ensure that no matter what we're not getting any exceptions caused since
// that would cause people to not be able to login
return string.Format("Unknown, exception occurred trying to resolve IP {0}", ex);
}
}
}
}
+2 -2
View File
@@ -40,8 +40,8 @@ namespace Umbraco.Core.Logging
/// <returns></returns>
private static string PrefixThreadId(string generateMessageFormat)
{
return "[Thread " + Thread.CurrentThread.ManagedThreadId + "] " + generateMessageFormat;
}
return "[T" + Thread.CurrentThread.ManagedThreadId + "/D" + AppDomain.CurrentDomain.Id + "] " + generateMessageFormat;
}
#region Error
/// <summary>
+1 -1
View File
@@ -12,7 +12,7 @@ namespace Umbraco.Core.Macros
internal class MacroTagParser
{
private static readonly Regex MacroRteContent = new Regex(@"(<!--\s*?)(<\?UMBRACO_MACRO.*?/>)(\s*?-->)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
private static readonly Regex MacroPersistedFormat = new Regex(@"(<\?UMBRACO_MACRO macroAlias=[""']([^""\'\n\r]+?)[""'].+?)(?:/>|>.*?</\?UMBRACO_MACRO>)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
private static readonly Regex MacroPersistedFormat = new Regex(@"(<\?UMBRACO_MACRO (?:.+)?macroAlias=[""']([^""\'\n\r]+?)[""'].+?)(?:/>|>.*?</\?UMBRACO_MACRO>)", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.Singleline);
/// <summary>
/// This formats the persisted string to something useful for the rte so that the macro renders properly since we
+1 -68
View File
@@ -337,74 +337,7 @@ namespace Umbraco.Core.Models
ChangePublishedState(PublishedState.Unpublished);
}
}
/// <summary>
/// Indicates whether a specific property on the current <see cref="IContent"/> entity is dirty.
/// </summary>
/// <param name="propertyName">Name of the property to check</param>
/// <returns>True if Property is dirty, otherwise False</returns>
public override bool IsPropertyDirty(string propertyName)
{
bool existsInEntity = base.IsPropertyDirty(propertyName);
if (existsInEntity)
return true;
return Properties.Any(x => x.IsPropertyDirty(propertyName));
}
/// <summary>
/// Indicates whether the current entity is dirty.
/// </summary>
/// <returns>True if entity is dirty, otherwise False</returns>
public override bool IsDirty()
{
return IsEntityDirty() || IsAnyUserPropertyDirty();
}
/// <summary>
/// Returns true if only the entity properties are direty
/// </summary>
/// <returns></returns>
public bool IsEntityDirty()
{
return base.IsDirty();
}
/// <summary>
/// Returns true if any of the properties are dirty
/// </summary>
/// <returns></returns>
public bool IsAnyUserPropertyDirty()
{
return Properties.Any(x => x.IsDirty());
}
/// <summary>
/// Returns a list of all dirty user defined properties
/// </summary>
/// <returns></returns>
public IEnumerable<string> GetDirtyUserProperties()
{
return Properties.Where(x => x.IsDirty()).Select(x => x.Alias);
}
/// <summary>
/// Resets dirty properties by clearing the dictionary used to track changes.
/// </summary>
/// <remarks>
/// Please note that resetting the dirty properties could potentially
/// obstruct the saving of a new or updated entity.
/// </remarks>
public override void ResetDirtyProperties()
{
base.ResetDirtyProperties();
foreach (var property in Properties)
{
property.ResetDirtyProperties();
}
}
/// <summary>
/// Method to call when Entity is being saved
/// </summary>
+86 -1
View File
@@ -466,6 +466,8 @@ namespace Umbraco.Core.Models
public abstract void ChangeTrashedState(bool isTrashed, int parentId = -20);
#region Dirty property handling
/// <summary>
/// We will override this method to ensure that when we reset the dirty properties that we
/// also reset the dirty changes made to the content's Properties (user defined)
@@ -480,6 +482,89 @@ namespace Umbraco.Core.Models
prop.ResetDirtyProperties(rememberPreviouslyChangedProperties);
}
}
/// <summary>
/// Indicates whether the current entity is dirty.
/// </summary>
/// <returns>True if entity is dirty, otherwise False</returns>
public override bool IsDirty()
{
return IsEntityDirty() || this.IsAnyUserPropertyDirty();
}
/// <summary>
/// Indicates whether the current entity was dirty.
/// </summary>
/// <returns>True if entity was dirty, otherwise False</returns>
public override bool WasDirty()
{
return WasEntityDirty() || this.WasAnyUserPropertyDirty();
}
/// <summary>
/// Returns true if only the entity properties are dirty
/// </summary>
/// <returns></returns>
public bool IsEntityDirty()
{
return base.IsDirty();
}
/// <summary>
/// Returns true if only the entity properties were dirty
/// </summary>
/// <returns></returns>
public bool WasEntityDirty()
{
return base.WasDirty();
}
/// <summary>
/// Indicates whether a specific property on the current <see cref="IContent"/> entity is dirty.
/// </summary>
/// <param name="propertyName">Name of the property to check</param>
/// <returns>
/// True if any of the class properties are dirty or
/// True if any of the user defined PropertyType properties are dirty based on their alias,
/// otherwise False
/// </returns>
public override bool IsPropertyDirty(string propertyName)
{
bool existsInEntity = base.IsPropertyDirty(propertyName);
if (existsInEntity)
return true;
if (Properties.Contains(propertyName))
{
return Properties[propertyName].IsDirty();
}
return false;
}
/// <summary>
/// Indicates whether a specific property on the current entity was changed and the changes were committed
/// </summary>
/// <param name="propertyName">Name of the property to check</param>
/// <returns>
/// True if any of the class properties are dirty or
/// True if any of the user defined PropertyType properties are dirty based on their alias,
/// otherwise False
/// </returns>
public override bool WasPropertyDirty(string propertyName)
{
bool existsInEntity = base.WasPropertyDirty(propertyName);
if (existsInEntity)
return true;
if (Properties.Contains(propertyName))
{
return Properties[propertyName].WasDirty();
}
return false;
}
#endregion
}
}
+24 -8
View File
@@ -77,10 +77,9 @@ namespace Umbraco.Core.Models
/// </remarks>
internal static bool RequiresSaving(this IContent entity, PublishedState publishedState)
{
var dirtyEntity = (ICanBeDirty)entity;
var publishedChanged = dirtyEntity.IsPropertyDirty("Published") && publishedState != PublishedState.Unpublished;
var publishedChanged = entity.IsPropertyDirty("Published") && publishedState != PublishedState.Unpublished;
//check if any user prop has changed
var propertyValueChanged = ((Content)entity).IsAnyUserPropertyDirty();
var propertyValueChanged = entity.IsAnyUserPropertyDirty();
//We need to know if any other property apart from Published was changed here
//don't create a new version if the published state has changed to 'Save' but no data has actually been changed
@@ -114,6 +113,25 @@ namespace Umbraco.Core.Models
return ShouldCreateNewVersion(entity, publishedState);
}
/// <summary>
/// Returns a list of all dirty user defined properties
/// </summary>
/// <returns></returns>
public static IEnumerable<string> GetDirtyUserProperties(this IContentBase entity)
{
return entity.Properties.Where(x => x.IsDirty()).Select(x => x.Alias);
}
public static bool IsAnyUserPropertyDirty(this IContentBase entity)
{
return entity.Properties.Any(x => x.IsDirty());
}
public static bool WasAnyUserPropertyDirty(this IContentBase entity)
{
return entity.Properties.Any(x => x.WasDirty());
}
/// <summary>
/// Determines if a new version should be created
/// </summary>
@@ -128,15 +146,13 @@ namespace Umbraco.Core.Models
/// </remarks>
internal static bool ShouldCreateNewVersion(this IContent entity, PublishedState publishedState)
{
var dirtyEntity = (ICanBeDirty)entity;
//check if the published state has changed or the language
var publishedChanged = dirtyEntity.IsPropertyDirty("Published") && publishedState != PublishedState.Unpublished;
var langChanged = dirtyEntity.IsPropertyDirty("Language");
var publishedChanged = entity.IsPropertyDirty("Published") && publishedState != PublishedState.Unpublished;
var langChanged = entity.IsPropertyDirty("Language");
var contentChanged = publishedChanged || langChanged;
//check if any user prop has changed
var propertyValueChanged = ((Content)entity).IsAnyUserPropertyDirty();
var propertyValueChanged = entity.IsAnyUserPropertyDirty();
//return true if published or language has changed
if (contentChanged)
@@ -78,7 +78,7 @@ namespace Umbraco.Core.Models.EntityBase
/// Indicates that the entity had been changed and the changes were committed
/// </summary>
/// <returns></returns>
public bool WasDirty()
public virtual bool WasDirty()
{
return _lastPropertyChangedInfo != null && _lastPropertyChangedInfo.Any();
}
@@ -4,6 +4,7 @@ using System.Configuration.Provider;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.Configuration;
using System.Web.Hosting;
using System.Web.Security;
@@ -893,5 +894,15 @@ namespace Umbraco.Core.Security
return sb.ToString();
}
/// <summary>
/// Returns the current request IP address for logging if there is one
/// </summary>
/// <returns></returns>
protected string GetCurrentRequestIpAddress()
{
var httpContext = HttpContext.Current == null ? (HttpContextBase) null : new HttpContextWrapper(HttpContext.Current);
return httpContext.GetCurrentRequestIpAddress();
}
}
}
+81 -1
View File
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using Umbraco.Core.Cache;
using Umbraco.Core.CodeAnnotations;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
@@ -19,12 +20,13 @@ namespace Umbraco.Core.Services
private readonly IMediaService _mediaService;
private readonly IMemberService _memberService;
private readonly IMemberTypeService _memberTypeService;
private readonly IRuntimeCacheProvider _runtimeCache;
private readonly IDataTypeService _dataTypeService;
private readonly Dictionary<string, Tuple<UmbracoObjectTypes, Func<int, IUmbracoEntity>>> _supportedObjectTypes;
public EntityService(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory,
IContentService contentService, IContentTypeService contentTypeService, IMediaService mediaService, IDataTypeService dataTypeService,
IMemberService memberService, IMemberTypeService memberTypeService)
IMemberService memberService, IMemberTypeService memberTypeService, IRuntimeCacheProvider runtimeCache)
{
_uowProvider = provider;
_repositoryFactory = repositoryFactory;
@@ -34,6 +36,7 @@ namespace Umbraco.Core.Services
_dataTypeService = dataTypeService;
_memberService = memberService;
_memberTypeService = memberTypeService;
_runtimeCache = runtimeCache;
_supportedObjectTypes = new Dictionary<string, Tuple<UmbracoObjectTypes, Func<int, IUmbracoEntity>>>
{
@@ -45,6 +48,83 @@ namespace Umbraco.Core.Services
{typeof (IMember).FullName, new Tuple<UmbracoObjectTypes, Func<int, IUmbracoEntity>>(UmbracoObjectTypes.Member, _memberService.GetById)},
{typeof (IMemberType).FullName, new Tuple<UmbracoObjectTypes, Func<int, IUmbracoEntity>>(UmbracoObjectTypes.MemberType, _memberTypeService.Get)}
};
}
/// <summary>
/// Returns the integer id for a given GUID
/// </summary>
/// <param name="key"></param>
/// <param name="umbracoObjectType"></param>
/// <returns></returns>
public Attempt<int> GetIdForKey(Guid key, UmbracoObjectTypes umbracoObjectType)
{
var result = _runtimeCache.GetCacheItem<int?>(CacheKeys.IdToKeyCacheKey + key, () =>
{
using (var uow = _uowProvider.GetUnitOfWork())
{
switch (umbracoObjectType)
{
case UmbracoObjectTypes.Document:
case UmbracoObjectTypes.MemberType:
case UmbracoObjectTypes.Media:
case UmbracoObjectTypes.Template:
case UmbracoObjectTypes.MediaType:
case UmbracoObjectTypes.DocumentType:
case UmbracoObjectTypes.Member:
case UmbracoObjectTypes.DataType:
return uow.Database.ExecuteScalar<int?>(new Sql().Select("id").From<NodeDto>().Where<NodeDto>(dto => dto.UniqueId == key));
case UmbracoObjectTypes.RecycleBin:
case UmbracoObjectTypes.Stylesheet:
case UmbracoObjectTypes.MemberGroup:
case UmbracoObjectTypes.ContentItem:
case UmbracoObjectTypes.ContentItemType:
case UmbracoObjectTypes.ROOT:
case UmbracoObjectTypes.Unknown:
default:
throw new NotSupportedException();
}
}
});
return result.HasValue ? Attempt.Succeed(result.Value) : Attempt<int>.Fail();
}
/// <summary>
/// Returns the GUID for a given integer id
/// </summary>
/// <param name="id"></param>
/// <param name="umbracoObjectType"></param>
/// <returns></returns>
public Attempt<Guid> GetKeyForId(int id, UmbracoObjectTypes umbracoObjectType)
{
var result = _runtimeCache.GetCacheItem<Guid?>(CacheKeys.KeyToIdCacheKey + id, () =>
{
using (var uow = _uowProvider.GetUnitOfWork())
{
switch (umbracoObjectType)
{
case UmbracoObjectTypes.Document:
case UmbracoObjectTypes.MemberType:
case UmbracoObjectTypes.Media:
case UmbracoObjectTypes.Template:
case UmbracoObjectTypes.MediaType:
case UmbracoObjectTypes.DocumentType:
case UmbracoObjectTypes.Member:
case UmbracoObjectTypes.DataType:
return uow.Database.ExecuteScalar<Guid?>(new Sql().Select("uniqueID").From<NodeDto>().Where<NodeDto>(dto => dto.NodeId == id));
case UmbracoObjectTypes.RecycleBin:
case UmbracoObjectTypes.Stylesheet:
case UmbracoObjectTypes.MemberGroup:
case UmbracoObjectTypes.ContentItem:
case UmbracoObjectTypes.ContentItemType:
case UmbracoObjectTypes.ROOT:
case UmbracoObjectTypes.Unknown:
default:
throw new NotSupportedException();
}
}
});
return result.HasValue ? Attempt.Succeed(result.Value) : Attempt<Guid>.Fail();
}
public IUmbracoEntity GetByKey(Guid key, bool loadBaseType = true)
@@ -7,6 +7,21 @@ namespace Umbraco.Core.Services
{
public interface IEntityService
{
/// <summary>
/// Returns the integer id for a given GUID
/// </summary>
/// <param name="key"></param>
/// <param name="umbracoObjectType"></param>
/// <returns></returns>
Attempt<int> GetIdForKey(Guid key, UmbracoObjectTypes umbracoObjectType);
/// <summary>
/// Returns the GUID for a given integer id
/// </summary>
/// <param name="id"></param>
/// <param name="umbracoObjectType"></param>
/// <returns></returns>
Attempt<Guid> GetKeyForId(int id, UmbracoObjectTypes umbracoObjectType);
/// <summary>
/// Gets an UmbracoEntity by its Id, and optionally loads the complete object graph.
@@ -85,14 +85,14 @@ namespace Umbraco.Core.Services
}
//get the lazy value from cache
result.Add(culture, new Lazy<XDocument>(() => _cache.GetCacheItem<XDocument>(
string.Format("{0}-{1}", typeof(LocalizedTextServiceFileSources).Name, culture.Name), () =>
result[culture] = new Lazy<XDocument>(() => _cache.GetCacheItem<XDocument>(
string.Format("{0}-{1}", typeof (LocalizedTextServiceFileSources).Name, culture.Name), () =>
{
using (var fs = localCopy.OpenRead())
{
return XDocument.Load(fs);
}
}, isSliding: true, timeout: TimeSpan.FromMinutes(10), dependentFiles: new[] { localCopy.FullName })));
}, isSliding: true, timeout: TimeSpan.FromMinutes(10), dependentFiles: new[] {localCopy.FullName}));
}
return result;
});
+2 -1
View File
@@ -167,7 +167,8 @@ namespace Umbraco.Core.Services
if (_entityService == null)
_entityService = new Lazy<IEntityService>(() => new EntityService(
provider, repositoryFactory.Value,
_contentService.Value, _contentTypeService.Value, _mediaService.Value, _dataTypeService.Value, _memberService.Value, _memberTypeService.Value));
_contentService.Value, _contentTypeService.Value, _mediaService.Value, _dataTypeService.Value, _memberService.Value, _memberTypeService.Value,
cache.RuntimeCache));
if (_relationService == null)
_relationService = new Lazy<IRelationService>(() => new RelationService(provider, repositoryFactory.Value, _entityService.Value));
+27 -2
View File
@@ -1,4 +1,5 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using Umbraco.Core.Events;
@@ -207,6 +208,9 @@ namespace Umbraco.Core.Services
}
}
//TODO: Remove this in 7.3, we need to track this in a db column!
private readonly ConcurrentDictionary<int, int> _failedLoginAttempts = new ConcurrentDictionary<int, int>();
/// <summary>
/// Get an <see cref="IUser"/> by username
/// </summary>
@@ -217,7 +221,18 @@ namespace Umbraco.Core.Services
using (var repository = _repositoryFactory.CreateUserRepository(_uowProvider.GetUnitOfWork()))
{
var query = Query<IUser>.Builder.Where(x => x.Username.Equals(username));
return repository.GetByQuery(query).FirstOrDefault();
var user = repository.GetByQuery(query).FirstOrDefault();
if (user != null)
{
//check if they have any failed logins and merge
int failedAttempts;
if (_failedLoginAttempts.TryGetValue(user.Id, out failedAttempts))
{
user.FailedPasswordAttempts = failedAttempts;
}
}
return user;
}
}
@@ -284,6 +299,9 @@ namespace Umbraco.Core.Services
}
else
{
int failedAttempts;
_failedLoginAttempts.TryRemove(user.Id, out failedAttempts);
if (DeletingUser.IsRaisedEventCancelled(new DeleteEventArgs<IUser>(user), this))
return;
@@ -317,6 +335,8 @@ namespace Umbraco.Core.Services
{
repository.AddOrUpdate(entity);
uow.Commit();
_failedLoginAttempts.AddOrUpdate(entity.Id, i => entity.FailedPasswordAttempts, (i, i1) => entity.FailedPasswordAttempts);
}
if (raiseEvents)
@@ -342,10 +362,15 @@ namespace Umbraco.Core.Services
{
foreach (var member in entities)
{
repository.AddOrUpdate(member);
repository.AddOrUpdate(member);
}
//commit the whole lot in one go
uow.Commit();
foreach (var member in entities)
{
_failedLoginAttempts.AddOrUpdate(member.Id, i => member.FailedPasswordAttempts, (i, i1) => member.FailedPasswordAttempts);
}
}
if (raiseEvents)
+3 -1
View File
@@ -64,7 +64,7 @@
</Reference>
<Reference Include="MySql.Data">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\MySql.Data.6.6.5\lib\net40\MySql.Data.dll</HintPath>
<HintPath>..\packages\MySql.Data.6.9.6\lib\net45\MySql.Data.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
@@ -313,6 +313,7 @@
<Compile Include="Events\SendToPublishEventArgs.cs" />
<Compile Include="Exceptions\InvalidCompositionException.cs" />
<Compile Include="HideFromTypeFinderAttribute.cs" />
<Compile Include="HttpContextExtensions.cs" />
<Compile Include="IApplicationEventHandler.cs" />
<Compile Include="IDisposeOnRequestEnd.cs" />
<Compile Include="Manifest\GridEditorConverter.cs" />
@@ -1216,6 +1217,7 @@
<Compile Include="WriteLock.cs" />
<Compile Include="XmlExtensions.cs" />
<Compile Include="XmlHelper.cs" />
<Compile Include="Xml\UmbracoXPathPathSyntaxParser.cs" />
<Compile Include="Xml\XPath\MacroNavigator.cs" />
<Compile Include="Xml\XPath\INavigableContentType.cs" />
<Compile Include="Xml\XPath\NavigableNavigator.cs" />
@@ -0,0 +1,117 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Umbraco.Core.Xml
{
/// <summary>
/// This is used to parse our customize Umbraco XPath expressions (i.e. that include special tokens like $site) into
/// a real XPath statement
/// </summary>
internal class UmbracoXPathPathSyntaxParser
{
/// <summary>
/// Parses custom umbraco xpath expression
/// </summary>
/// <param name="xpathExpression">The Xpath expression</param>
/// <param name="nodeContextId">
/// The current node id context of executing the query - null if there is no current node, in which case
/// some of the parameters like $current, $parent, $site will be disabled
/// </param>
/// <param name="getPath">The callback to create the nodeId path, given a node Id</param>
/// <param name="publishedContentExists">The callback to return whether a published node exists based on Id</param>
/// <returns></returns>
public static string ParseXPathQuery(
string xpathExpression,
int? nodeContextId,
Func<int, IEnumerable<string>> getPath,
Func<int, bool> publishedContentExists)
{
//TODO: This should probably support some of the old syntax and token replacements, currently
// it does not, there is a ticket raised here about it: http://issues.umbraco.org/issue/U4-6364
// previous tokens were: "$currentPage", "$ancestorOrSelf", "$parentPage" and I beleive they were
// allowed 'inline', not just at the beginning... whether or not we want to support that is up
// for discussion.
Mandate.ParameterNotNullOrEmpty(xpathExpression, "xpathExpression");
Mandate.ParameterNotNull(getPath, "getPath");
Mandate.ParameterNotNull(publishedContentExists, "publishedContentExists");
//no need to parse it
if (xpathExpression.StartsWith("$") == false)
return xpathExpression;
//get nearest published item
Func<IEnumerable<string>, int> getClosestPublishedAncestor = (path =>
{
foreach (var i in path)
{
int idAsInt;
if (int.TryParse(i, out idAsInt))
{
var exists = publishedContentExists(int.Parse(i));
if (exists)
return idAsInt;
}
}
return -1;
});
const string rootXpath = "descendant::*[@id={0}]";
//parseable items:
var vars = new Dictionary<string, Func<string, string>>();
//These parameters must have a node id context
if (nodeContextId.HasValue)
{
vars.Add("$current", q =>
{
var closestPublishedAncestorId = getClosestPublishedAncestor(getPath(nodeContextId.Value));
return q.Replace("$current", string.Format(rootXpath, closestPublishedAncestorId));
});
vars.Add("$parent", q =>
{
//remove the first item in the array if its the current node
//this happens when current is published, but we are looking for its parent specifically
var path = getPath(nodeContextId.Value).ToArray();
if (path[0] == nodeContextId.ToString())
{
path = path.Skip(1).ToArray();
}
var closestPublishedAncestorId = getClosestPublishedAncestor(path);
return q.Replace("$parent", string.Format(rootXpath, closestPublishedAncestorId));
});
vars.Add("$site", q =>
{
var closestPublishedAncestorId = getClosestPublishedAncestor(getPath(nodeContextId.Value));
return q.Replace("$site", string.Format(rootXpath, closestPublishedAncestorId) + "/ancestor-or-self::*[@level = 1]");
});
}
//TODO: This used to just replace $root with string.Empty BUT, that would never work
// the root is always "/root . Need to confirm with Per why this was string.Empty before!
vars.Add("$root", q => q.Replace("$root", "/root"));
foreach (var varible in vars)
{
if (xpathExpression.StartsWith(varible.Key))
{
xpathExpression = varible.Value(xpathExpression);
break;
}
}
return xpathExpression;
}
}
}
+16 -16
View File
@@ -1,19 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AutoMapper" version="3.0.0" targetFramework="net45" />
<package id="HtmlAgilityPack" version="1.4.6" targetFramework="net45" />
<package id="log4net-mediumtrust" version="2.0.0" targetFramework="net40" />
<package id="Microsoft.AspNet.Mvc" version="4.0.30506.0" targetFramework="net40" />
<package id="Microsoft.AspNet.Razor" version="2.0.30506.0" targetFramework="net40" />
<package id="Microsoft.AspNet.WebApi.Client" version="4.0.30506.0" targetFramework="net45" />
<package id="Microsoft.AspNet.WebPages" version="2.0.30506.0" targetFramework="net40" />
<package id="Microsoft.Bcl" version="1.1.9" targetFramework="net45" />
<package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net45" />
<package id="Microsoft.Net.Http" version="2.2.22" targetFramework="net45" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net40" />
<package id="MiniProfiler" version="2.1.0" targetFramework="net45" />
<package id="MySql.Data" version="6.6.5" targetFramework="net40" />
<package id="Newtonsoft.Json" version="6.0.4" targetFramework="net45" />
<package id="SharpZipLib" version="0.86.0" targetFramework="net40" />
<package id="SqlServerCE" version="4.0.0.0" targetFramework="net40" />
<package id="AutoMapper" version="3.0.0" targetFramework="net45" userInstalled="true" />
<package id="HtmlAgilityPack" version="1.4.6" targetFramework="net45" userInstalled="true" />
<package id="log4net-mediumtrust" version="2.0.0" targetFramework="net4" userInstalled="true" />
<package id="Microsoft.AspNet.Mvc" version="4.0.30506.0" targetFramework="net4" userInstalled="true" />
<package id="Microsoft.AspNet.Razor" version="2.0.30506.0" targetFramework="net4" userInstalled="true" />
<package id="Microsoft.AspNet.WebApi.Client" version="4.0.30506.0" targetFramework="net45" userInstalled="true" />
<package id="Microsoft.AspNet.WebPages" version="2.0.30506.0" targetFramework="net4" userInstalled="true" />
<package id="Microsoft.Bcl" version="1.1.9" targetFramework="net45" userInstalled="true" />
<package id="Microsoft.Bcl.Build" version="1.0.14" targetFramework="net45" userInstalled="true" />
<package id="Microsoft.Net.Http" version="2.2.22" targetFramework="net45" userInstalled="true" />
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net4" userInstalled="true" />
<package id="MiniProfiler" version="2.1.0" targetFramework="net45" userInstalled="true" />
<package id="MySql.Data" version="6.9.6" targetFramework="net45" userInstalled="true" />
<package id="Newtonsoft.Json" version="6.0.4" targetFramework="net45" userInstalled="true" />
<package id="SharpZipLib" version="0.86.0" targetFramework="net4" userInstalled="true" />
<package id="SqlServerCE" version="4.0.0.0" targetFramework="net4" userInstalled="true" />
</packages>
+79 -1
View File
@@ -1,4 +1,5 @@
using System.Linq;
using System;
using System.Linq;
using System.Web.UI;
using NUnit.Framework;
using Umbraco.Core.Cache;
@@ -21,6 +22,83 @@ namespace Umbraco.Tests.Cache
public virtual void TearDown()
{
Provider.ClearAllCache();
}
[Test]
public void Throws_On_Reentry()
{
// don't run for StaticCacheProvider - not making sense
if (GetType() == typeof (StaticCacheProviderTests))
Assert.Ignore("Do not run for StaticCacheProvider.");
Exception exception = null;
var result = Provider.GetCacheItem("blah", () =>
{
try
{
var result2 = Provider.GetCacheItem("blah");
}
catch (Exception e)
{
exception = e;
}
return "value";
});
Assert.IsNotNull(exception);
Assert.IsAssignableFrom<InvalidOperationException>(exception);
}
[Test]
public void Does_Not_Cache_Exceptions()
{
var counter = 0;
object result;
try
{
result = Provider.GetCacheItem("Blah", () =>
{
counter++;
throw new Exception("Do not cache this");
});
}
catch (Exception){}
try
{
result = Provider.GetCacheItem("Blah", () =>
{
counter++;
throw new Exception("Do not cache this");
});
}
catch (Exception){}
Assert.Greater(counter, 1);
}
[Test]
public void Ensures_Delegate_Result_Is_Cached_Once()
{
var counter = 0;
object result;
result = Provider.GetCacheItem("Blah", () =>
{
counter++;
return "";
});
result = Provider.GetCacheItem("Blah", () =>
{
counter++;
return "";
});
Assert.AreEqual(counter, 1);
}
[Test]
@@ -1,4 +1,5 @@
using System.Web;
using System;
using System.Web;
using NUnit.Framework;
using Umbraco.Core.Cache;
@@ -29,5 +30,29 @@ namespace Umbraco.Tests.Cache
{
get { return _provider; }
}
[Test]
public void DoesNotCacheExceptions()
{
string value;
Assert.Throws<Exception>(() => { value = (string)_provider.GetCacheItem("key", () => GetValue(1)); });
Assert.Throws<Exception>(() => { value = (string)_provider.GetCacheItem("key", () => GetValue(2)); });
// does not throw
value = (string)_provider.GetCacheItem("key", () => GetValue(3));
Assert.AreEqual("succ3", value);
// cache
value = (string)_provider.GetCacheItem("key", () => GetValue(4));
Assert.AreEqual("succ3", value);
}
private static string GetValue(int i)
{
Console.WriteLine("get" + i);
if (i < 3)
throw new Exception("fail");
return "succ" + i;
}
}
}
@@ -28,10 +28,16 @@ namespace Umbraco.Tests.Configurations.UmbracoSettings
Assert.IsTrue(SettingsSection.Content.Error404Collection.Count() == 3);
Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(0).Culture == "default");
Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(0).ContentId == 1047);
Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(0).HasContentId);
Assert.IsFalse(SettingsSection.Content.Error404Collection.ElementAt(0).HasContentKey);
Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(1).Culture == "en-US");
Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(1).ContentId == 1048);
Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(1).ContentXPath == "$site/error [@name = 'error']");
Assert.IsFalse(SettingsSection.Content.Error404Collection.ElementAt(1).HasContentId);
Assert.IsFalse(SettingsSection.Content.Error404Collection.ElementAt(1).HasContentKey);
Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(2).Culture == "en-UK");
Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(2).ContentId == 1049);
Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(2).ContentKey == new Guid("8560867F-B88F-4C74-A9A4-679D8E5B3BFC"));
Assert.IsTrue(SettingsSection.Content.Error404Collection.ElementAt(2).HasContentKey);
Assert.IsFalse(SettingsSection.Content.Error404Collection.ElementAt(2).HasContentId);
}
[Test]
@@ -42,8 +42,8 @@
</error404>-->
<error404>
<errorPage culture="default">1047</errorPage>
<errorPage culture="en-US">1048</errorPage>
<errorPage culture="en-UK">1049</errorPage>
<errorPage culture="en-US">$site/error [@name = 'error']</errorPage>
<errorPage culture="en-UK">8560867F-B88F-4C74-A9A4-679D8E5B3BFC</errorPage>
</error404>
<!--<error404>1</error404>-->
</errors>
@@ -109,6 +109,29 @@ namespace Umbraco.Tests.Macros
<p>asdfasdf</p>".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty));
}
[Test]
public void Format_RTE_Data_For_Editor_With_Params_When_MacroAlias_Not_First()
{
var content = @"<p>asdfasdf</p>
<p>asdfsadf</p>
<?UMBRACO_MACRO test1=""value1"" test2=""value2"" macroAlias=""Map"" />
<p>asdfasdf</p>";
var result = MacroTagParser.FormatRichTextPersistedDataForEditor(content, new Dictionary<string, string>() { { "test1", "value1" }, { "test2", "value2" } });
// Assert.AreEqual(@"<p>asdfasdf</p>
//<p>asdfsadf</p>
//<div class=""umb-macro-holder Map mceNonEditable"" test1=""value1"" test2=""value2"">
//<!-- <?UMBRACO_MACRO macroAlias=""Map"" test1=""value1"" test2=""value2"" /> -->
//<ins>Macro alias: <strong>Map</strong></ins></div>
//<p>asdfasdf</p>".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty));
Assert.AreEqual(@"<p>asdfasdf</p>
<p>asdfsadf</p>
<div class=""umb-macro-holder mceNonEditable"" test1=""value1"" test2=""value2"">
<!-- <?UMBRACO_MACRO test1=""value1"" test2=""value2"" macroAlias=""Map"" /> -->
<ins>Macro alias: <strong>Map</strong></ins></div>
<p>asdfasdf</p>".Replace(Environment.NewLine, string.Empty), result.Replace(Environment.NewLine, string.Empty));
}
[Test]
public void Format_RTE_Data_For_Editor_With_Params_Closing_Tag()
{
+31
View File
@@ -701,6 +701,37 @@ namespace Umbraco.Tests.Models
Assert.That(contentType.WasPropertyDirty("Alias"), Is.True);
}
[Test]
public void After_Committing_Changes_Was_Dirty_Is_True_On_Changed_Property()
{
// Arrange
var contentType = MockedContentTypes.CreateTextpageContentType();
contentType.ResetDirtyProperties(); //reset
var content = MockedContent.CreateTextpageContent(contentType, "test", -1);
content.ResetDirtyProperties();
// Act
content.SetPropertyValue("title", "new title");
Assert.That(content.IsEntityDirty(), Is.False);
Assert.That(content.IsDirty(), Is.True);
Assert.That(content.IsPropertyDirty("title"), Is.True);
Assert.That(content.IsAnyUserPropertyDirty(), Is.True);
Assert.That(content.GetDirtyUserProperties().Count(), Is.EqualTo(1));
Assert.That(content.Properties[0].IsDirty(), Is.True);
Assert.That(content.Properties["title"].IsDirty(), Is.True);
content.ResetDirtyProperties(); //this would be like committing the entity
// Assert
Assert.That(content.WasDirty(), Is.True);
Assert.That(content.Properties[0].WasDirty(), Is.True);
Assert.That(content.WasPropertyDirty("title"), Is.True);
Assert.That(content.Properties["title"].IsDirty(), Is.False);
Assert.That(content.Properties["title"].WasDirty(), Is.True);
}
[Test]
public void If_Not_Committed_Was_Dirty_Is_False()
{
@@ -21,17 +21,29 @@ namespace Umbraco.Tests.Scheduling
TestHelper.SetupLog4NetForTests();
}
/*
[Test]
public async void ShutdownWaitWhenRunning()
{
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions { AutoStart = true, KeepAlive = true }))
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions
{
Assert.IsTrue(runner.IsRunning);
Thread.Sleep(800); // for long
Assert.IsTrue(runner.IsRunning);
AutoStart = true,
KeepAlive = true
}))
{
var stopped = false;
runner.Stopped += (sender, args) => { stopped = true; };
Assert.IsTrue(runner.IsRunning); // because AutoStart is true
Thread.Sleep(500); // and because KeepAlive is true...
Assert.IsTrue(runner.IsRunning); // ...it keeps running
runner.Shutdown(false, true); // -force +wait
await runner; // wait for the entire runner operation to complete
Assert.IsTrue(runner.IsCompleted);
await runner.StoppedAwaitable; // runner stops, within test's timeout
Assert.IsTrue(runner.IsCompleted); // shutdown completes the runner
Assert.IsFalse(runner.IsRunning); // no more running tasks
Assert.IsTrue(stopped);
}
}
@@ -44,38 +56,121 @@ namespace Umbraco.Tests.Scheduling
runner.TaskStarting += (sender, args) => Console.WriteLine("starting {0}", DateTime.Now);
runner.TaskCompleted += (sender, args) => Console.WriteLine("completed {0}", DateTime.Now);
runner.Stopped += (sender, args) => Console.WriteLine("stopped {0}", DateTime.Now);
Assert.IsFalse(runner.IsRunning);
Assert.IsFalse(runner.IsRunning); // because AutoStart is false
Console.WriteLine("Adding task {0}", DateTime.Now);
runner.Add(new MyTask(5000));
Thread.Sleep(500);
Assert.IsTrue(runner.IsRunning); // is running the task
Console.WriteLine("Shutting down {0}", DateTime.Now);
runner.Shutdown(false, false); // -force -wait
Assert.IsTrue(runner.IsCompleted);
Assert.IsTrue(runner.IsCompleted); // shutdown completes the runner
Assert.IsTrue(runner.IsRunning); // still running that task
Thread.Sleep(3000); // wait slightly less than the task takes to complete
Assert.IsTrue(runner.IsRunning); // still running that task
await runner; // wait for the entire runner operation to complete
await runner.StoppedAwaitable; // runner stops, within test's timeout
Console.WriteLine("End {0}", DateTime.Now);
}
}
*/
[Test]
public async void ShutdownWhenRunningWithWait()
{
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions()))
{
var stopped = false;
runner.Stopped += (sender, args) => { stopped = true; };
Assert.IsFalse(runner.IsRunning); // because AutoStart is false
runner.Add(new MyTask(5000));
Assert.IsTrue(runner.IsRunning); // is running the task
runner.Shutdown(false, true); // -force +wait
// all this before we await because +wait
Assert.IsTrue(runner.IsCompleted); // shutdown completes the runner
Assert.IsFalse(runner.IsRunning); // no more running tasks
Assert.IsTrue(stopped);
await runner.StoppedAwaitable; // runner stops, within test's timeout
}
}
[Test]
public async void ShutdownWhenRunningWithoutWait()
{
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions()))
{
var stopped = false;
runner.Stopped += (sender, args) => { stopped = true; };
Assert.IsFalse(runner.IsRunning); // because AutoStart is false
runner.Add(new MyTask(5000));
Assert.IsTrue(runner.IsRunning); // is running the task
runner.Shutdown(false, false); // -force +wait
// all this before we await because -wait
Assert.IsTrue(runner.IsCompleted); // shutdown completes the runner
Assert.IsTrue(runner.IsRunning); // still running the task
Assert.IsFalse(stopped);
await runner.StoppedAwaitable; // runner stops, within test's timeout
// and then...
Assert.IsFalse(runner.IsRunning); // no more running tasks
Assert.IsTrue(stopped);
}
}
[Test]
public async void ShutdownCompletesTheRunner()
{
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions()))
{
Assert.IsFalse(runner.IsRunning); // because AutoStart is false
// shutdown -force => run all queued tasks
runner.Shutdown(false, false); // -force -wait
await runner.StoppedAwaitable; // runner stops, within test's timeout
Assert.IsFalse(runner.IsRunning); // still not running anything
Assert.IsTrue(runner.IsCompleted); // shutdown completes the runner
// cannot add tasks to it anymore
Assert.IsFalse(runner.TryAdd(new MyTask()));
Assert.Throws<InvalidOperationException>(() =>
{
runner.Add(new MyTask());
});
}
}
[Test]
public async void ShutdownFlushesTheQueue()
{
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions()))
{
Assert.IsFalse(runner.IsRunning);
MyTask t;
Assert.IsFalse(runner.IsRunning); // because AutoStart is false
runner.Add(new MyTask(5000));
runner.Add(new MyTask());
var t = new MyTask();
runner.Add(t);
Assert.IsTrue(runner.IsRunning); // is running the first task
runner.Add(t = new MyTask());
Assert.IsTrue(runner.IsRunning); // is running tasks
// shutdown -force => run all queued tasks
runner.Shutdown(false, false); // -force -wait
await runner; // wait for the entire runner operation to complete
Assert.IsTrue(runner.IsRunning); // is running tasks
await runner.StoppedAwaitable; // runner stops, within test's timeout
Assert.AreNotEqual(DateTime.MinValue, t.Ended); // t has run
}
}
@@ -85,15 +180,20 @@ namespace Umbraco.Tests.Scheduling
{
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions()))
{
Assert.IsFalse(runner.IsRunning);
MyTask t;
Assert.IsFalse(runner.IsRunning); // because AutoStart is false
runner.Add(new MyTask(5000));
runner.Add(new MyTask());
var t = new MyTask();
runner.Add(t);
Assert.IsTrue(runner.IsRunning); // is running the first task
runner.Add(t = new MyTask());
Assert.IsTrue(runner.IsRunning); // is running tasks
// shutdown +force => tries to cancel the current task, ignores queued tasks
runner.Shutdown(true, false); // +force -wait
await runner; // wait for the entire runner operation to complete
Assert.AreEqual(DateTime.MinValue, t.Ended); // t has not run
Assert.IsTrue(runner.IsRunning); // is running that long task it cannot cancel
await runner.StoppedAwaitable; // runner stops, within test's timeout
Assert.AreEqual(DateTime.MinValue, t.Ended); // t has *not* run
}
}
@@ -102,23 +202,106 @@ namespace Umbraco.Tests.Scheduling
{
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions()))
{
Assert.IsFalse(runner.IsRunning);
Assert.IsFalse(runner.IsRunning); // because AutoStart is false
runner.Add(new MyTask(5000));
runner.Add(new MyTask());
runner.Add(new MyTask());
Assert.IsTrue(runner.IsRunning); // is running the task
Assert.IsTrue(runner.IsRunning); // is running tasks
// shutdown -force => run all queued tasks
runner.Shutdown(false, false); // -force -wait
Assert.IsTrue(runner.IsCompleted);
Assert.IsTrue(runner.IsRunning); // still running that task
Assert.IsTrue(runner.IsCompleted); // shutdown completes the runner
Assert.IsTrue(runner.IsRunning); // still running a task
Thread.Sleep(3000);
Assert.IsTrue(runner.IsRunning); // still running that task
Assert.IsTrue(runner.IsRunning); // still running a task
// shutdown +force => tries to cancel the current task, ignores queued tasks
runner.Shutdown(true, false); // +force -wait
await runner; // wait for the entire runner operation to complete
await runner.StoppedAwaitable; // runner stops, within test's timeout
}
}
[Test]
public async void HostingStopNonImmediate()
{
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions()))
{
MyTask t;
var stopped = false;
runner.Stopped += (sender, args) => { stopped = true; };
var terminating = false;
runner.Terminating += (sender, args) => { terminating = true; };
var terminated = false;
runner.Terminated += (sender, args) => { terminated = true; };
Assert.IsFalse(runner.IsRunning); // because AutoStart is false
runner.Add(new MyTask(5000));
runner.Add(new MyTask());
runner.Add(t = new MyTask());
Assert.IsTrue(runner.IsRunning); // is running the task
runner.Stop(false); // -immediate = -force, -wait
Assert.IsTrue(terminating); // has raised that event
Assert.IsFalse(terminated); // but not terminated yet
// all this before we await because -wait
Assert.IsTrue(runner.IsCompleted); // shutdown completes the runner
Assert.IsTrue(runner.IsRunning); // still running the task
await runner.StoppedAwaitable; // runner stops, within test's timeout
Assert.IsFalse(runner.IsRunning);
Assert.IsTrue(stopped);
await runner.TerminatedAwaitable; // runner terminates, within test's timeout
Assert.IsTrue(terminated); // has raised that event
Assert.AreNotEqual(DateTime.MinValue, t.Ended); // t has run
}
}
[Test]
public void Create_IsRunning()
public async void HostingStopImmediate()
{
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions()))
{
MyTask t;
var stopped = false;
runner.Stopped += (sender, args) => { stopped = true; };
var terminating = false;
runner.Terminating += (sender, args) => { terminating = true; };
var terminated = false;
runner.Terminated += (sender, args) => { terminated = true; };
Assert.IsFalse(runner.IsRunning); // because AutoStart is false
runner.Add(new MyTask(5000));
runner.Add(new MyTask());
runner.Add(t = new MyTask());
Assert.IsTrue(runner.IsRunning); // is running the task
runner.Stop(true); // +immediate = +force, +wait
Assert.IsTrue(terminating); // has raised that event
Assert.IsTrue(terminated); // and that event
Assert.IsTrue(stopped); // and that one
// and all this before we await because +wait
Assert.IsTrue(runner.IsCompleted); // shutdown completes the runner
Assert.IsFalse(runner.IsRunning); // done running
await runner.StoppedAwaitable; // runner stops, within test's timeout
await runner.TerminatedAwaitable; // runner terminates, within test's timeout
Assert.AreEqual(DateTime.MinValue, t.Ended); // t has *not* run
}
}
[Test]
public void Create_IsNotRunning()
{
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions()))
{
@@ -126,14 +309,17 @@ namespace Umbraco.Tests.Scheduling
}
}
[Ignore]
[Test]
public async void Create_AutoStart_IsRunning()
{
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions { AutoStart = true }))
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions
{
Assert.IsTrue(runner.IsRunning);
await runner; // wait for the entire runner operation to complete
AutoStart = true
}))
{
Assert.IsTrue(runner.IsRunning); // because AutoStart is true
await runner.StoppedAwaitable; // runner stops, within test's timeout
}
}
@@ -142,7 +328,7 @@ namespace Umbraco.Tests.Scheduling
{
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions { AutoStart = true, KeepAlive = true }))
{
Assert.IsTrue(runner.IsRunning);
Assert.IsTrue(runner.IsRunning); // because AutoStart is true
Thread.Sleep(800); // for long
Assert.IsTrue(runner.IsRunning);
// dispose will stop it
@@ -159,8 +345,13 @@ namespace Umbraco.Tests.Scheduling
// dispose will stop it
}
await runner; // wait for the entire runner operation to complete
await runner.StoppedAwaitable; // runner stops, within test's timeout
//await runner.TerminatedAwaitable; // NO! see note below
Assert.Throws<InvalidOperationException>(() => runner.Add(new MyTask()));
// but do NOT await on TerminatedAwaitable - disposing just shuts the runner down
// so that we don't have a runaway task in tests, etc - but it does NOT terminate
// the runner - it really is NOT a nice way to end a runner - it's there for tests
}
[Test]
@@ -188,7 +379,7 @@ namespace Umbraco.Tests.Scheduling
runner.Add(new MyTask());
Assert.IsTrue(runner.IsRunning);
waitHandle.WaitOne();
await runner; //since we are not being kept alive, it will quit
await runner.StoppedAwaitable; //since we are not being kept alive, it will quit
Assert.IsFalse(runner.IsRunning);
}
}
@@ -221,11 +412,11 @@ namespace Umbraco.Tests.Scheduling
runner.Add(task);
await runner.CurrentThreadingTask; // wait for the Task operation to complete
Assert.IsTrue(task.Ended != default(DateTime)); // task is done
await runner; // wait for the entire runner operation to complete
await runner.StoppedAwaitable; // wait for the entire runner operation to complete
}
}
[Ignore]
[Test]
public async void WaitOnRunner_Tasks()
{
@@ -237,7 +428,7 @@ namespace Umbraco.Tests.Scheduling
{
tasks.ForEach(runner.Add);
await runner; // wait for the entire runner operation to complete
await runner.StoppedAwaitable; // wait for the entire runner operation to complete
// check that tasks are done
Assert.IsTrue(tasks.All(x => x.Ended != default(DateTime)));
@@ -260,7 +451,7 @@ namespace Umbraco.Tests.Scheduling
runner.Add(task);
waitHandle.WaitOne(); // wait 'til task is done
Assert.IsTrue(task.Ended != default(DateTime)); // task is done
await runner; // wait for the entire runner operation to complete
await runner.StoppedAwaitable; // wait for the entire runner operation to complete
}
}
@@ -280,7 +471,7 @@ namespace Umbraco.Tests.Scheduling
WaitHandle.WaitAll(tasks.Values.Select(x => (WaitHandle)x).ToArray());
Assert.IsTrue(tasks.All(x => x.Key.Ended != default(DateTime)));
await runner; // wait for the entire runner operation to complete
await runner.StoppedAwaitable; // wait for the entire runner operation to complete
}
}
@@ -382,7 +573,7 @@ namespace Umbraco.Tests.Scheduling
}
}
[Ignore]
[Test]
public void RecurringTaskTest()
{
@@ -422,7 +613,7 @@ namespace Umbraco.Tests.Scheduling
{
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions()))
{
var task = new MyDelayedTask(200);
var task = new MyDelayedTask(200, false);
runner.Add(task);
Assert.IsTrue(runner.IsRunning);
Thread.Sleep(5000);
@@ -431,7 +622,7 @@ namespace Umbraco.Tests.Scheduling
task.Release();
await runner.CurrentThreadingTask; //wait for current task to complete
Assert.IsTrue(task.HasRun);
await runner; // wait for the entire runner operation to complete
await runner.StoppedAwaitable; // wait for the entire runner operation to complete
}
}
@@ -440,19 +631,19 @@ namespace Umbraco.Tests.Scheduling
{
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions()))
{
var task = new MyDelayedTask(200);
var task = new MyDelayedTask(200, true);
runner.Add(task);
Assert.IsTrue(runner.IsRunning);
Thread.Sleep(5000);
Assert.IsTrue(runner.IsRunning); // still waiting for the task to release
Assert.IsFalse(task.HasRun);
runner.Shutdown(false, false);
await runner; // wait for the entire runner operation to complete
await runner.StoppedAwaitable; // wait for the entire runner operation to complete
Assert.IsTrue(task.HasRun);
}
}
[Ignore]
[Test]
public void DelayedRecurring()
{
@@ -478,6 +669,7 @@ namespace Umbraco.Tests.Scheduling
waitHandle.WaitOne();
Assert.GreaterOrEqual(runCount, 4);
Assert.IsTrue(task.HasRun);
// stops recurring
runner.Shutdown(false, false);
@@ -492,10 +684,27 @@ namespace Umbraco.Tests.Scheduling
var exceptions = new ConcurrentQueue<Exception>();
runner.TaskError += (sender, args) => exceptions.Enqueue(args.Exception);
var task = new MyFailingTask(false); // -async
var task = new MyFailingTask(false, true, false); // -async, +running, -disposing
runner.Add(task);
Assert.IsTrue(runner.IsRunning);
await runner; // wait for the entire runner operation to complete
await runner.StoppedAwaitable; // wait for the entire runner operation to complete
Assert.AreEqual(1, exceptions.Count); // traced and reported
}
}
[Test]
public async void FailingTaskDisposing()
{
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions()))
{
var exceptions = new ConcurrentQueue<Exception>();
runner.TaskError += (sender, args) => exceptions.Enqueue(args.Exception);
var task = new MyFailingTask(false, false, true); // -async, -running, +disposing
runner.Add(task);
Assert.IsTrue(runner.IsRunning);
await runner.StoppedAwaitable; // wait for the entire runner operation to complete
Assert.AreEqual(1, exceptions.Count); // traced and reported
}
@@ -509,10 +718,27 @@ namespace Umbraco.Tests.Scheduling
var exceptions = new ConcurrentQueue<Exception>();
runner.TaskError += (sender, args) => exceptions.Enqueue(args.Exception);
var task = new MyFailingTask(true); // +async
var task = new MyFailingTask(true, true, false); // +async, +running, -disposing
runner.Add(task);
Assert.IsTrue(runner.IsRunning);
await runner; // wait for the entire runner operation to complete
await runner.StoppedAwaitable; // wait for the entire runner operation to complete
Assert.AreEqual(1, exceptions.Count); // traced and reported
}
}
[Test]
public async void FailingTaskDisposingAsync()
{
using (var runner = new BackgroundTaskRunner<IBackgroundTask>(new BackgroundTaskRunnerOptions()))
{
var exceptions = new ConcurrentQueue<Exception>();
runner.TaskError += (sender, args) => exceptions.Enqueue(args.Exception);
var task = new MyFailingTask(false, false, true); // -async, -running, +disposing
runner.Add(task);
Assert.IsTrue(runner.IsRunning);
await runner.StoppedAwaitable; // wait for the entire runner operation to complete
Assert.AreEqual(1, exceptions.Count); // traced and reported
}
@@ -521,22 +747,28 @@ namespace Umbraco.Tests.Scheduling
private class MyFailingTask : IBackgroundTask
{
private readonly bool _isAsync;
private readonly bool _running;
private readonly bool _disposing;
public MyFailingTask(bool isAsync)
public MyFailingTask(bool isAsync, bool running, bool disposing)
{
_isAsync = isAsync;
_running = running;
_disposing = disposing;
}
public void Run()
{
Thread.Sleep(1000);
throw new Exception("Task has thrown.");
if (_running)
throw new Exception("Task has thrown.");
}
public async Task RunAsync(CancellationToken token)
{
await Task.Delay(1000);
throw new Exception("Task has thrown.");
if (_running)
throw new Exception("Task has thrown.");
}
public bool IsAsync
@@ -544,13 +776,17 @@ namespace Umbraco.Tests.Scheduling
get { return _isAsync; }
}
// fixme - must also test what happens if we throw on dispose!
public void Dispose()
{ }
{
if (_disposing)
throw new Exception("Task has thrown.");
}
}
private class MyDelayedRecurringTask : DelayedRecurringTaskBase<MyDelayedRecurringTask>
{
public bool HasRun { get; private set; }
public MyDelayedRecurringTask(IBackgroundTaskRunner<MyDelayedRecurringTask> runner, int delayMilliseconds, int periodMilliseconds)
: base(runner, delayMilliseconds, periodMilliseconds)
{ }
@@ -566,7 +802,7 @@ namespace Umbraco.Tests.Scheduling
public override void PerformRun()
{
// nothing to do at the moment
HasRun = true;
}
public override Task PerformRunAsync()
@@ -583,30 +819,28 @@ namespace Umbraco.Tests.Scheduling
private class MyDelayedTask : ILatchedBackgroundTask
{
private readonly int _runMilliseconds;
private readonly ManualResetEvent _gate;
private readonly ManualResetEventSlim _gate;
public bool HasRun { get; private set; }
public MyDelayedTask(int runMilliseconds)
public MyDelayedTask(int runMilliseconds, bool runsOnShutdown)
{
_runMilliseconds = runMilliseconds;
_gate = new ManualResetEvent(false);
_gate = new ManualResetEventSlim(false);
RunsOnShutdown = runsOnShutdown;
}
public WaitHandle Latch
{
get { return _gate; }
get { return _gate.WaitHandle; }
}
public bool IsLatched
{
get { return true; }
get { return _gate.IsSet == false; }
}
public bool RunsOnShutdown
{
get { return true; }
}
public bool RunsOnShutdown { get; private set; }
public void Run()
{
+2 -2
View File
@@ -58,9 +58,9 @@
<Reference Include="AutoMapper.Net4">
<HintPath>..\packages\AutoMapper.3.0.0\lib\net40\AutoMapper.Net4.dll</HintPath>
</Reference>
<Reference Include="Examine, Version=0.1.62.2941, Culture=neutral, processorArchitecture=MSIL">
<Reference Include="Examine, Version=0.1.63.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Examine.0.1.62.2941\lib\Examine.dll</HintPath>
<HintPath>..\packages\Examine.0.1.63.0\lib\Examine.dll</HintPath>
</Reference>
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
+1 -1
View File
@@ -2,7 +2,7 @@
<packages>
<package id="AspNetWebApi.SelfHost" version="4.0.20710.0" targetFramework="net45" />
<package id="AutoMapper" version="3.0.0" targetFramework="net45" />
<package id="Examine" version="0.1.62.2941" targetFramework="net45" />
<package id="Examine" version="0.1.63.0" targetFramework="net45" />
<package id="log4net-mediumtrust" version="2.0.0" targetFramework="net40" />
<package id="Lucene.Net" version="2.9.4.1" targetFramework="net45" />
<package id="Microsoft.AspNet.Mvc" version="4.0.30506.0" targetFramework="net40" />
@@ -229,7 +229,7 @@ textarea {
.radio input[type="radio"],
.checkbox input[type="checkbox"] {
float: left;
margin-left: -20px;
margin-left: 0px;
}
// Move the options list down to align with labels
@@ -9,7 +9,7 @@ LazyLoad.js([
'/Umbraco/js/umbraco.security.js',
'/Umbraco/ServerVariables',
'/Umbraco/lib/spectrum/spectrum.js',
'http://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js',
'https://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js',
'/umbraco/js/canvasdesigner.panel.js',
], function () {
jQuery(document).ready(function () {
@@ -180,7 +180,7 @@ var app = angular.module("Umbraco.canvasdesigner", ['colorpicker', 'ui.slider',
// TODO: special init for font family picker
if (item.type == "googlefontpicker" && item.values.fontFamily) {
var variant = item.values.fontWeight != "" || item.values.fontStyle != "" ? ":" + item.values.fontWeight + item.values.fontStyle : "";
var gimport = "@import url('http://fonts.googleapis.com/css?family=" + item.values.fontFamily + variant + "');";
var gimport = "@import url('https://fonts.googleapis.com/css?family=" + item.values.fontFamily + variant + "');";
if ($.inArray(gimport, parameters) < 0) {
parameters.splice(0, 0, gimport);
}
@@ -412,7 +412,7 @@ var app = angular.module("Umbraco.canvasdesigner", ['colorpicker', 'ui.slider',
var webFontScriptLoaded = false;
var loadGoogleFont = function (font) {
if (!webFontScriptLoaded) {
$.getScript('http://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js')
$.getScript('https://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js')
.done(function () {
webFontScriptLoaded = true;
// Recursively call once webfont script is available.
@@ -19,7 +19,7 @@ var refreshLayout = function (parameters) {
var webFontScriptLoaded = false;
var getFont = function (font) {
if (!webFontScriptLoaded) {
$.getScript('http://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js')
$.getScript('https://ajax.googleapis.com/ajax/libs/webfont/1/webfont.js')
.done(function () {
webFontScriptLoaded = true;
// Recursively call once webfont script is available.
@@ -22,6 +22,9 @@ function sectionsDirective($timeout, $window, navigationService, treeService, se
if (scope.showTray) {
return 'slide';
}
else if (scope.showTray === false) {
return 'slide';
}
else {
return '';
}
@@ -49,26 +52,35 @@ function sectionsDirective($timeout, $window, navigationService, treeService, se
}
});
}
//Listen for global state changes
eventsService.on("appState.globalState.changed", function (e, args) {
if (args.key === "showTray") {
scope.showTray = args.value;
}
if (args.key === "stickyNavigation") {
scope.stickyNavigation = args.value;
}
});
eventsService.on("appState.sectionState.changed", function (e, args) {
if (args.key === "currentSection") {
scope.currentSection = args.value;
}
});
eventsService.on("app.reInitialize", function (e, args) {
var evts = [];
//Listen for global state changes
evts.push(eventsService.on("appState.globalState.changed", function(e, args) {
if (args.key === "showTray") {
scope.showTray = args.value;
}
if (args.key === "stickyNavigation") {
scope.stickyNavigation = args.value;
}
}));
evts.push(eventsService.on("appState.sectionState.changed", function(e, args) {
if (args.key === "currentSection") {
scope.currentSection = args.value;
}
}));
evts.push(eventsService.on("app.reInitialize", function(e, args) {
//re-load the sections if we're re-initializing (i.e. package installed)
loadSections();
loadSections();
}));
//ensure to unregister from all events!
scope.$on('$destroy', function () {
for (var e in evts) {
eventsService.unsubscribe(evts[e]);
}
});
//on page resize
@@ -83,6 +95,13 @@ function sectionsDirective($timeout, $window, navigationService, treeService, se
};
scope.sectionClick = function (section) {
if (navigationService.userDialog) {
navigationService.userDialog.close();
}
if (navigationService.helpDialog) {
navigationService.helpDialog.close();
}
navigationService.hideSearch();
navigationService.showTree(section.alias);
$location.path("/" + section.alias);
@@ -92,8 +111,20 @@ function sectionsDirective($timeout, $window, navigationService, treeService, se
navigationService.reloadSection(section.alias);
};
scope.trayClick = function(){
navigationService.showTray();
scope.trayClick = function () {
// close dialogs
if (navigationService.userDialog) {
navigationService.userDialog.close();
}
if (navigationService.helpDialog) {
navigationService.helpDialog.close();
}
if (appState.getGlobalState("showTray") === true) {
navigationService.hideTray();
} else {
navigationService.showTray();
}
};
loadSections();
@@ -48,23 +48,25 @@ function valFormManager(serverValidationManager, $rootScope, $log, $timeout, not
element.addClass(className);
}
var unsubscribe = [];
//listen for the forms saving event
scope.$on(savingEventName, function (ev, args) {
unsubscribe.push(scope.$on(savingEventName, function(ev, args) {
element.addClass(className);
//set the flag so we can check to see if we should display the error.
isSavingNewItem = $routeParams.create;
});
}));
//listen for the forms saved event
scope.$on(savedEvent, function (ev, args) {
unsubscribe.push(scope.$on(savedEvent, function(ev, args) {
//remove validation class
element.removeClass(className);
//clear form state as at this point we retrieve new data from the server
//and all validation will have cleared at this point
formCtrl.$setPristine();
});
}));
//This handles the 'unsaved changes' dialog which is triggered when a route is attempting to be changed but
// the form has pending changes
@@ -92,10 +94,12 @@ function valFormManager(serverValidationManager, $rootScope, $log, $timeout, not
}
});
unsubscribe.push(locationEvent);
//Ensure to remove the event handler when this instance is destroyted
scope.$on('$destroy', function() {
if(locationEvent){
locationEvent();
for (var u in unsubscribe) {
unsubscribe[u]();
}
});
@@ -96,8 +96,10 @@ function valPropertyMsg(serverValidationManager) {
//create properties on our custom scope so we can use it in our template
scope.errorMsg = "";
var unsubscribe = [];
//listen for form error changes
scope.$on("valStatusChanged", function (evt, args) {
unsubscribe.push(scope.$on("valStatusChanged", function(evt, args) {
if (args.form.$invalid) {
//first we need to check if the valPropertyMsg validity is invalid
@@ -123,10 +125,10 @@ function valPropertyMsg(serverValidationManager) {
hasError = false;
scope.errorMsg = "";
}
}, true);
}, true));
//listen for the forms saving event
scope.$on("formSubmitting", function (ev, args) {
unsubscribe.push(scope.$on("formSubmitting", function(ev, args) {
showValidation = true;
if (hasError && scope.errorMsg === "") {
scope.errorMsg = getErrorMsg();
@@ -135,15 +137,15 @@ function valPropertyMsg(serverValidationManager) {
scope.errorMsg = "";
stopWatch();
}
});
}));
//listen for the forms saved event
scope.$on("formSubmitted", function (ev, args) {
unsubscribe.push(scope.$on("formSubmitted", function(ev, args) {
showValidation = false;
scope.errorMsg = "";
formCtrl.$setValidity('valPropertyMsg', true);
stopWatch();
});
}));
//listen for server validation changes
// NOTE: we pass in "" in order to listen for all validation changes to the content property, not for
@@ -179,7 +181,16 @@ function valPropertyMsg(serverValidationManager) {
serverValidationManager.unsubscribe(scope.property.alias, "");
});
}
//when the scope is disposed we need to unsubscribe
scope.$on('$destroy', function () {
for (var u in unsubscribe) {
unsubscribe[u]();
}
});
}
};
}
angular.module('umbraco.directives.validation').directive("valPropertyMsg", valPropertyMsg);
@@ -43,8 +43,10 @@ function valToggleMsg(serverValidationManager) {
}
});
var unsubscribe = [];
//listen for the saving event (the result is a callback method which is called to unsubscribe)
var unsubscribeSaving = scope.$on("formSubmitting", function (ev, args) {
unsubscribe.push(scope.$on("formSubmitting", function(ev, args) {
showValidation = true;
if (formCtrl[attr.valMsgFor].$error[attr.valToggleMsg]) {
element.show();
@@ -56,20 +58,21 @@ function valToggleMsg(serverValidationManager) {
else {
element.hide();
}
});
}));
//listen for the saved event (the result is a callback method which is called to unsubscribe)
var unsubscribeSaved = scope.$on("formSubmitted", function (ev, args) {
unsubscribe.push(scope.$on("formSubmitted", function(ev, args) {
showValidation = false;
element.hide();
});
}));
//when the element is disposed we need to unsubscribe!
// NOTE: this is very important otherwise if this directive is part of a modal, the listener still exists because the dom
// element might still be there even after the modal has been hidden.
element.bind('$destroy', function () {
unsubscribeSaving();
unsubscribeSaved();
for (var u in unsubscribe) {
unsubscribe[u]();
}
});
}
@@ -537,6 +537,13 @@ angular.module('umbraco.services')
template: 'views/common/dialogs/ysod.html',
show: true
});
},
confirmDialog: function (ysodError) {
options.template = 'views/common/dialogs/confirm.html';
options.show = true;
return openDialog(options);
}
};
});
@@ -15,7 +15,7 @@ function macroService() {
//This regex will match an alias of anything except characters that are quotes or new lines (for legacy reasons, when new macros are created
// their aliases are cleaned an invalid chars are stripped)
var expression = /(<\?UMBRACO_MACRO macroAlias=["']([^\"\'\n\r]+?)["'][\s\S]+?)(\/>|>.*?<\/\?UMBRACO_MACRO>)/i;
var expression = /(<\?UMBRACO_MACRO (?:.+)?macroAlias=["']([^\"\'\n\r]+?)["'][\s\S]+?)(\/>|>.*?<\/\?UMBRACO_MACRO>)/i;
var match = expression.exec(syntax);
if (!match || match.length < 3) {
return null;
@@ -513,23 +513,26 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo
* Opens the user dialog, next to the sections navigation
* template is located in views/common/dialogs/user.html
*/
showUserDialog: function() {
showUserDialog: function () {
// hide tray and close help dialog
if (service.helpDialog) {
service.helpDialog.close();
}
service.hideTray();
if(userDialog){
userDialog.close();
userDialog = null;
if (service.userDialog) {
service.userDialog.close();
service.userDialog = undefined;
}
userDialog = dialogService.open(
{
template: "views/common/dialogs/user.html",
modalClass: "umb-modal-left",
show: true
});
service.userDialog = dialogService.open(
{
template: "views/common/dialogs/user.html",
modalClass: "umb-modal-left",
show: true
});
return userDialog;
return service.userDialog;
},
/**
@@ -541,7 +544,13 @@ function navigationService($rootScope, $routeParams, $log, $location, $q, $timeo
* Opens the user dialog, next to the sections navigation
* template is located in views/common/dialogs/user.html
*/
showHelpDialog: function() {
showHelpDialog: function () {
// hide tray and close user dialog
service.hideTray();
if (service.userDialog) {
service.userDialog.close();
}
if(service.helpDialog){
service.helpDialog.close();
service.helpDialog = undefined;
@@ -206,7 +206,7 @@ function umbPhotoFolderHelper($compile, $log, $timeout, $filter, imageHelper, me
},
/** builds an image grid row */
buildRow: function(imgs, maxRowHeight, minDisplayHeight, maxRowWidth, idealImgPerRow, margin) {
buildRow: function(imgs, maxRowHeight, minDisplayHeight, maxRowWidth, idealImgPerRow, margin, totalRemaining) {
var currRowWidth = 0;
var row = { images: [] };
@@ -253,8 +253,8 @@ function umbPhotoFolderHelper($compile, $log, $timeout, $filter, imageHelper, me
this.setImageStyle(row.images[j], sizes[j].width, sizes[j].height, margin, bottomMargin);
}
if (row.images.length === 1) {
//if there's only one image on the row, set the container to max width
if (row.images.length === 1 && totalRemaining > 1) {
//if there's only one image on the row and there are more images remaining, set the container to max width
row.images[0].style.width = maxRowWidth + "px";
}
@@ -278,7 +278,7 @@ function umbPhotoFolderHelper($compile, $log, $timeout, $filter, imageHelper, me
buildGrid: function(images, maxRowWidth, maxRowHeight, startingIndex, minDisplayHeight, idealImgPerRow, margin,imagesOnly) {
var rows = [];
var imagesProcessed = 0;
var imagesProcessed = 0;
//first fill in all of the original image sizes and URLs
for (var i = startingIndex; i < images.length; i++) {
@@ -298,7 +298,8 @@ function umbPhotoFolderHelper($compile, $log, $timeout, $filter, imageHelper, me
var currImgs = images.slice(imagesProcessed);
//build the row
var row = this.buildRow(currImgs, maxRowHeight, minDisplayHeight, maxRowWidth, idealImgPerRow, margin);
var remaining = images.length - imagesProcessed;
var row = this.buildRow(currImgs, maxRowHeight, minDisplayHeight, maxRowWidth, idealImgPerRow, margin, remaining);
if (row.images.length > 0) {
rows.push(row);
imagesProcessed += row.images.length;
@@ -48,14 +48,16 @@ function MainController($scope, $rootScope, $location, $routeParams, $timeout, $
eventsService.emit("app.closeDialogs", event);
};
var evts = [];
//when a user logs out or timesout
eventsService.on("app.notAuthenticated", function() {
evts.push(eventsService.on("app.notAuthenticated", function() {
$scope.authenticated = null;
$scope.user = null;
});
}));
//when the app is read/user is logged in, setup the data
eventsService.on("app.ready", function (evt, data) {
evts.push(eventsService.on("app.ready", function (evt, data) {
$scope.authenticated = data.authenticated;
$scope.user = data.user;
@@ -73,7 +75,7 @@ function MainController($scope, $rootScope, $location, $routeParams, $timeout, $
notificationsService.add(notification);
}
}
});
})
//if the user has changed we need to redirect to the root so they don't try to continue editing the
//last item in the URL (NOTE: the user id can equal zero, so we cannot just do !data.lastUserId since that will resolve to true)
@@ -104,6 +106,13 @@ function MainController($scope, $rootScope, $location, $routeParams, $timeout, $
}, 3000);
}
}));
//ensure to unregister from all events!
$scope.$on('$destroy', function () {
for (var e in evts) {
eventsService.unsubscribe(evts[e]);
}
});
}
@@ -47,15 +47,17 @@ function NavigationController($scope, $rootScope, $location, $log, $routeParams,
$scope.selectedId = navigationService.currentId;
var evts = [];
//Listen for global state changes
eventsService.on("appState.globalState.changed", function (e, args) {
evts.push(eventsService.on("appState.globalState.changed", function(e, args) {
if (args.key === "showNavigation") {
$scope.showNavigation = args.value;
}
});
}));
//Listen for menu state changes
eventsService.on("appState.menuState.changed", function (e, args) {
evts.push(eventsService.on("appState.menuState.changed", function(e, args) {
if (args.key === "showMenuDialog") {
$scope.showContextMenuDialog = args.value;
}
@@ -71,20 +73,21 @@ function NavigationController($scope, $rootScope, $location, $log, $routeParams,
if (args.key === "currentNode") {
$scope.menuNode = args.value;
}
});
}));
//Listen for section state changes
eventsService.on("appState.treeState.changed", function (e, args) {
evts.push(eventsService.on("appState.treeState.changed", function(e, args) {
var f = args;
if (args.value.root && args.value.root.metaData.containsTrees === false) {
$rootScope.emptySection = true;
}else{
}
else {
$rootScope.emptySection = false;
}
});
}));
//Listen for section state changes
eventsService.on("appState.sectionState.changed", function (e, args) {
evts.push(eventsService.on("appState.sectionState.changed", function(e, args) {
//section changed
if (args.key === "currentSection") {
$scope.currentSection = args.value;
@@ -93,26 +96,26 @@ function NavigationController($scope, $rootScope, $location, $log, $routeParams,
if (args.key === "showSearchResults") {
$scope.showSearchResults = args.value;
}
});
}));
//This reacts to clicks passed to the body element which emits a global call to close all dialogs
eventsService.on("app.closeDialogs", function (event) {
evts.push(eventsService.on("app.closeDialogs", function(event) {
if (appState.getGlobalState("stickyNavigation")) {
navigationService.hideNavigation();
//TODO: don't know why we need this? - we are inside of an angular event listener.
angularHelper.safeApply($scope);
}
});
}));
//when a user logs out or timesout
eventsService.on("app.notAuthenticated", function () {
evts.push(eventsService.on("app.notAuthenticated", function() {
$scope.authenticated = false;
});
}));
//when the application is ready and the user is authorized setup the data
eventsService.on("app.ready", function (evt, data) {
evts.push(eventsService.on("app.ready", function(evt, data) {
$scope.authenticated = true;
});
}));
//this reacts to the options item in the tree
//todo, migrate to nav service
@@ -151,6 +154,13 @@ function NavigationController($scope, $rootScope, $location, $log, $routeParams,
}, 300);
}
};
//ensure to unregister from all events!
$scope.$on('$destroy', function () {
for (var e in evts) {
eventsService.unsubscribe(evts[e]);
}
});
}
//register it
+15 -3
View File
@@ -2,7 +2,6 @@
app.run(['userService', '$log', '$rootScope', '$location', 'navigationService', 'appState', 'editorState', 'fileManager', 'assetsService', 'eventsService', '$cookies', '$templateCache',
function (userService, $log, $rootScope, $location, navigationService, appState, editorState, fileManager, assetsService, eventsService, $cookies, $templateCache) {
//This sets the default jquery ajax headers to include our csrf token, we
// need to user the beforeSend method because our token changes per user/login so
// it cannot be static
@@ -16,8 +15,10 @@ app.run(['userService', '$log', '$rootScope', '$location', 'navigationService',
eventsService.on("app.authenticated", function(evt, data) {
assetsService._loadInitAssets().then(function() {
appState.setGlobalState("isReady", true);
//send the ready event
//send the ready event with the included returnToPath,returnToSearch data
eventsService.emit("app.ready", data);
returnToPath = null, returnToSearch = null;
});
});
@@ -44,7 +45,18 @@ app.run(['userService', '$log', '$rootScope', '$location', 'navigationService',
wiring up it's controller, etc... and then redirect to the rejected URL. */
$rootScope.$on('$routeChangeError', function(event, current, previous, rejection) {
event.preventDefault();
$location.path(rejection.path).search(rejection.search);
var returnPath = null;
if (rejection.path == "/login" || rejection.path.startsWith("/login/")) {
//Set the current path before redirecting so we know where to redirect back to
returnPath = encodeURIComponent($location.url());
}
$location.path(rejection.path)
if (returnPath) {
$location.search("returnPath", returnPath);
}
});
+16 -1
View File
@@ -305,7 +305,8 @@ textarea {
.radio input[type="radio"],
.checkbox input[type="checkbox"] {
float: left;
margin-left: -20px;
margin-left: 0px;
margin-right:5px;
}
// Move the options list down to align with labels
@@ -793,3 +794,17 @@ legend + .control-group {
position: relative;
z-index: 1000;
}
@media (max-width: 767px) {
// Labels on own row
.form-horizontal .control-label {
width: 100%;
}
.form-horizontal .controls {
margin-left: 0;
}
}
+11 -2
View File
@@ -22,9 +22,10 @@
}
.login-overlay .form {
position:fixed;
display: block;
padding-top: 100px;
padding-left: 165px;
top: 100px;
left: 165px;
width: 370px;
text-align: right
}
@@ -44,4 +45,12 @@
padding-left: 6px;
margin-top: 10px;
text-align: center;
}
@media (max-width: 565px) {
// Remove padding on login-form on smaller devices
.login-overlay .form {
left: inherit;
right:25px;
}
}
+1 -1
View File
@@ -146,7 +146,7 @@ h5{
.controls-row {
padding-top: 5px;
margin-left: 240px !important;
margin-left: 240px;
}
.controls-row label {
display: inline-block
@@ -63,6 +63,7 @@
.umb-modal-left .umb-panel-header .umb-headline, .umb-modal-left .umb-panel-header h1 {
width: auto;
padding-left: 0;
}
/* umb.dialog is used for the dialogs on the conent tree*/
+12 -16
View File
@@ -37,17 +37,13 @@
bottom: 31px !important;
}
/*
.umb-tab-buttons.umb-bottom-bar {
bottom: 50px !important;
}*/
.umb-panel-header .umb-headline, .umb-panel-header h1 {
font-size: 16px;
border: none;
background: none;
margin: 15px 0 0 20px;
padding: 3px 5px;
line-height: 1.4;
height: auto;
width: 100%;
border: 1px solid @grayLighter;
@@ -91,7 +87,7 @@
margin: -6px 0 0 0;
padding: 0 0 2px 0;
border-radius: 0;
line-height: 1em;
line-height: normal;
border: 1px solid transparent;
color: @black;
letter-spacing: -0.01em
@@ -152,27 +148,27 @@
/* tab buttons */
.umb-bottom-bar{
background: white;
-webkit-box-shadow: 0px -18px 20px rgba(255, 255, 255, 1);
-moz-box-shadow: 0px -18px 20px rgba(255, 255, 255, 1);
box-shadow: 0px -18px 20px rgba(255, 255, 255, 1);
border-top: 1px solid @grayLighter;
padding: 10px 0 10px 0;
position: fixed;
bottom: 0px;
left: 100px;
right: 20px;
z-index: 6010;
};
@media (min-width: 1101px) {
.umb-bottom-bar {left: 460px;}
}
.umb-tab-buttons{padding-left: 240px;}
.umb-tab-buttons{
padding-left: 0px;
}
@media (min-width: 1101px) {
.umb-bottom-bar {
left: 460px;
}
}
.umb-tab-pane{padding-bottom: 90px}
.tab-content{overflow: visible; }
@@ -25,7 +25,7 @@
}
.umb-codeeditor{
width: 99%;
width: 99%;
}
//
@@ -68,7 +68,7 @@ div.umb-codeeditor .umb-btn-toolbar {
.mce-ico{font-size: 12px !important; color: @blackLight !important;}
/* Special case to support helviticons for the tiny mce button controls */
.mce-ico.mce-i-custom[class^="icon-"],
.mce-ico.mce-i-custom[class*=" icon-"] {
.mce-ico.mce-i-custom[class*=" icon-"] {
font-family: icomoon;
font-size:16px !important;
}
@@ -100,8 +100,8 @@ ul.color-picker li a {
/* pre-value editor */
.control-group.color-picker-preval pre {
display: inline;
margin-right: 20px;
display: inline;
margin-right: 20px;
margin-left: 10px;
}
@@ -116,8 +116,8 @@ ul.color-picker li a {
// --------------------------------------------------
.umb-mediapicker .add-link{
display: inline-block;
height: 120px;
width: 120px;
height: 120px;
width: 120px;
text-align: center;
color: @grayLight;
border: 2px @grayLight dashed !important;
@@ -187,7 +187,7 @@ ul.color-picker li a {
.umb-sortable-thumbnails li img
{
max-width:100%;
max-width:100%;
max-height:100%;
margin:auto;
display:block;
@@ -206,12 +206,12 @@ ul.color-picker li a {
.umb-sortable-thumbnails .icon-holder *
{
color: @grayLight;
display: block
display: block
}
//
// Cropper
// Cropper
// -------------------------------------------------
.umb-cropper{
@@ -237,7 +237,7 @@ ul.color-picker li a {
position: relative;
margin: auto;
}
.umb-cropper-gravity .viewport{
overflow: hidden;
position: relative;
@@ -301,17 +301,13 @@ ul.color-picker li a {
// --------------------------------------------------
.umb-folderbrowser .add-link{
display: inline-block;
height: 120px;
width: 120px;
height: 120px;
width: 120px;
text-align: center;
border: 1px @grayLight dashed;
line-height: 120px
}
.umb-folderbrowser .selector-overlay{
display: none !important;
}
.umb-upload-drop-zone{
margin-bottom:5px;
}
@@ -368,8 +364,8 @@ ul.color-picker li a {
.umb-photo-folder .picrow div a:first-child {
width:100%;
.umb-photo-folder .picrow div a:first-child {
width:100%;
height:100%;
}
@@ -382,15 +378,19 @@ ul.color-picker li a {
.umb-photo-folder a:hover{text-decoration: none}
.umb-photo-folder .umb-non-thumbnail{
text-align: center;
vertical-align: center;
vertical-align: middle;
font-size: 12px;
background: @grayLighter;
color: @black;
text-decoration: none;
}
.umb-photo-folder .selector-overlay{
display: none;
}
//this is a temp hack, to provide selectors in the dialog:
.umb-photo-folder .pic:hover .selector-overlay{
.umb-photo-folder .pic:hover .selector-overlay {
position: absolute;
bottom: 0px;
left: 0px;
@@ -402,6 +402,11 @@ ul.color-picker li a {
text-align: center;
color: white;
opacity: 0.4;
text-decoration:none;
overflow: hidden;
text-overlow: ellipsis;
white-space: nowrap;
}
.umb-photo-folder .umb-non-thumbnail i{
@@ -410,7 +415,18 @@ ul.color-picker li a {
line-height: 60px;
display: block;
margin: auto;
padding-top: 20px;
/*vertically aligns */
position: relative;
top: 50%;
transform: translateY(-50%);
}
.umb-photo-folder .umb-non-thumbnail span{
position: absolute;
display: block;
margin: auto;
width: 100%;
top: 20px;
}
.umb-photo-folder .selected{
@@ -505,4 +521,4 @@ ul.color-picker li a {
// --------------------------------------------------
.bootstrap-datetimepicker-widget .btn{padding: 0;}
.bootstrap-datetimepicker-widget .picker-switch .btn{ background: none; border: none;}
.umb-datepicker .input-append .add-on{cursor: pointer;}
.umb-datepicker .input-append .add-on{cursor: pointer;}
@@ -7,6 +7,7 @@ ul.sections {
background: @blackLight;
height: 100%;
width: 80px;
border-right: 1px solid @grayDark;
}
ul.sections li {
@@ -42,6 +43,7 @@ ul.sections li a {
width: 100%;
height: 100%;
margin: 0 0 0 -4px;
cursor: pointer; // make sure IE10 displays pointer cursor for expand and help sections.
}
ul.sections a span {
@@ -63,7 +65,7 @@ ul.sections:hover a span {
// -------------------------
ul.sections li.avatar {
height: 69px;
height: 67px;
padding: 30px 0 2px 0;
text-align: center;
margin: 0 0 0 -4px;
@@ -116,7 +118,38 @@ ul.sections li.help a {
// -------------------------
li.expand a, li.expand{border: none !Important;}
ul.sections-tray {
padding-top: 102px;
width: 80px;
li.expand {
&.open > a > i.icon {
-webkit-transition: all 1s !important;
-o-transition: all 1s !important;
-moz-transition: all 1s !important;
transition: all 1s !important;
&:before {
-ms-transform: rotate(180deg) !important; /* IE 9 */
-webkit-transform: rotate(180deg) !important; /* Chrome, Safari, Opera */
-o-transform: rotate(180deg) !important;
-moz-transform: rotate(180deg) !important;
transform: rotate(180deg) !important;
}
}
}
ul.sections-tray {
padding-top: 99px;
width: 80px;
& > li:first-child > a {
border-top: 1px solid #343434;
}
& > li {
// 5px (instead of 4px) because of vertical border
border-left-width: 5px;
&.current, &:hover {
border-left-width: 5px;
}
}
}
@@ -35,7 +35,7 @@ angular.module("umbraco")
});
helpService.findVideos(rq).then(function(videos){
$scope.videos = videos;
$scope.videos = videos;
});
});
@@ -37,7 +37,7 @@
<li class="span2" ng-repeat="video in videos">
<div class="thumbnail" style="margin-right: 20px">
<a target="_blank" href="{{video.link}}?utm_source=core&utm_medium=help&utm_content=link&utm_campaign=tv" title="{{video.title}}">
<img ng-src="{{video.thumbnail}}" alt="{{video.title}}">
<img ng-src="{{video.thumbnail}}" alt="{{video.title}}">
</a>
</div>
</li>
@@ -73,7 +73,7 @@ function InsertMacroController($scope, entityResource, macroResource, umbPropEdi
var val = item.value;
if (!_.isString(item.value)) {
if (item.value != null && item.value != undefined && !_.isString(item.value)) {
try {
val = angular.toJson(val);
}
@@ -5,14 +5,14 @@ angular.module("umbraco")
$scope.history = historyService.getCurrent();
$scope.version = Umbraco.Sys.ServerVariables.application.version + " assembly: " + Umbraco.Sys.ServerVariables.application.assemblyVersion;
var evtHandlers = [];
evtHandlers.push(eventsService.on("historyService.add", function (e, args) {
var evts = [];
evts.push(eventsService.on("historyService.add", function (e, args) {
$scope.history = args.all;
}));
evtHandlers.push(eventsService.on("historyService.remove", function (e, args) {
evts.push(eventsService.on("historyService.remove", function (e, args) {
$scope.history = args.all;
}));
evtHandlers.push(eventsService.on("historyService.removeAll", function (e, args) {
evts.push(eventsService.on("historyService.removeAll", function (e, args) {
$scope.history = [];
}));
@@ -62,8 +62,8 @@ angular.module("umbraco")
//remove all event handlers
$scope.$on('$destroy', function () {
for (var i = 0; i < evtHandlers.length; i++) {
evtHandlers[i]();
for (var e = 0; e < evts.length; e++) {
evts[e]();
}
});
@@ -1,10 +1,24 @@
/** This controller is simply here to launch the login dialog when the route is explicitly changed to /login */
angular.module('umbraco').controller("Umbraco.LoginController", function (eventsService, $scope, userService, $location) {
angular.module('umbraco').controller("Umbraco.LoginController", function (eventsService, $scope, userService, $location, $rootScope) {
userService._showLoginDialog();
eventsService.on("app.ready", function(){
$scope.avatar = "assets/img/application/logo.png";
$location.path("/").search("");
var evtOn = eventsService.on("app.ready", function(evt, data){
$scope.avatar = "assets/img/application/logo.png";
var path = "/";
//check if there's a returnPath query string, if so redirect to it
var locationObj = $location.search();
if (locationObj.returnPath) {
path = decodeURIComponent(locationObj.returnPath);
}
$location.url(path);
});
});
$scope.$on('$destroy', function () {
eventsService.unsubscribe(evtOn);
});
});
@@ -11,15 +11,17 @@
<div ng-style="img.style" class="umb-non-thumbnail" ng-if="!img.thumbnail">
<i class="icon large {{img.icon}}"></i>
{{img.name}}
<span>{{img.name}}</span>
</div>
<div ng-if="img.thumbnail" class="umb-photo" ng-style="img.thumbStyle" alt="{{img.name}}">
</div>
<div ng-if="img.thumbnail" class="umb-photo" ng-style="img.thumbStyle" alt="{{img.name}}"></div>
</a>
<a href ng-click="clickHandler(img, $event, true)"
ng-if="img.isFolder" class="selector-overlay">
<localize key="buttons_select">Select</localize>
<a href ng-click="clickHandler(img, $event, true)" class="selector-overlay">
<localize key="buttons_select" ng-if="img.isFolder">Select</localize>
<span ng-if="!img.isFolder">{{img.name}}</span>
</a>
</div>
</div>
@@ -16,7 +16,7 @@
</a>
</li>
<li class="expand" ng-show="needTray">
<li class="expand" ng-class="{ 'open': showTray === true }" ng-show="needTray">
<a href ng-click="trayClick()">
<i class="icon icon-arrow-right"></i>
</a>
@@ -49,13 +49,18 @@ function mediaPickerController($scope, dialogService, entityResource, $log, icon
}
};
$scope.$on("formSubmitting", function (ev, args) {
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
var currIds = _.map($scope.renderModel, function (i) {
return i.id;
});
$scope.model.value = trim(currIds.join(), ",");
});
//when the scope is destroyed we need to unsubscribe
$scope.$on('$destroy', function () {
unsubscribe();
});
//load media data
var modelIds = $scope.model.value ? $scope.model.value.split(',') : [];
entityResource.getByIds(modelIds, dialogOptions.entityType).then(function (data) {
@@ -58,10 +58,15 @@ angular.module('umbraco')
};
$scope.$on("formSubmitting", function (ev, args) {
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
$scope.model.value = trim($scope.ids.join(), ",");
});
//when the scope is destroyed we need to unsubscribe
$scope.$on('$destroy', function () {
unsubscribe();
});
function trim(str, chr) {
var rgxtrim = (!chr) ? new RegExp('^\\s+|\\s+$', 'g') : new RegExp('^'+chr+'+|'+chr+'+$', 'g');
return str.replace(rgxtrim, '');
@@ -43,13 +43,18 @@ angular.module('umbraco')
//we always need to ensure we dont submit anything broken
$scope.$on("formSubmitting", function (ev, args) {
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
if($scope.model.value.type === "member"){
$scope.model.value.id = -1;
$scope.model.value.query = "";
}
});
//when the scope is destroyed we need to unsubscribe
$scope.$on('$destroy', function () {
unsubscribe();
});
function populate(item){
$scope.clear();
item.icon = iconHelper.convertFromLegacyIcon(item.icon);
@@ -91,15 +91,17 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.ChangePasswordCont
//set model to null
$scope.model.value = null;
};
var unsubscribe = [];
//listen for the saved event, when that occurs we'll
//change to changing = false;
$scope.$on("formSubmitted", function () {
unsubscribe.push($scope.$on("formSubmitted", function() {
if ($scope.model.config.disableToggle === false) {
$scope.changing = false;
}
});
$scope.$on("formSubmitting", function() {
}
}));
unsubscribe.push($scope.$on("formSubmitting", function() {
//if there was a previously generated password displaying, clear it
if ($scope.changing && $scope.model.value) {
$scope.model.value.generatedPassword = null;
@@ -108,6 +110,13 @@ angular.module("umbraco").controller("Umbraco.PropertyEditors.ChangePasswordCont
//we are not changing, so the model needs to be null
$scope.model.value = null;
}
}));
//when the scope is destroyed we need to unsubscribe
$scope.$on('$destroy', function () {
for (var u in unsubscribe) {
unsubscribe[u]();
}
});
$scope.showReset = function() {
@@ -20,29 +20,32 @@
<!-- we need to show the old pass field when the provider cannot retrieve the password -->
<umb-control-group alias="oldPassword" label="Old password" ng-show="$parent.showOldPass()">
<input type="text" name="oldPassword" ng-model="$parent.model.value.oldPassword"
<input type="password" name="oldPassword" ng-model="$parent.model.value.oldPassword"
class="input-large umb-textstring textstring"
ng-required="$parent.showOldPass()"
val-server="oldPassword" no-dirty-check/>
val-server="oldPassword" no-dirty-check
autocomplete="off"/>
<span class="help-inline" val-msg-for="oldPassword" val-toggle-msg="required">Required</span>
<span class="help-inline" val-msg-for="oldPassword" val-toggle-msg="valServer"></span>
</umb-control-group>
<umb-control-group alias="password" label="New password" ng-show="$parent.showNewPass()">
<input type="text" name="password" ng-model="$parent.model.value.newPassword"
class="input-large umb-textstring textstring"
<input type="password" name="password" ng-model="$parent.model.value.newPassword"
class="input-large umb-textstring textstring"
ng-required="!$parent.model.value.reset"
val-server="value"
ng-minlength="{{$parent.model.config.minPasswordLength}}" no-dirty-check/>
val-server="value"
ng-minlength="{{$parent.model.config.minPasswordLength}}" no-dirty-check
autocomplete="off" />
<span class="help-inline" val-msg-for="password" val-toggle-msg="required">Required</span>
<span class="help-inline" val-msg-for="password" val-toggle-msg="minlength">Minimum {{$parent.model.config.minPasswordLength}} characters</span>
<span class="help-inline" val-msg-for="password" val-toggle-msg="valServer"></span>
</umb-control-group>
<umb-control-group alias="confirmpassword" label="Confirm password" ng-show="$parent.showConfirmPass()">
<input type="text" name="confirmpassword" ng-model="$parent.model.confirm"
<input type="password" name="confirmpassword" ng-model="$parent.model.confirm"
class="input-large umb-textstring textstring"
val-compare="password" no-dirty-check/>
val-compare="password" no-dirty-check
autocomplete="off" />
<span class="help-inline" val-msg-for="confirmpassword" val-toggle-msg="valCompare">Passwords must match</span>
</umb-control-group>
@@ -53,7 +53,7 @@ function contentPickerController($scope, dialogService, entityResource, editorSt
startNode: {
query: "",
type: "content",
id: -1
id: $scope.model.config.startNodeId ? $scope.model.config.startNodeId : -1 // get start node for simple Content Picker
}
};
@@ -158,13 +158,18 @@ function contentPickerController($scope, dialogService, entityResource, editorSt
$scope.renderModel = [];
};
$scope.$on("formSubmitting", function (ev, args) {
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
var currIds = _.map($scope.renderModel, function (i) {
return i.id;
});
$scope.model.value = trim(currIds.join(), ",");
});
//when the scope is destroyed we need to unsubscribe
$scope.$on('$destroy', function () {
unsubscribe();
});
//load current data
var modelIds = $scope.model.value ? $scope.model.value.split(',') : [];
entityResource.getByIds(modelIds, entityType).then(function (data) {
@@ -18,9 +18,16 @@ function dateTimePickerController($scope, notificationsService, assetsService, a
//map the user config
$scope.model.config = angular.extend(config, $scope.model.config);
$scope.datetimePickerValue = $scope.model.value;
//hide picker if clicking on the document
$scope.hidePicker = function () {
$element.find("div:first").datetimepicker("hide");
//$element.find("div:first").datetimepicker("hide");
// Sometimes the statement above fails and generates errors in the browser console. The following statements fix that.
var dtp = $element.find("div:first");
if (dtp && dtp.datetimepicker) {
dtp.datetimepicker("hide");
}
};
$(document).bind("click", $scope.hidePicker);
@@ -67,8 +74,16 @@ function dateTimePickerController($scope, notificationsService, assetsService, a
.datetimepicker($scope.model.config)
.on("dp.change", applyDate);
//manually assign the date to the plugin
$element.find("div:first").datetimepicker("setValue", $scope.model.value ? $scope.model.value : null);
//manually assign the date to the plugin
if (!$scope.model.config.format) {
$element.find("div:first").datetimepicker("setValue", $scope.model.value ? $scope.model.value : null);
}
else {
$element.find("div:first").datetimepicker("setValue", $scope.model.value ? new Date($scope.model.value) : null);
if ($scope.model.value && $scope.model.config.format) {
$scope.datetimePickerValue = moment($scope.model.value).format($scope.model.config.format);
}
}
//Ensure to remove the event handler when this instance is destroyted
$scope.$on('$destroy', function () {
@@ -1,7 +1,7 @@
<div class="umb-editor umb-datepicker" ng-controller="Umbraco.PropertyEditors.DatepickerController">
<div class="input-append date datepicker" style="position: relative;" id="datepicker{{model.alias}}">
<input name="datepicker" data-format="{{model.config.format}}" type="text"
ng-model="model.value"
ng-model="datetimePickerValue"
ng-required="model.validation.mandatory"
val-server="value" />
<span class="add-on">
@@ -1,79 +1,97 @@
angular.module("umbraco")
.controller("Umbraco.PropertyEditors.GridPrevalueEditor.RowConfigController",
function ($scope) {
function RowConfigController($scope) {
$scope.currentRow = angular.copy($scope.dialogOptions.currentRow);
$scope.editors = $scope.dialogOptions.editors;
$scope.columns = $scope.dialogOptions.columns;
$scope.currentRow = $scope.dialogOptions.currentRow;
$scope.editors = $scope.dialogOptions.editors;
$scope.columns = $scope.dialogOptions.columns;
$scope.scaleUp = function(section, max, overflow) {
var add = 1;
if (overflow !== true) {
add = (max > 1) ? 1 : max;
}
//var add = (max > 1) ? 1 : max;
section.grid = section.grid + add;
};
$scope.scaleUp = function(section, max, overflow){
var add = 1;
if(overflow !== true){
add = (max > 1) ? 1 : max;
}
//var add = (max > 1) ? 1 : max;
section.grid = section.grid+add;
};
$scope.scaleDown = function(section) {
var remove = (section.grid > 1) ? 1 : section.grid;
section.grid = section.grid - remove;
};
$scope.scaleDown = function(section){
var remove = (section.grid > 1) ? 1 : section.grid;
section.grid = section.grid-remove;
};
$scope.percentage = function(spans) {
return ((spans / $scope.columns) * 100).toFixed(1);
};
$scope.percentage = function(spans){
return ((spans / $scope.columns) * 100).toFixed(1);
};
$scope.toggleCollection = function(collection, toggle){
if(toggle){
collection = [];
}else{
delete collection;
}
};
$scope.toggleCollection = function(collection, toggle) {
if (toggle) {
collection = [];
}
else {
delete collection;
}
};
/****************
area
*****************/
$scope.configureCell = function(cell, row){
if($scope.currentCell && $scope.currentCell=== cell){
delete $scope.currentCell;
}else{
if(cell === undefined){
var available = $scope.availableRowSpace;
var space = 4;
/****************
area
*****************/
$scope.configureCell = function(cell, row) {
if ($scope.currentCell && $scope.currentCell === cell) {
delete $scope.currentCell;
}
else {
if (cell === undefined) {
var available = $scope.availableRowSpace;
var space = 4;
if(available < 4 && available > 0){
space = available;
}
cell = {
grid: space
};
row.areas.push(cell);
}
$scope.currentCell = cell;
if (available < 4 && available > 0) {
space = available;
}
};
$scope.deleteArea = function(index){
$scope.currentRow.areas.splice(index, 1);
};
$scope.closeArea = function(){
$scope.currentCell = undefined;
};
cell = {
grid: space
};
row.areas.push(cell);
}
$scope.currentCell = cell;
}
};
$scope.$watch("currentRow", function(row){
if(row){
var total = 0;
_.forEach(row.areas, function(area){
total = (total + area.grid);
});
$scope.deleteArea = function(index) {
$scope.currentRow.areas.splice(index, 1);
};
$scope.closeArea = function() {
$scope.currentCell = undefined;
};
$scope.availableRowSpace = $scope.columns - total;
}
}, true);
});
$scope.nameChanged = false;
var originalName = $scope.currentRow.name;
$scope.$watch("currentRow", function(row) {
if (row) {
var total = 0;
_.forEach(row.areas, function(area) {
total = (total + area.grid);
});
$scope.availableRowSpace = $scope.columns - total;
if (originalName) {
if (originalName != row.name) {
$scope.nameChanged = true;
}
else {
$scope.nameChanged = false;
}
}
}
}, true);
$scope.complete = function () {
angular.extend($scope.dialogOptions.currentRow, $scope.currentRow);
$scope.close();
}
}
angular.module("umbraco").controller("Umbraco.PropertyEditors.GridPrevalueEditor.RowConfigController", RowConfigController);
@@ -1,11 +1,17 @@
<div class="umb-panel usky-grid usky-grid-configuration"
ng-controller="Umbraco.PropertyEditors.GridPrevalueEditor.RowConfigController">
<div class="umb-panel-body no-header with-footer">
<div class="umb-forms-settings">
<h5><localize key="grid_addRowConfiguration" /></h5>
<p><localize key="grid_addRowConfigurationDetail" /></p>
<div class="alert alert-warn ng-scope" ng-show="nameChanged">
Modifying a row configuration name will result in loss of
data for any existing content that is based on this configuration.
</div>
<umb-control-group label="@general_name">
<input type="text" ng-model="currentRow.name" />
</umb-control-group>
@@ -83,7 +89,11 @@ ng-controller="Umbraco.PropertyEditors.GridPrevalueEditor.RowConfigController">
<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-primary">
<a href ng-click="close()" class="btn btn-link">
<localize key="general_cancel">Cancel</localize>
</a>
<a href ng-click="complete()" class="btn btn-primary">
<localize key="general_ok" class="ng-isolate-scope ng-scope">Done</localize>
</a>
</div>
@@ -0,0 +1,26 @@
<div>
<div class="umb-panel-body no-header with-footer compact">
<umb-pane>
<h3 class="alert alert-warn ng-scope">Warning!</h3>
<p>
You are deleting the row configuration '<strong>{{dialogData.rowName}}</strong>'
</p>
<p>
Modifying a row configuration name will result in loss of
data for any existing content that is based on this configuration.
</p>
<p>
<localize key="general_areyousure">Are you sure?</localize>
</p>
</umb-pane>
</div>
<div class="umb-panel-footer">
<umb-confirm on-confirm="submit" on-cancel="close">
</umb-confirm>
</div>
</div>
@@ -14,6 +14,8 @@ angular.module("umbraco")
// Sortable options
// *********************************************
var draggedRteSettings;
$scope.sortableOptions = {
distance: 10,
cursor: "move",
@@ -40,15 +42,22 @@ angular.module("umbraco")
},
start: function (e, ui) {
draggedRteSettings = {};
ui.item.find('.mceNoEditor').each(function () {
tinyMCE.execCommand('mceRemoveEditor', false, $(this).attr('id'));
// remove all RTEs in the dragged row and save their settings
var id = $(this).attr('id');
draggedRteSettings[id] = _.findWhere(tinyMCE.editors, { id: id }).settings;
tinyMCE.execCommand('mceRemoveEditor', false, id);
});
},
stop: function (e, ui) {
// reset all RTEs affected by the dragging
ui.item.parents(".usky-column").find('.mceNoEditor').each(function () {
tinyMCE.execCommand('mceRemoveEditor', false, $(this).attr('id'));
tinyMCE.execCommand('mceAddEditor', false, $(this).attr('id'));
var id = $(this).attr('id');
draggedRteSettings[id] = draggedRteSettings[id] || _.findWhere(tinyMCE.editors, { id: id }).settings;
tinyMCE.execCommand('mceRemoveEditor', false, id);
tinyMCE.init(draggedRteSettings[id]);
});
}
};
@@ -98,6 +107,7 @@ angular.module("umbraco")
},
update: function (event, ui) {
// add all RTEs which are affected by the dragging
if (!ui.sender) {
if (cancelMove) {
ui.item.sortable.cancel();
@@ -121,6 +131,11 @@ angular.module("umbraco")
start: function (e, ui) {
ui.item.find('.mceNoEditor').each(function () {
notIncludedRte = [];
// save the dragged RTE settings
draggedRteSettings = _.findWhere(tinyMCE.editors, { id: $(this).attr('id') }).settings;
// remove the dragged RTE
tinyMCE.execCommand('mceRemoveEditor', false, $(this).attr('id'));
});
},
@@ -128,14 +143,21 @@ angular.module("umbraco")
stop: function (e, ui) {
ui.item.parents(".usky-cell").find('.mceNoEditor').each(function () {
if ($.inArray($(this).attr('id'), notIncludedRte) < 0) {
// add all dragged's neighbouring RTEs in the new cell
notIncludedRte.splice(0, 0, $(this).attr('id'));
}
});
$timeout(function () {
// reconstruct the dragged RTE
tinyMCE.init(draggedRteSettings);
_.forEach(notIncludedRte, function (id) {
tinyMCE.execCommand('mceRemoveEditor', false, id);
tinyMCE.execCommand('mceAddEditor', false, id);
console.info("stop " + id);
// reset all the other RTEs
if (id != draggedRteSettings.id) {
var rteSettings = _.findWhere(tinyMCE.editors, { id: id }).settings;
tinyMCE.execCommand('mceRemoveEditor', false, id);
tinyMCE.init(rteSettings);
}
});
}, 500, false);
}
@@ -127,9 +127,24 @@ angular.module("umbraco")
);
};
//var rowDeletesPending = false;
$scope.deleteLayout = function (index) {
//rowDeletesPending = true;
$scope.deleteLayout = function(index){
$scope.model.value.layouts.splice(index, 1);
//show ok/cancel dialog
var confirmDialog = dialogService.open(
{
template: "views/propertyEditors/grid/dialogs/rowdeleteconfirm.html",
show: true,
callback: function() {
$scope.model.value.layouts.splice(index, 1);
},
dialogData: {
rowName: $scope.model.value.layouts[index].name
}
}
);
};
@@ -216,7 +231,7 @@ angular.module("umbraco")
/****************
Clean up
*****************/
$scope.$on("formSubmitting", function (ev, args) {
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
var ts = $scope.model.value.templates;
var ls = $scope.model.value.layouts;
@@ -237,4 +252,9 @@ angular.module("umbraco")
});
});
//when the scope is destroyed we need to unsubscribe
$scope.$on('$destroy', function () {
unsubscribe();
});
});
@@ -1,8 +1,8 @@
<div class="umb-editor">
<input name="integerField" type="number" class="umb-editor umb-number"
<input name="integerField" type="number" class="umb-editor umb-number "
ng-model="model.value"
val-server="value"
fix-number />
fix-number min="{{model.config.min}}" max="{{model.config.max}}" step="{{model.config.step}}" />
<span class="help-inline" val-msg-for="integerField" val-toggle-msg="number">Not a number</span>
<span class="help-inline" val-msg-for="integerField" val-toggle-msg="valServer">{{propertyForm.requiredField.errorMsg}}</span>
@@ -50,14 +50,14 @@
<td>
<a href="#" ng-click="sort('Name', true)" prevent-default class="sortable">
<localize key="general_name">Name</localize>
<i class="icon" ng-class="{'icon-navigation-down': isSortDirection('Name', 'asc'), 'icon-navigation-up': isSortDirection('Name', 'desc')}"></i>
<i class="icon" ng-class="{'icon-navigation-up': isSortDirection('Name', 'asc'), 'icon-navigation-down': isSortDirection('Name', 'desc')}"></i>
</a>
</td>
<td ng-repeat="column in options.includeProperties">
<a href="#" ng-click="sort(column.alias, column.allowSorting)" ng-class="{'sortable':column.allowSorting}" prevent-default>
<span ng-bind="column.header"></span>
<i class="icon" ng-class="{'icon-navigation-down': isSortDirection(column.alias, 'asc'), 'icon-navigation-up': isSortDirection(column.alias, 'desc')}"></i>
<i class="icon" ng-class="{'icon-navigation-up': isSortDirection(column.alias, 'asc'), 'icon-navigation-down': isSortDirection(column.alias, 'desc')}"></i>
</a>
</td>
@@ -85,7 +85,7 @@ angular.module('umbraco')
$scope.renderModel = [];
};
$scope.$on("formSubmitting", function (ev, args) {
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
var syntax = [];
angular.forEach($scope.renderModel, function(value, key){
syntax.push(value.syntax);
@@ -94,6 +94,11 @@ angular.module('umbraco')
$scope.model.value = syntax.join("");
});
//when the scope is destroyed we need to unsubscribe
$scope.$on('$destroy', function () {
unsubscribe();
});
function trim(str, chr) {
var rgxtrim = (!chr) ? new RegExp('^\\s+|\\s+$', 'g') : new RegExp('^'+chr+'+|'+chr+'+$', 'g');
@@ -1,7 +1,5 @@
angular.module("umbraco")
.controller("Umbraco.PropertyEditors.MarkdownEditorController",
//inject umbracos assetsServce and dialog service
function ($scope, assetsService, dialogService, $timeout) {
function MarkdownEditorController($scope, assetsService, dialogService, $timeout) {
//tell the assets service to load the markdown.editor libs from the markdown editors
//plugin folder
@@ -11,36 +9,41 @@ function ($scope, assetsService, dialogService, $timeout) {
}
assetsService
.load([
"lib/markdown/markdown.converter.js",
.load([
"lib/markdown/markdown.converter.js",
"lib/markdown/markdown.sanitizer.js",
"lib/markdown/markdown.editor.js"
])
.then(function () {
//this function will execute when all dependencies have loaded
// but in the case that they've been previously loaded, we can only
// init the md editor after this digest because the DOM needs to be ready first
// so run the init on a timeout
$timeout(function() {
var converter2 = new Markdown.Converter();
var editor2 = new Markdown.Editor(converter2, "-" + $scope.model.alias);
editor2.run();
.then(function () {
//subscribe to the image dialog clicks
editor2.hooks.set("insertImageDialog", function (callback) {
// we need a short delay to wait for the textbox to appear.
setTimeout(function () {
//this function will execute when all dependencies have loaded
// but in the case that they've been previously loaded, we can only
// init the md editor after this digest because the DOM needs to be ready first
// so run the init on a timeout
$timeout(function () {
var converter2 = new Markdown.Converter();
var editor2 = new Markdown.Editor(converter2, "-" + $scope.model.alias);
editor2.run();
dialogService.mediaPicker({
callback: function (data) {
callback(data.image);
}
//subscribe to the image dialog clicks
editor2.hooks.set("insertImageDialog", function (callback) {
dialogService.mediaPicker({
callback: function (data) {
callback(data.image);
}
});
return true; // tell the editor that we'll take care of getting the image url
});
return true; // tell the editor that we'll take care of getting the image url
});
}, 200);
});
});
//load the seperat css for the editor to avoid it blocking our js loading TEMP HACK
assetsService.loadCss("lib/markdown/markdown.css");
});
//load the seperat css for the editor to avoid it blocking our js loading TEMP HACK
assetsService.loadCss("lib/markdown/markdown.css");
})
}
angular.module("umbraco").controller("Umbraco.PropertyEditors.MarkdownEditorController", MarkdownEditorController);
@@ -65,13 +65,18 @@ function memberGroupPicker($scope, dialogService){
$scope.renderModel = [];
};
$scope.$on("formSubmitting", function (ev, args) {
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
var currIds = _.map($scope.renderModel, function (i) {
return i.id;
});
$scope.model.value = trim(currIds.join(), ",");
});
//when the scope is destroyed we need to unsubscribe
$scope.$on('$destroy', function () {
unsubscribe();
});
}
angular.module('umbraco').controller("Umbraco.PropertyEditors.MemberGroupPickerController", memberGroupPicker);
@@ -60,13 +60,18 @@ function memberPickerController($scope, dialogService, entityResource, $log, ico
$scope.renderModel = [];
};
$scope.$on("formSubmitting", function (ev, args) {
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
var currIds = _.map($scope.renderModel, function (i) {
return i.id;
});
$scope.model.value = trim(currIds.join(), ",");
});
//when the scope is destroyed we need to unsubscribe
$scope.$on('$destroy', function () {
unsubscribe();
});
//load member data
var modelIds = $scope.model.value ? $scope.model.value.split(',') : [];
entityResource.getByIds(modelIds, "Member").then(function (data) {
@@ -1,5 +1,13 @@
function MultipleTextBoxController($scope) {
$scope.sortableOptions = {
axis: 'y',
containment: 'parent',
cursor: 'move',
items: '> div.control-group',
tolerance: 'pointer'
};
if (!$scope.model.value) {
$scope.model.value = [];
}
@@ -1,17 +1,20 @@
<div class="umb-editor umb-multiple-textbox" ng-controller="Umbraco.PropertyEditors.MultipleTextBoxController">
<div class="control-group" ng-repeat="item in model.value">
<input type="text" name="item_{{$index}}" ng-model="item.value" class="umb-editor" />
<a prevent-default href="" title="Remove this text box"
ng-show="model.value.length > model.config.min"
ng-click="remove($index)">
<i class="icon icon-remove"></i>
</a>
<div ui-sortable="sortableOptions" ng-model="model.value">
<div class="control-group" ng-repeat="item in model.value">
<i class="icon icon-navigation handle"></i>
<input type="text" name="item_{{$index}}" ng-model="item.value" class="umb-editor" />
<a prevent-default href="" title="Remove this text box"
ng-show="model.value.length > model.config.min"
ng-click="remove($index)">
<i class="icon icon-remove"></i>
</a>
</div>
</div>
<a prevent-default href="" title="Add another text box"
ng-show="model.config.max <= 0 || model.value.length < model.config.max"
ng-click="add()">
ng-show="model.config.max <= 0 || model.value.length < model.config.max"
ng-click="add()">
<i class="icon icon-add"></i>
</a>
</div>
</div>
@@ -58,12 +58,16 @@ angular.module("umbraco").controller("Umbraco.PrevalueEditors.RteController",
}
};
$scope.$on("formSubmitting", function (ev, args) {
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
var commands = _.where($scope.tinyMceConfig.commands, {selected: true});
$scope.model.value.toolbar = _.pluck(commands, "frontEndCommand");
});
//when the scope is destroyed we need to unsubscribe
$scope.$on('$destroy', function () {
unsubscribe();
});
});
@@ -40,6 +40,18 @@ describe('macro service tests', function () {
expect(result.macroParamsDictionary.test2).toBe("hello");
});
it('can parse syntax for macros when macroAlias is not the first parameter', function () {
var result = macroService.parseMacroSyntax("<?UMBRACO_MACRO test=\"asdf\" test2='hello' macroAlias='Map.Test' />");
expect(result).not.toBeNull();
expect(result.macroAlias).toBe("Map.Test");
expect(result.macroParamsDictionary.test).not.toBeUndefined();
expect(result.macroParamsDictionary.test).toBe("asdf");
expect(result.macroParamsDictionary.test2).not.toBeUndefined();
expect(result.macroParamsDictionary.test2).toBe("hello");
});
it('can parse syntax for macros with aliases containing whitespace and other chars', function () {
var result = macroService.parseMacroSyntax("<?UMBRACO_MACRO macroAlias='Map Test [Hello\\World]' test=\"asdf\" test2='hello' />");
+10 -16
View File
@@ -84,9 +84,8 @@
<ConfigurationOverrideFile>
</ConfigurationOverrideFile>
<DefineConstants>TRACE</DefineConstants>
<DocumentationFile>
</DocumentationFile>
<DebugSymbols>false</DebugSymbols>
<DocumentationFile>bin\Umbraco.Web.UI.XML</DocumentationFile>
<DebugSymbols>true</DebugSymbols>
<FileAlignment>4096</FileAlignment>
<NoStdLib>false</NoStdLib>
<NoWarn>
@@ -96,7 +95,7 @@
<RemoveIntegerChecks>false</RemoveIntegerChecks>
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
<WarningLevel>4</WarningLevel>
<DebugType>none</DebugType>
<DebugType>pdbonly</DebugType>
<ErrorReport>prompt</ErrorReport>
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
<Prefer32Bit>false</Prefer32Bit>
@@ -127,9 +126,9 @@
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\dotless.1.4.1.0\lib\dotless.Core.dll</HintPath>
</Reference>
<Reference Include="Examine, Version=0.1.62.2941, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\Examine.0.1.62.2941\lib\Examine.dll</HintPath>
<Reference Include="Examine">
<HintPath>..\packages\Examine.0.1.63.0\lib\Examine.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
@@ -152,12 +151,6 @@
<HintPath>..\packages\Lucene.Net.2.9.4.1\lib\net40\Lucene.Net.dll</HintPath>
</Reference>
<Reference Include="Microsoft.CSharp" />
<Reference Include="Microsoft.Threading.Tasks">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.165\lib\net45\Microsoft.Threading.Tasks.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Threading.Tasks.Extensions">
<HintPath>..\packages\Microsoft.Bcl.Async.1.0.165\lib\net45\Microsoft.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Web.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<Private>True</Private>
<HintPath>..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll</HintPath>
@@ -172,7 +165,7 @@
</Reference>
<Reference Include="MySql.Data">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\packages\MySql.Data.6.6.5\lib\net40\MySql.Data.dll</HintPath>
<HintPath>..\packages\MySql.Data.6.9.6\lib\net45\MySql.Data.dll</HintPath>
</Reference>
<Reference Include="Newtonsoft.Json, Version=6.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
@@ -2070,6 +2063,7 @@
<Content Include="Umbraco\PartialViewMacros\Templates\Navigation.cshtml" />
<Content Include="Umbraco\PartialViewMacros\Templates\SiteMap.cshtml" />
<Content Include="Umbraco\Views\AuthorizeUpgrade.cshtml" />
<Content Include="Umbraco\Translation\translationTasks.dtd" />
<None Include="Umbraco_client\CodeMirror\js\mode\coffeescript\LICENSE" />
<None Include="Umbraco_client\CodeMirror\js\mode\pascal\LICENSE" />
<None Include="Umbraco_client\CodeMirror\js\mode\perl\LICENSE" />
@@ -2546,9 +2540,9 @@ xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.0\x86\*.* "$(TargetDir)x86\"
<WebProjectProperties>
<UseIIS>True</UseIIS>
<AutoAssignPort>True</AutoAssignPort>
<DevelopmentServerPort>7250</DevelopmentServerPort>
<DevelopmentServerPort>7260</DevelopmentServerPort>
<DevelopmentServerVPath>/</DevelopmentServerVPath>
<IISUrl>http://localhost:7250</IISUrl>
<IISUrl>http://localhost:7260</IISUrl>
<NTLMAuthentication>False</NTLMAuthentication>
<UseCustomServer>False</UseCustomServer>
<CustomServerUrl>
@@ -12,6 +12,12 @@
<errors>
<error404>1</error404>
<!--
The value for error pages can be:
* A content item's integer ID (example: 1234)
* A content item's GUID ID (example: 26C1D84F-C900-4D53-B167-E25CC489DAC8)
* An XPath statement (example: //errorPages[@nodeName='My cool error']
-->
<!--
<error404>
<errorPage culture="default">1</errorPage>
@@ -118,33 +118,10 @@
<useDomainPrefixes>false</useDomainPrefixes>
<!-- this will add a trailing slash (/) to urls when in directory url mode -->
<addTrailingSlash>true</addTrailingSlash>
<urlReplacing removeDoubleDashes="true">
<urlReplacing removeDoubleDashes="true" toAscii="true">
<char org=" ">-</char>
<char org="&quot;"></char>
<char org="'"></char>
<char org="%"></char>
<char org="."></char>
<char org=";"></char>
<char org="/"></char>
<char org="\"></char>
<char org=":"></char>
<char org="#"></char>
<char org="+">plus</char>
<char org="*">star</char>
<char org="&amp;"></char>
<char org="?"></char>
<char org="æ">ae</char>
<char org="ø">oe</char>
<char org="å">aa</char>
<char org="ä">ae</char>
<char org="ö">oe</char>
<char org="ü">ue</char>
<char org="ß">ss</char>
<char org="Ä">ae</char>
<char org="Ö">oe</char>
<char org="|">-</char>
<char org="&lt;"></char>
<char org="&gt;"></char>
<char org="ö">oxxx</char>
<!--<char org="ü">ue</char>-->
</urlReplacing>
</requestHandler>

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