Compare commits

...

128 Commits

Author SHA1 Message Date
Mads Rasmussen 1dacbbdbf6 added dots to website/language selector 2016-03-16 11:09:06 +01:00
Mads Rasmussen f0b374c30b filter out selected item 2016-03-16 10:43:09 +01:00
Mads Rasmussen ec5feee1f3 WIP prototyping website/language selector 2016-03-16 09:26:34 +01:00
Simon Busborg 1d1d99ddad added variationsHelper service and toggler for content 2016-03-15 14:47:03 +01:00
Claus c306f94a6a Merge pull request #1154 from pynej/fix-stylesheet-tree-sync
Fix for issue causing the entire stylesheets tree to reload when …
2016-03-15 12:46:59 +01:00
Claus 11b2ec89fd Merge pull request #1167 from umbraco/temp-U4-8154
U4-8154 - bugfix Sql query expressions parsing
2016-03-15 12:36:52 +01:00
Claus 89596f00f1 Merge pull request #1151 from arknu/icon-transparency
Fix transparency for image icons in the tray
2016-03-15 09:54:36 +01:00
Claus 4fa6e70e72 Merge pull request #1140 from jamescoxhead/U4-7746
U4-7746 - use flat icon in partial views tree
2016-03-15 09:22:18 +01:00
Warren Buckley a5a0a84d46 Merge pull request #1163 from umbraco/temp-U4-7767
U4-7767 List View Filter needs debounce - many requests to handler me…
2016-03-14 16:12:19 +00:00
Warren Buckley 839431e6fa Merge pull request #1170 from umbraco/temp-U4-8157
U4-8157 Right-click on root node returns console error when it doesn'…
2016-03-14 14:28:39 +00:00
Stephan 5369a6fc56 Upgrade ModelsBuilder to 3.0.1 2016-03-14 13:37:49 +01:00
Claus 8a078e258f U4-8157 Right-click on root node returns console error when it doesn't has any actions
Ensured we don't use throw to stop the program flow if no menuUrl is defined on the node. It is a likely scenario that some root node don't have right click actions so its better to handle this.
2016-03-14 12:15:15 +01:00
Sebastiaan Janssen fb42574c34 Revert "U4-5334 Richtext editor inserts extra p - tags to html output" - apparently it does just as much harm as it does good
This reverts commit 9ad3b6a337.
2016-03-12 21:02:05 +01:00
Sebastiaan Janssen 9ad3b6a337 U4-5334 Richtext editor inserts extra p - tags to html output
#U4-5334 Fixed
2016-03-12 12:58:53 +01:00
Stephan 65b16fbfe5 U4-8154 - bugfix Sql query expressions parsing 2016-03-11 14:18:08 +01:00
Stephan 6ad2853bce Merge pull request #1165 from umbraco/temp-U4-7949
U4-7949 The task runner has completed YSOD when using the Umbraco Pac…
2016-03-10 18:29:08 +01:00
Sebastiaan Janssen b2407eab98 Merge pull request #1107 from bjarnef/dev-v7-tinymce-font-icons
Change icons for richtext editor config
2016-03-10 17:47:46 +01:00
Shannon 778c7a836b Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2016-03-10 15:52:43 +01:00
Shannon 11f9cdead0 U4-6366 Issue assigning member roles on MemberService.Saved event 2016-03-10 15:52:34 +01:00
Sebastiaan Janssen a1076d5443 Merge pull request #1160 from umbraco/temp-U4-6438
U4-6438 - fix dynamic extension methods when type loading goes bad
2016-03-10 15:49:15 +01:00
Shannon 4a11bf68f3 U4-7949 The task runner has completed YSOD when using the Umbraco Package installer 2016-03-10 15:23:52 +01:00
Sebastiaan Janssen fa64e73a43 Merge pull request #1164 from umbraco/temp-U4-5797
U4-5797 - fix PublishedContentType cache refresh for compositions
2016-03-10 14:04:46 +01:00
Stephan adf3e2dfe0 U4-5797 - fix PublishedContentType cache refresh for compositions 2016-03-10 13:59:50 +01:00
Shannon c4c86cf5ce U4-7767 List View Filter needs debounce - many requests to handler method 2016-03-10 13:02:20 +01:00
Sebastiaan Janssen 479aba8e1d Fixes unit test.. in the correct branch this time 2016-03-10 11:47:51 +01:00
Shannon 0c474e2aba U4-7670 True/false fields on Macro Picker don't save their setting nor read existing setting. - another null check required. 2016-03-10 10:06:20 +01:00
Shannon Deminick 4f5b34cdfe Merge pull request #1162 from pynej/codemirror-js-error
Fix for missing doc.setLine() function breaking code mirror editor.
2016-03-10 09:58:16 +01:00
Warren Buckley 0cb7f220ea Merge pull request #1149 from umbraco/temp-U4-4700
U4-4700 List View Doesn't Respect User Permissions
2016-03-10 08:52:38 +00:00
Jeremy Pyne 0995b2cb5a Fix for missing doc.setLine() function breaking code mirror editor. 2016-03-09 14:55:15 -05:00
Stephan 1b37475144 U4-6438 - fix dynamic extension methods when type loading goes bad 2016-03-09 15:55:41 +01:00
Shannon be0bacd895 Ensures all angular views are cache busted so browser cache is not an issue after upgrading. 2016-03-08 17:23:54 +01:00
Shannon a2564bd0c3 ensures that requests are only made for ids that haven't already been queried. 2016-03-08 16:18:33 +01:00
Shannon 402a5c9d56 fixes bool check 2016-03-08 15:57:59 +01:00
Shannon 2a2f22c7d9 fixes js null issue with boolean.controller 2016-03-08 15:53:45 +01:00
Shannon 372a768dca U4-4700 List view doesn't respect user permissions - makes the buttons show/hide based on the selected items instead of the current item. 2016-03-08 15:53:22 +01:00
Sebastiaan Janssen f6e48243a6 U4-8088 NuGet upgrade of UmbracoCms pacakage doesn't add ModelsBuilder keys to web.config 2016-03-08 13:39:35 +01:00
Warren Buckley 94ea677ec0 Merge pull request #1146 from umbraco/temp-U4-7641
U4-7641 - enable content type copy
2016-03-08 09:38:16 +00:00
Sebastiaan Janssen 55e7159f7d Forgot to remove them from the nuspec files 2016-03-08 10:35:57 +01:00
Sebastiaan Janssen 390a94e323 U4-8054 Issue with NuGet Uninstall.ps1 (running on updates)
#U4-8054 Fixed
2016-03-08 10:34:19 +01:00
Shannon Deminick 19fb920aa1 Merge pull request #1150 from umbraco/temp-U4-7823
U4-7823 - stop flooding the log with errors getting media 0
2016-03-07 17:58:49 +01:00
Shannon Deminick f35e1604ca Merge pull request #1141 from umbraco/temp-U4-8030
U4-8030 - Fix RenderModelBinder issue with surface
2016-03-07 17:53:31 +01:00
Shannon b9765c3bec fixes RenderModelBinder to use base implementation,adds unit tests 2016-03-07 17:52:28 +01:00
Shannon d5a57c505c adds RenderModelBinderTests 2016-03-07 16:53:57 +01:00
Shannon 5f365241a8 updates RenderModelBinder to simply check for IPublishedContent or IRenderModel 2016-03-07 16:29:40 +01:00
Shannon 9c121f0044 Fixes RenderModelBinder to inherit from DefaultModelBinder and use the default logic if the model in the route values is not IRenderModel 2016-03-07 16:26:30 +01:00
Shannon f13bc07ddc Merge branch 'dev-v7' of https://github.com/umbraco/Umbraco-CMS into dev-v7 2016-03-07 15:13:41 +01:00
Shannon a707d23692 Allows for specifying explicit product names by overriding the property in MigrationStartupHander 2016-03-07 15:13:31 +01:00
Simon Busborg 0929b7d42c Fixes U4-8113 Styling for property labels affect package meta data labels 2016-03-07 14:55:18 +01:00
Simon Busborg 35a9272b68 Fixes U4-8036 Umbraco.MultiNodeTreePicker checkbox doesn't appear after selecting something from list view 2016-03-07 14:45:30 +01:00
Shannon Deminick 112453a032 Merge pull request #1144 from umbraco/temp-U4-8077
U4-8077 - ensure product name in migration event handlers
2016-03-07 14:09:29 +01:00
Simon Busborg bba7367ba6 Fixes U4-8058 Labels are changed to block-level elements 2016-03-07 12:12:35 +01:00
Jeremy Pyne 83e679ba5e Fix for issue causing the entire stylesheets tree to reload when selecting a item. 2016-03-02 16:00:33 -05:00
Sebastiaan Janssen 05c35b22bd Merge pull request #1148 from umbraco/temp-U4-7040
U4-7040 - Fix bug with permissions cache refresh
2016-03-02 15:03:47 +01:00
Asbjørn Riis-Knudsen 4d950fb4d4 Fix transparency for image icons in the tray 2016-02-28 17:40:58 +01:00
Stephan 0d191fb8bd U4-7823 - stop flooding the log with errors getting media 0 2016-02-26 11:35:24 +01:00
Mads Rasmussen f6318fb6f3 Merge pull request #1147 from lars-erik/fix-u4-8082-nested-forms-and-submit-bug
Fixes: U4-8082 New overlays post forms in IE / Edge
2016-02-26 10:08:51 +01:00
Warren Buckley c7a3efadb1 Remove debug JSON in the view 2016-02-25 21:09:12 +00:00
Warren Buckley 956425dfbf Now updated so the create button hides if we do not have the Create permission 'C' 2016-02-25 21:06:25 +00:00
Warren Buckley c616354522 After reading src code for contentEditorHelper.configureContentEditorButtons it makes the same assumption that if the publish action 'U' is present then the user can also unpublish aka 'Z' 2016-02-25 20:49:56 +00:00
Stephan 17b29357d4 U4-7040 - Fix bug with permissions cache refresh 2016-02-25 17:43:38 +01:00
Stephan 36246b96d4 Fix bug with permissions cache refresh 2016-02-25 17:39:34 +01:00
Stephan 7d8791ec86 Fix ActionButtonsResolver (need review) 2016-02-25 17:05:44 +01:00
Stephan f349a9ae3e U4-7641 - bugfix 2016-02-25 16:26:20 +01:00
Warren Buckley 2719e2c231 WIP - ListView that grabs the current nodes permission from the editorState & use a neater object to return to the view rather than the lovely Magic String CHARs. Need help understanding that I don't get all the permissions to be expected 2016-02-25 15:19:42 +00:00
Lars-Erik Aabech 57a766098d Removed nested form and changed buttons to type="button" + action instead of ng-submit on form. 2016-02-25 16:04:37 +01:00
Stephan dafde545b0 U4-7641 - bugfix + implement for media types 2016-02-25 16:02:04 +01:00
Stephan 610538261e U4-7641 - enable content type copy 2016-02-25 15:26:03 +01:00
Simon Busborg f78cb8a970 Merge pull request #1119 from jchurchley/dev-v7
Fixes U4-7963 Listview columns not evenly spaced in Chrome
2016-02-25 14:52:17 +01:00
Sebastiaan Janssen def276de01 Merge pull request #1143 from umbraco/temp-U4-8027
U4-8027 - fix ApplicationContext request cache (was null cache)
2016-02-25 10:46:31 +01:00
Stephan 293b170a56 U4-8027 - fix ApplicationContext request cache (was null cache) 2016-02-24 14:16:48 +01:00
Stephan 9f7b82e20f U4-8077 - ensure product name in migration event handlers 2016-02-24 13:59:15 +01:00
Warren Buckley 6ba4efc416 Merge pull request #1142 from umbraco/temp-U4-7570
Temp u4 7570
2016-02-24 11:12:59 +00:00
Simon Busborg 981fb39af6 Fixed crop slider 2016-02-24 09:14:13 +01:00
Sebastiaan Janssen c64f6f894e U4-8024 Unable to use MvcBuildViews since 7.4.0 upgrade because 'umbraco.cms.presentation.create.controls.content' has been removed
Removes files for which the codebehind no longer exists
2016-02-23 17:23:55 +01:00
Simon Busborg 3e73c2da43 Fixed width of cropper 2016-02-23 16:31:10 +01:00
Mads Rasmussen 26a8d23039 Fixes: U4-8063 Content type editor: Keyboard shortcut overview should close on escape 2016-02-23 15:09:27 +01:00
Mads Rasmussen 2632ef740c Fixes: U4-7570 Hide image, focal point and remove link until image has loaded 2016-02-23 13:55:05 +01:00
Sebastiaan Janssen f024dba864 Merge pull request #1139 from umbraco/temp-U4-8017
U4-8017 - fix issues with MySql InitColumnTypeMap
2016-02-22 19:05:41 +01:00
Stephan 9758851a4b Fix SqlCeSyntaxProviderTests 2016-02-22 18:55:49 +01:00
Stephan 04b3532e9d U4-8030 - Fix RenderModelBinder issue with surface 2016-02-22 18:38:06 +01:00
Sebastiaan Janssen 38e56f0fea Might make the build server happy? 2016-02-22 17:57:44 +01:00
Sebastiaan Janssen 462baf91e4 Merge pull request #1137 from umbraco/temp-U4-7914
U4-7914 - add PublishedContentRequest.Preparing event
2016-02-22 17:45:50 +01:00
James Coxhead 01bcd3b623 Changed partial views icon to icon-article 2016-02-22 16:15:31 +00:00
James Coxhead 64fd95bd22 Updated tree icons for partial views and partial view macros 2016-02-22 16:13:25 +00:00
Stephan f1366c7d29 U4-8017 - fix issues with MySql InitColumnTypeMap 2016-02-19 13:33:11 +01:00
Warren Buckley baaa9340e4 Merge pull request #1131 from umbraco/temp-U4-7918
Fixes U4-7918 Make icon picker for document type and list views consistent
2016-02-19 12:03:27 +00:00
Mads Rasmussen 183a5b5c43 U4-7472: fix macro parameter column width 2016-02-19 09:52:29 +01:00
Mads Rasmussen 1a0c095f40 Merge pull request #932 from engern/MacroParamSortOrder
Fixes U4-7472 - Should be possible to sort macro parameters
2016-02-19 09:27:27 +01:00
Stephan ffada74aa4 Improve RenderModelBinder error msg when same type, different assemblies 2016-02-18 16:04:45 +01:00
Mads Rasmussen f2fc70f731 Merge pull request #982 from abryukhov/patch-4
U4-7616 - Nodes sort dialog - additional date formats
2016-02-18 14:19:06 +01:00
Simon Busborg 866b0113e7 Fixes grunt break 2016-02-18 12:43:09 +01:00
Simon Busborg 06c49daca7 Merge branch 'dev-v7-login-retina-umbraco-logo' of git://github.com/bjarnef/Umbraco-CMS into bjarnef-dev-v7-login-retina-umbraco-logo
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/less/pages/login.less
2016-02-18 12:42:17 +01:00
Stephan 9293008b94 U4-7914 - add PublishedContentRequest.Preparing event 2016-02-18 11:36:48 +01:00
Mads Rasmussen dbb9386d22 Fixes: U4-7660 [7.4 Fix] Added a default value to the Umbaco.TrueFalse datatype. Thanks Jeremy Pyne 2016-02-18 11:20:04 +01:00
Mads Rasmussen 51ed441b85 Merge branch 'u4-5123' of https://github.com/AndyButland/Umbraco-CMS into AndyButland-u4-5123
# Conflicts:
#	src/Umbraco.Web/PropertyEditors/ListViewPropertyEditor.cs
2016-02-18 10:00:22 +01:00
Simon Busborg f566fec665 Merge branch 'Acentrage-U4-6700' into dev-v7 2016-02-17 15:26:51 +01:00
Mads Rasmussen 9d92781a97 Merge pull request #949 from kgiszewski/dev-v7
Fix u4-7534
2016-02-17 15:04:14 +01:00
Simon Busborg 123bfe5afe Fixed merge conflict 2016-02-17 14:31:30 +01:00
Shannon Deminick 3383d2a2ac Merge pull request #1135 from umbraco/temp-U4-7601
U4-7601 - filter published content by composition
2016-02-17 13:31:07 +01:00
Stephan cc6dfd0c55 U4-7601 - refactor PR, case insensitive 2016-02-17 12:55:40 +01:00
Stephan d4802fcef6 Merge branch 'feature/is-composed-of' of https://github.com/AndyButland/Umbraco-CMS into temp-U4-7601 2016-02-17 12:44:18 +01:00
John Churchley 65c97040b3 Fix Chrome issue listview columns not evenly spaced
http://issues.umbraco.org/issue/U4-7963#
2016-02-15 12:17:13 +00:00
Simon Busborg 0f8a13d60a 7 in a row instead of 8, bumped font-size on icons to 30 2016-02-12 10:17:42 +01:00
Simon Busborg 5c1502c806 Removes umb-control-group when no icons displayed 2016-02-12 10:13:30 +01:00
Simon Busborg 3cdebf4427 Fixes U4-7918 Make icon picker for document type and list views consistent 2016-02-12 09:38:37 +01:00
bjarnef 5176b68935 Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7-tinymce-font-icons 2016-02-08 15:07:36 +01:00
bjarnef 0bfc5f1272 Change icons in tinymce config 2016-02-08 15:07:16 +01:00
bjarnef 39c18d4201 Merge branch 'dev-v7' of https://github.com/bjarnef/Umbraco-CMS into dev-v7 2016-02-05 15:54:48 +01:00
bjarnef 66ea8ae604 Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2016-02-05 14:55:53 +01:00
bjarnef 6fc794ca2e Merge branch 'dev-v7' of https://github.com/bjarnef/Umbraco-CMS into dev-v7 2016-02-03 14:42:14 +01:00
bjarnef df958223b0 Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2016-01-26 18:17:00 +01:00
bjarnef 1217d9f0b3 Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2016-01-24 23:25:29 +01:00
bjarnef 1301897f39 Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2016-01-22 22:02:51 +01:00
bjarnef 6d34fe416d Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2016-01-21 20:38:52 +01:00
bjarnef a884ece8b1 Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2016-01-21 18:15:50 +01:00
bjarnef 0ffcc9b889 Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2016-01-20 19:21:58 +01:00
bjarnef ee3131b63d Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2016-01-19 21:03:42 +01:00
bjarnef 4fd7182388 Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2016-01-19 20:56:36 +01:00
Alexander Bryukhov ae85b7bf2b Nodes sort dialog - adding date formats
Adding dates processing for 'dd.MM.yyyy' formats
2015-12-28 23:00:08 +06:00
AndyButland b52c480da3 Added IPublishedContent extension method for filtering nodes based on composition alias
Created unit test for IsComposedOf
2015-12-22 16:27:12 +01:00
kgiszewski dada91f006 Fix u4-7534 2015-12-14 13:35:46 -05:00
engern 348694d9d4 Use same color as the rest 2015-11-29 12:22:22 +01:00
engern 855e3b3dcc Add the possibility to sort the macro parameters 2015-11-29 12:06:19 +01:00
engern 5a8ea4aa41 Merge branch 'dev-v7' of https://github.com/engern/Umbraco-CMS into dev-v7 2015-11-29 09:38:36 +01:00
engern 4bd465f666 Merge remote-tracking branch 'refs/remotes/umbraco/dev-v7' into dev-v7 2015-11-29 09:38:20 +01:00
Tommy Enger ad591c07cf Merge pull request #1 from umbraco/dev-v7
Update from original
2015-11-29 09:37:54 +01:00
bjarnef cd3aaa47ca Add retina version of Umbraco logo in login screen 2015-11-19 00:25:05 +01:00
AndyButland a05cc03254 Allows position of the list view child items tab to be positioned within the tab list 2015-11-15 21:18:21 +01:00
139 changed files with 3624 additions and 1588 deletions
-1
View File
@@ -72,7 +72,6 @@
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.dll" target="lib\UmbracoExamine.dll" />
<file src="..\_BuildOutput\WebApp\bin\UmbracoExamine.xml" target="lib\UmbracoExamine.xml" />
<file src="tools\install.core.ps1" target="tools\install.ps1" />
<file src="tools\uninstall.core.ps1" target="tools\uninstall.ps1" />
<!-- Added to be able to produce a symbols package -->
<file src="..\_BuildOutput\bin\SQLCE4Umbraco.pdb" target="lib" />
-1
View File
@@ -33,7 +33,6 @@
<file src="..\_BuildOutput\WebApp\umbraco\**" target="UmbracoFiles\umbraco" />
<file src="..\_BuildOutput\WebApp\umbraco_client\**" target="UmbracoFiles\umbraco_client" />
<file src="tools\install.ps1" target="tools\install.ps1" />
<file src="tools\uninstall.ps1" target="tools\uninstall.ps1" />
<file src="tools\Readme.txt" target="tools\Readme.txt" />
<file src="tools\ReadmeUpgrade.txt" target="tools\ReadmeUpgrade.txt" />
<file src="tools\Web.config.install.xdt" target="Content\Web.config.install.xdt" />
@@ -21,6 +21,8 @@
<appSettings xdt:Transform="InsertIfMissing" />
<appSettings>
<add key="owin:appStartup" value="UmbracoDefaultOwinStartup" xdt:Locator="Match(key)" xdt:Transform="InsertIfMissing" />
<add key="Umbraco.ModelsBuilder.Enable" value="false" xdt:Locator="Match(key)" xdt:Transform="InsertIfMissing" />
<add key="Umbraco.ModelsBuilder.ModelsMode" value="Nothing" xdt:Locator="Match(key)" xdt:Transform="InsertIfMissing" />
</appSettings>
<umbracoConfiguration xdt:Transform="InsertIfMissing">
-48
View File
@@ -1,48 +0,0 @@
param($installPath, $toolsPath, $package, $project)
Write-Host "installPath:" "${installPath}"
Write-Host "toolsPath:" "${toolsPath}"
Write-Host " "
if ($project) {
# Create paths and list them
$projectPath = (Get-Item $project.Properties.Item("FullPath").Value).FullName
Write-Host "projectPath:" "${projectPath}"
$backupPath = Join-Path $projectPath "App_Data\NuGetBackup"
Write-Host "backupPath:" "${backupPath}"
$umbracoBinFolder = Join-Path $projectPath "bin"
Write-Host "umbracoBinFolder:" "${umbracoBinFolder}"
# Remove backups
Write-Host "removing backups:" "${backupPath}"
if(Test-Path $backupPath) { Remove-Item -Recurse -Force $backupPath -Confirm:$false }
# Delete files Umbraco ships with
Write-Host "removing dlls:" "${umbracoBinFolder}"
if(Test-Path $umbracoBinFolder\businesslogic.dll) { Remove-Item $umbracoBinFolder\businesslogic.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\cms.dll) { Remove-Item $umbracoBinFolder\cms.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\controls.dll) { Remove-Item $umbracoBinFolder\controls.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\interfaces.dll) { Remove-Item $umbracoBinFolder\interfaces.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\log4net.dll) { Remove-Item $umbracoBinFolder\log4net.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Microsoft.ApplicationBlocks.Data.dll) { Remove-Item $umbracoBinFolder\Microsoft.ApplicationBlocks.Data.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\SQLCE4Umbraco.dll) { Remove-Item $umbracoBinFolder\SQLCE4Umbraco.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Data.SqlServerCe.dll) { Remove-Item $umbracoBinFolder\System.Data.SqlServerCe.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\System.Data.SqlServerCe.Entity.dll) { Remove-Item $umbracoBinFolder\System.Data.SqlServerCe.Entity.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\TidyNet.dll) { Remove-Item $umbracoBinFolder\TidyNet.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\umbraco.dll) { Remove-Item $umbracoBinFolder\umbraco.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Umbraco.Core.dll) { Remove-Item $umbracoBinFolder\Umbraco.Core.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\umbraco.DataLayer.dll) { Remove-Item $umbracoBinFolder\umbraco.DataLayer.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\umbraco.editorControls.dll) { Remove-Item $umbracoBinFolder\umbraco.editorControls.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\umbraco.MacroEngines.dll) { Remove-Item $umbracoBinFolder\umbraco.MacroEngines.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\umbraco.providers.dll) { Remove-Item $umbracoBinFolder\umbraco.providers.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\Umbraco.Web.UI.dll) { Remove-Item $umbracoBinFolder\Umbraco.Web.UI.dll -Force -Confirm:$false }
if(Test-Path $umbracoBinFolder\UmbracoExamine.dll) { Remove-Item $umbracoBinFolder\UmbracoExamine.dll -Force -Confirm:$false }
$amd64Folder = Join-Path $umbracoBinFolder "amd64"
if(Test-Path $amd64Folder) { Remove-Item $amd64Folder -Force -Recurse -Confirm:$false }
$x86Folder = Join-Path $umbracoBinFolder "x86"
if(Test-Path $x86Folder) { Remove-Item $x86Folder -Force -Recurse -Confirm:$false }
}
-39
View File
@@ -1,39 +0,0 @@
param($installPath, $toolsPath, $package, $project)
Write-Host "installPath:" "${installPath}"
Write-Host "toolsPath:" "${toolsPath}"
Write-Host " "
if ($project) {
# Create paths and list them
$projectPath = (Get-Item $project.Properties.Item("FullPath").Value).FullName
Write-Host "projectPath:" "${projectPath}"
$backupPath = Join-Path $projectPath "App_Data\NuGetBackup"
Write-Host "backupPath:" "${backupPath}"
$appBrowsers = Join-Path $projectPath "App_Browsers"
Write-Host "appBrowsers:" "${appBrowsers}"
$appData = Join-Path $projectPath "App_Data"
Write-Host "appData:" "${appData}"
# Remove backups
Write-Host "removing backups:" "${backupPath}"
if(Test-Path $backupPath) { Remove-Item -Recurse -Force $backupPath -Confirm:$false }
# Remove app_data files
Write-Host "removing app_data files:" "${appData}"
if(Test-Path $appData\packages) { Remove-Item $appData\packages -Recurse -Force -Confirm:$false }
Write-Host "removing app_browsers:" "${appBrowsers}"
if(Test-Path $appBrowsers\Form.browser) { Remove-Item $appBrowsers\Form.browser -Force -Confirm:$false }
if(Test-Path $appBrowsers\w3cvalidator.browser) { Remove-Item $appBrowsers\w3cvalidator.browser -Force -Confirm:$false }
# Remove umbraco and umbraco_files
$umbracoFolder = Join-Path $projectPath "Umbraco"
Write-Host "removing umbraco folder:" "${umbracoFolder}"
if(Test-Path $umbracoFolder) { Remove-Item $umbracoFolder -Recurse -Force -Confirm:$false }
$umbracoClientFolder = Join-Path $projectPath "Umbraco_Client"
Write-Host "removing umbraco client folder:" "${umbracoClientFolder}"
if(Test-Path $umbracoClientFolder) { Remove-Item $umbracoClientFolder -Recurse -Force -Confirm:$false }
}
@@ -5,8 +5,10 @@ using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Linq.Expressions;
using System.Text;
using System.Web.Services.Description;
using Umbraco.Core.Cache;
using Umbraco.Core.Logging;
namespace Umbraco.Core.Dynamics
{
@@ -20,6 +22,20 @@ namespace Umbraco.Core.Dynamics
/// </summary>
private static readonly ConcurrentDictionary<Tuple<Type, string, int>, MethodInfo[]> MethodCache = new ConcurrentDictionary<Tuple<Type, string, int>, MethodInfo[]>();
private static IEnumerable<Type> GetTypes(Assembly a)
{
try
{
return TypeFinder.GetTypesWithFormattedException(a);
}
catch (ReflectionTypeLoadException ex)
{
// is this going to flood the log?
LogHelper.Error(typeof (ExtensionMethodFinder), "Failed to get types.", ex);
return Enumerable.Empty<Type>();
}
}
/// <summary>
/// Returns the enumerable of all extension method info's in the app domain = USE SPARINGLY!!!
/// </summary>
@@ -36,7 +52,7 @@ namespace Umbraco.Core.Dynamics
// assemblies that contain extension methods
.Where(a => a.IsDefined(typeof (ExtensionAttribute), false))
// types that contain extension methods
.SelectMany(a => a.GetTypes()
.SelectMany(a => GetTypes(a)
.Where(t => t.IsDefined(typeof (ExtensionAttribute), false) && t.IsSealed && t.IsGenericType == false && t.IsNested == false))
// actual extension methods
.SelectMany(t => t.GetMethods(BindingFlags.Static | BindingFlags.Public)
@@ -45,9 +61,9 @@ namespace Umbraco.Core.Dynamics
.Concat(typeof (Enumerable).GetMethods(BindingFlags.Static | BindingFlags.Public))
//If we don't do this then we'll be scanning all assemblies each time!
.ToArray(),
//only cache for 5 minutes
timeout: TimeSpan.FromMinutes(5),
timeout: TimeSpan.FromMinutes(5),
//each time this is accessed it will be for 5 minutes longer
isSliding:true);
@@ -57,7 +73,7 @@ namespace Umbraco.Core.Dynamics
/// Returns all extension methods found matching the definition
/// </summary>
/// <param name="runtimeCache">
/// The runtime cache is used to temporarily cache all extension methods found in the app domain so that
/// The runtime cache is used to temporarily cache all extension methods found in the app domain so that
/// while we search for individual extension methods, the process will be reasonably 'quick'. We then statically
/// cache the MethodInfo's that we are looking for and then the runtime cache will expire and give back all that memory.
/// </param>
@@ -78,7 +94,7 @@ namespace Umbraco.Core.Dynamics
{
var candidates = GetAllExtensionMethodsInAppDomain(runtimeCache);
// filter by name
// filter by name
var filtr1 = candidates.Where(m => m.Name == name);
// filter by args count
@@ -102,7 +118,7 @@ namespace Umbraco.Core.Dynamics
return filtr3.ToArray();
});
}
private static MethodInfo DetermineMethodFromParams(IEnumerable<MethodInfo> methods, Type genericType, IEnumerable<object> args)
@@ -123,12 +139,12 @@ namespace Umbraco.Core.Dynamics
types = method.GetParameters().Select(pi => pi.ParameterType).Skip(1)
});
//This type comparer will check
//This type comparer will check
var typeComparer = new DelegateEqualityComparer<Type>(
//Checks if the argument type passed in can be assigned from the parameter type in the method. For
//Checks if the argument type passed in can be assigned from the parameter type in the method. For
// example, if the argument type is HtmlHelper<MyModel> but the method parameter type is HtmlHelper then
// it will match because the argument is assignable to that parameter type and will be able to execute
TypeHelper.IsTypeAssignableFrom,
TypeHelper.IsTypeAssignableFrom,
//This will not ever execute but if it does we need to get the hash code of the string because the hash
// code of a type is random
type => type.FullName.GetHashCode());
@@ -159,7 +175,7 @@ namespace Umbraco.Core.Dynamics
.ToArray();
var methods = GetAllExtensionMethods(runtimeCache, thisType, name, args.Length).ToArray();
return DetermineMethodFromParams(methods, genericType, args);
}
}
+63 -24
View File
@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.ComponentModel;
using Semver;
using Umbraco.Core.Configuration;
using Umbraco.Core.Persistence.Migrations;
namespace Umbraco.Core.Events
@@ -13,23 +14,49 @@ namespace Umbraco.Core.Events
/// </summary>
/// <param name="eventObject"></param>
/// <param name="targetVersion"></param>
/// <param name="productName"></param>
/// <param name="canCancel"></param>
/// <param name="configuredVersion"></param>
public MigrationEventArgs(IList<IMigration> eventObject, SemVersion configuredVersion, SemVersion targetVersion, bool canCancel)
: base(eventObject, canCancel)
{
ConfiguredSemVersion = configuredVersion;
TargetSemVersion = targetVersion;
}
public MigrationEventArgs(IList<IMigration> eventObject, SemVersion configuredVersion, SemVersion targetVersion, string productName, bool canCancel)
: this(eventObject, null, configuredVersion, targetVersion, productName, canCancel)
{ }
[Obsolete("Use constructor accepting UmbracoVersion instances instead")]
/// <summary>
/// Constructor accepting multiple migrations that are used in the migration runner
/// </summary>
/// <param name="eventObject"></param>
/// <param name="targetVersion"></param>
/// <param name="canCancel"></param>
/// <param name="configuredVersion"></param>
[Obsolete("Use constructor accepting a product name instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public MigrationEventArgs(IList<IMigration> eventObject, SemVersion configuredVersion, SemVersion targetVersion, bool canCancel)
: this(eventObject, null, configuredVersion, targetVersion, GlobalSettings.UmbracoMigrationName, canCancel)
{ }
[Obsolete("Use constructor accepting SemVersion instances and a product name instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public MigrationEventArgs(IList<IMigration> eventObject, Version configuredVersion, Version targetVersion, bool canCancel)
: base(eventObject, canCancel)
{
ConfiguredSemVersion = new SemVersion(configuredVersion);
TargetSemVersion = new SemVersion(targetVersion);
}
: this(eventObject, null, new SemVersion(configuredVersion), new SemVersion(targetVersion), GlobalSettings.UmbracoMigrationName, canCancel)
{ }
/// <summary>
/// Constructor accepting multiple migrations that are used in the migration runner
/// </summary>
/// <param name="eventObject"></param>
/// <param name="migrationContext"></param>
/// <param name="targetVersion"></param>
/// <param name="productName"></param>
/// <param name="canCancel"></param>
/// <param name="configuredVersion"></param>
internal MigrationEventArgs(IList<IMigration> eventObject, MigrationContext migrationContext, SemVersion configuredVersion, SemVersion targetVersion, string productName, bool canCancel)
: base(eventObject, canCancel)
{
MigrationContext = migrationContext;
ConfiguredSemVersion = configuredVersion;
TargetSemVersion = targetVersion;
ProductName = productName;
}
/// <summary>
/// Constructor accepting multiple migrations that are used in the migration runner
@@ -39,12 +66,15 @@ namespace Umbraco.Core.Events
/// <param name="targetVersion"></param>
/// <param name="canCancel"></param>
/// <param name="configuredVersion"></param>
[Obsolete("Use constructor accepting a product name instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
internal MigrationEventArgs(IList<IMigration> eventObject, MigrationContext migrationContext, SemVersion configuredVersion, SemVersion targetVersion, bool canCancel)
: base(eventObject, canCancel)
{
MigrationContext = migrationContext;
ConfiguredSemVersion = configuredVersion;
TargetSemVersion = targetVersion;
ProductName = GlobalSettings.UmbracoMigrationName;
}
/// <summary>
@@ -53,21 +83,28 @@ namespace Umbraco.Core.Events
/// <param name="eventObject"></param>
/// <param name="configuredVersion"></param>
/// <param name="targetVersion"></param>
public MigrationEventArgs(IList<IMigration> eventObject, SemVersion configuredVersion, SemVersion targetVersion)
: base(eventObject)
{
ConfiguredSemVersion = configuredVersion;
TargetSemVersion = targetVersion;
}
/// <param name="productName"></param>
public MigrationEventArgs(IList<IMigration> eventObject, SemVersion configuredVersion, SemVersion targetVersion, string productName)
: this(eventObject, null, configuredVersion, targetVersion, productName, false)
{ }
[Obsolete("Use constructor accepting UmbracoVersion instances instead")]
/// <summary>
/// Constructor accepting multiple migrations that are used in the migration runner
/// </summary>
/// <param name="eventObject"></param>
/// <param name="configuredVersion"></param>
/// <param name="targetVersion"></param>
[Obsolete("Use constructor accepting a product name instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public MigrationEventArgs(IList<IMigration> eventObject, SemVersion configuredVersion, SemVersion targetVersion)
: this(eventObject, null, configuredVersion, targetVersion, GlobalSettings.UmbracoMigrationName, false)
{ }
[Obsolete("Use constructor accepting SemVersion instances and a product name instead.")]
[EditorBrowsable(EditorBrowsableState.Never)]
public MigrationEventArgs(IList<IMigration> eventObject, Version configuredVersion, Version targetVersion)
: base(eventObject)
{
ConfiguredSemVersion = new SemVersion(configuredVersion);
TargetSemVersion = new SemVersion(targetVersion);
}
: this(eventObject, null, new SemVersion(configuredVersion), new SemVersion(targetVersion), GlobalSettings.UmbracoMigrationName, false)
{ }
/// <summary>
/// Returns all migrations that were used in the migration runner
@@ -95,6 +132,8 @@ namespace Umbraco.Core.Events
public SemVersion TargetSemVersion { get; private set; }
public string ProductName { get; private set; }
internal MigrationContext MigrationContext { get; private set; }
}
}
+7 -1
View File
@@ -7,6 +7,12 @@ namespace Umbraco.Core.Models
/// </summary
public interface IMediaType : IContentTypeComposition
{
/// <summary>
/// Creates a deep clone of the current entity with its identity/alias and it's property identities reset
/// </summary>
/// <param name="newAlias"></param>
/// <returns></returns>
IMediaType DeepCloneWithResetIdentities(string newAlias);
}
}
+25
View File
@@ -38,5 +38,30 @@ namespace Umbraco.Core.Models
: base(parent, alias)
{
}
/// <summary>
/// Creates a deep clone of the current entity with its identity/alias and it's property identities reset
/// </summary>
/// <returns></returns>
public IMediaType DeepCloneWithResetIdentities(string alias)
{
var clone = (MediaType)DeepClone();
clone.Alias = alias;
clone.Key = Guid.Empty;
foreach (var propertyGroup in clone.PropertyGroups)
{
propertyGroup.ResetIdentity();
propertyGroup.ResetDirtyProperties(false);
}
foreach (var propertyType in clone.PropertyTypes)
{
propertyType.ResetIdentity();
propertyType.ResetDirtyProperties(false);
}
clone.ResetIdentity();
clone.ResetDirtyProperties(false);
return clone;
}
}
}
@@ -1,9 +1,6 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Web.Caching;
using System.Web.UI;
using Umbraco.Core.Cache;
namespace Umbraco.Core.Models.PublishedContent
@@ -16,6 +13,7 @@ namespace Umbraco.Core.Models.PublishedContent
public class PublishedContentType
{
private readonly PublishedPropertyType[] _propertyTypes;
private readonly HashSet<string> _compositionAliases;
// fast alias-to-index xref containing both the raw alias and its lowercase version
private readonly Dictionary<string, int> _indexes = new Dictionary<string, int>();
@@ -27,6 +25,7 @@ namespace Umbraco.Core.Models.PublishedContent
{
Id = contentType.Id;
Alias = contentType.Alias;
_compositionAliases = new HashSet<string>(contentType.CompositionAliases(), StringComparer.InvariantCultureIgnoreCase);
_propertyTypes = contentType.CompositionPropertyTypes
.Select(x => new PublishedPropertyType(this, x))
.ToArray();
@@ -34,10 +33,11 @@ namespace Umbraco.Core.Models.PublishedContent
}
// internal so it can be used for unit tests
internal PublishedContentType(int id, string alias, IEnumerable<PublishedPropertyType> propertyTypes)
internal PublishedContentType(int id, string alias, IEnumerable<string> compositionAliases, IEnumerable<PublishedPropertyType> propertyTypes)
{
Id = id;
Alias = alias;
_compositionAliases = new HashSet<string>(compositionAliases, StringComparer.InvariantCultureIgnoreCase);
_propertyTypes = propertyTypes.ToArray();
foreach (var propertyType in _propertyTypes)
propertyType.ContentType = this;
@@ -45,8 +45,8 @@ namespace Umbraco.Core.Models.PublishedContent
}
// create detached content type - ie does not match anything in the DB
internal PublishedContentType(string alias, IEnumerable<PublishedPropertyType> propertyTypes)
: this (0, alias, propertyTypes)
internal PublishedContentType(string alias, IEnumerable<string> compositionAliases, IEnumerable<PublishedPropertyType> propertyTypes)
: this(0, alias, compositionAliases, propertyTypes)
{ }
private void InitializeIndexes()
@@ -63,6 +63,7 @@ namespace Umbraco.Core.Models.PublishedContent
public int Id { get; private set; }
public string Alias { get; private set; }
public HashSet<string> CompositionAliases { get { return _compositionAliases; } }
#endregion
@@ -113,10 +114,25 @@ namespace Umbraco.Core.Models.PublishedContent
internal static void ClearContentType(int id)
{
Logging.LogHelper.Debug<PublishedContentType>("Clear content type w/id {0}.", () => id);
// requires a predicate because the key does not contain the ID
// faster than key strings comparisons anyway
// we don't support "get all" at the moment - so, cheating
var all = ApplicationContext.Current.ApplicationCache.StaticCache.GetCacheItemsByKeySearch<PublishedContentType>("PublishedContentType_").ToArray();
// the one we want to clear
var clr = all.FirstOrDefault(x => x.Id == id);
if (clr == null) return;
// those that have that one in their composition aliases
// note: CompositionAliases contains all recursive aliases
var oth = all.Where(x => x.CompositionAliases.InvariantContains(clr.Alias)).Select(x => x.Id);
// merge ids
var ids = oth.Concat(new[] { clr.Id }).ToArray();
// clear them all at once
// we don't support "clear many at once" at the moment - so, cheating
ApplicationContext.Current.ApplicationCache.StaticCache.ClearCacheObjectTypes<PublishedContentType>(
(key, value) => value.Id == id);
(key, value) => ids.Contains(value.Id));
}
internal static void ClearDataType(int id)
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
@@ -27,18 +28,21 @@ namespace Umbraco.Core.Persistence.Migrations
private readonly IMigration[] _migrations;
[Obsolete("Use the ctor that specifies all dependencies instead")]
[EditorBrowsable(EditorBrowsableState.Never)]
public MigrationRunner(Version currentVersion, Version targetVersion, string productName)
: this(LoggerResolver.Current.Logger, currentVersion, targetVersion, productName)
{
}
[Obsolete("Use the ctor that specifies all dependencies instead")]
[EditorBrowsable(EditorBrowsableState.Never)]
public MigrationRunner(ILogger logger, Version currentVersion, Version targetVersion, string productName)
: this(logger, currentVersion, targetVersion, productName, null)
{
}
[Obsolete("Use the ctor that specifies all dependencies instead")]
[EditorBrowsable(EditorBrowsableState.Never)]
public MigrationRunner(ILogger logger, Version currentVersion, Version targetVersion, string productName, params IMigration[] migrations)
: this(ApplicationContext.Current.Services.MigrationEntryService, logger, new SemVersion(currentVersion), new SemVersion(targetVersion), productName, migrations)
{
@@ -92,7 +96,7 @@ namespace Umbraco.Core.Persistence.Migrations
: OrderedDowngradeMigrations(foundMigrations).ToList();
if (Migrating.IsRaisedEventCancelled(new MigrationEventArgs(migrations, _currentVersion, _targetVersion, true), this))
if (Migrating.IsRaisedEventCancelled(new MigrationEventArgs(migrations, _currentVersion, _targetVersion, _productName, true), this))
{
_logger.Warn<MigrationRunner>("Migration was cancelled by an event");
return false;
@@ -121,7 +125,7 @@ namespace Umbraco.Core.Persistence.Migrations
throw;
}
Migrated.RaiseEvent(new MigrationEventArgs(migrations, migrationContext, _currentVersion, _targetVersion, false), this);
Migrated.RaiseEvent(new MigrationEventArgs(migrations, migrationContext, _currentVersion, _targetVersion, _productName, false), this);
return true;
}
@@ -128,6 +128,34 @@ namespace Umbraco.Core.Persistence.Querying
right = Visit(b.Right);
}
}
else if (operand == "=")
{
// deal with (x == true|false) - most common
var constRight = b.Right as ConstantExpression;
if (constRight != null && constRight.Type == typeof (bool))
return ((bool) constRight.Value) ? VisitNotNot(b.Left) : VisitNot(b.Left);
right = Visit(b.Right);
// deal with (true|false == x) - why not
var constLeft = b.Left as ConstantExpression;
if (constLeft != null && constLeft.Type == typeof (bool))
return ((bool) constLeft.Value) ? VisitNotNot(b.Right) : VisitNot(b.Right);
left = Visit(b.Left);
}
else if (operand == "<>")
{
// deal with (x != true|false) - most common
var constRight = b.Right as ConstantExpression;
if (constRight != null && constRight.Type == typeof(bool))
return ((bool) constRight.Value) ? VisitNot(b.Left) : VisitNotNot(b.Left);
right = Visit(b.Right);
// deal with (true|false != x) - why not
var constLeft = b.Left as ConstantExpression;
if (constLeft != null && constLeft.Type == typeof(bool))
return ((bool) constLeft.Value) ? VisitNot(b.Right) : VisitNotNot(b.Right);
left = Visit(b.Left);
}
else
{
left = Visit(b.Left);
@@ -231,25 +259,47 @@ namespace Umbraco.Core.Persistence.Querying
switch (u.NodeType)
{
case ExpressionType.Not:
var o = Visit(u.Operand);
//use a Not equal operator instead of <> since we don't know that <> works in all sql servers
switch (u.Operand.NodeType)
{
case ExpressionType.MemberAccess:
//In this case it wil be a false property , i.e. x => !Trashed
SqlParameters.Add(true);
return string.Format("NOT ({0} = @0)", o);
default:
//In this case it could be anything else, such as: x => !x.Path.StartsWith("-20")
return string.Format("NOT ({0})", o);
}
return VisitNot(u.Operand);
default:
return Visit(u.Operand);
}
}
private string VisitNot(Expression exp)
{
var o = Visit(exp);
// use a "NOT (...)" syntax instead of "<>" since we don't know whether "<>" works in all sql servers
// also, x.StartsWith(...) translates to "x LIKE '...%'" which we cannot "<>" and have to "NOT (...")
switch (exp.NodeType)
{
case ExpressionType.MemberAccess:
// false property , i.e. x => !Trashed
SqlParameters.Add(true);
return "NOT (" + o + " = @0)";
default:
// could be anything else, such as: x => !x.Path.StartsWith("-20")
return "NOT (" + o + ")";
}
}
private string VisitNotNot(Expression exp)
{
var o = Visit(exp);
switch (exp.NodeType)
{
case ExpressionType.MemberAccess:
// true property, i.e. x => Trashed
SqlParameters.Add(true);
return o + " = @0";
default:
// could be anything else, such as: x => x.Path.StartsWith("-20")
return o;
}
}
protected virtual string VisitNewArray(NewArrayExpression na)
{
@@ -1212,5 +1212,19 @@ AND umbracoNode.id <> @id",
{
return PerformExists(id);
}
public string GetUniqueAlias(string alias)
{
// alias is unique accross ALL content types!
var aliasColumn = SqlSyntax.GetQuotedColumnName("alias");
var aliases = Database.Fetch<string>(@"SELECT cmsContentType." + aliasColumn + @" FROM cmsContentType
INNER JOIN umbracoNode ON cmsContentType.nodeId = umbracoNode.id
WHERE cmsContentType." + aliasColumn + @" LIKE @pattern",
new { pattern = alias + "%", objectType = NodeObjectTypeId });
var i = 1;
string test;
while (aliases.Contains(test = alias + i)) i++;
return test;
}
}
}
@@ -32,5 +32,13 @@ namespace Umbraco.Core.Persistence.Repositories
/// </param>
/// <returns></returns>
IEnumerable<string> GetAllContentTypeAliases(params Guid[] objectTypes);
/// <summary>
/// Derives a unique alias from an existing alias.
/// </summary>
/// <param name="alias">The original alias.</param>
/// <returns>The original alias with a number appended to it, so that it is unique.</returns>
/// /// <remarks>Unique accross all content, media and member types.</remarks>
string GetUniqueAlias(string alias);
}
}
@@ -15,5 +15,13 @@ namespace Umbraco.Core.Persistence.Repositories
IEnumerable<IMediaType> GetByQuery(IQuery<PropertyType> query);
IEnumerable<MoveEventInfo<IMediaType>> Move(IMediaType toMove, EntityContainer container);
/// <summary>
/// Derives a unique alias from an existing alias.
/// </summary>
/// <param name="alias">The original alias.</param>
/// <returns>The original alias with a number appended to it, so that it is unique.</returns>
/// <remarks>Unique accross all content, media and member types.</remarks>
string GetUniqueAlias(string alias);
}
}
@@ -28,6 +28,8 @@ namespace Umbraco.Core.Persistence.SqlSyntax
GuidColumnDefinition = "char(36)";
DefaultValueFormat = "DEFAULT {0}";
InitColumnTypeMap();
}
public override IEnumerable<string> GetTablesInSchema(Database db)
@@ -794,7 +794,7 @@ namespace Umbraco.Core.Services
//TODO: This needs to change, if we are deleting a content type, we should just delete the data,
// this method will recursively go lookup every content item, check if any of it's descendants are
// of a different type, move them to the recycle bin, then permanently delete the content items.
// of a different type, move them to the recycle bin, then permanently delete the content items.
// The main problem with this is that for every content item being deleted, events are raised...
// which we need for many things like keeping caches in sync, but we can surely do this MUCH better.
@@ -1067,6 +1067,92 @@ namespace Umbraco.Core.Services
new OperationStatus<MoveOperationStatusType>(MoveOperationStatusType.Success, evtMsgs));
}
public Attempt<OperationStatus<IMediaType, MoveOperationStatusType>> CopyMediaType(IMediaType toCopy, int containerId)
{
var evtMsgs = EventMessagesFactory.Get();
IMediaType copy;
var uow = UowProvider.GetUnitOfWork();
using (var containerRepository = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.MediaTypeContainerGuid))
using (var repository = RepositoryFactory.CreateMediaTypeRepository(uow))
{
try
{
if (containerId > 0)
{
var container = containerRepository.Get(containerId);
if (container == null)
throw new DataOperationException<MoveOperationStatusType>(MoveOperationStatusType.FailedParentNotFound);
}
var alias = repository.GetUniqueAlias(toCopy.Alias);
copy = toCopy.DeepCloneWithResetIdentities(alias);
copy.Name = copy.Name + " (copy)"; // might not be unique
// if it has a parent, and the parent is a content type, unplug composition
// all other compositions remain in place in the copied content type
if (copy.ParentId > 0)
{
var parent = repository.Get(copy.ParentId);
if (parent != null)
copy.RemoveContentType(parent.Alias);
}
copy.ParentId = containerId;
repository.AddOrUpdate(copy);
}
catch (DataOperationException<MoveOperationStatusType> ex)
{
return Attempt.Fail(new OperationStatus<IMediaType, MoveOperationStatusType>(null, ex.Operation, evtMsgs));
}
uow.Commit();
}
return Attempt.Succeed(new OperationStatus<IMediaType, MoveOperationStatusType>(copy, MoveOperationStatusType.Success, evtMsgs));
}
public Attempt<OperationStatus<IContentType, MoveOperationStatusType>> CopyContentType(IContentType toCopy, int containerId)
{
var evtMsgs = EventMessagesFactory.Get();
IContentType copy;
var uow = UowProvider.GetUnitOfWork();
using (var containerRepository = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DocumentTypeContainerGuid))
using (var repository = RepositoryFactory.CreateContentTypeRepository(uow))
{
try
{
if (containerId > 0)
{
var container = containerRepository.Get(containerId);
if (container == null)
throw new DataOperationException<MoveOperationStatusType>(MoveOperationStatusType.FailedParentNotFound);
}
var alias = repository.GetUniqueAlias(toCopy.Alias);
copy = toCopy.DeepCloneWithResetIdentities(alias);
copy.Name = copy.Name + " (copy)"; // might not be unique
// if it has a parent, and the parent is a content type, unplug composition
// all other compositions remain in place in the copied content type
if (copy.ParentId > 0)
{
var parent = repository.Get(copy.ParentId);
if (parent != null)
copy.RemoveContentType(parent.Alias);
}
copy.ParentId = containerId;
repository.AddOrUpdate(copy);
}
catch (DataOperationException<MoveOperationStatusType> ex)
{
return Attempt.Fail(new OperationStatus<IContentType, MoveOperationStatusType>(null, ex.Operation, evtMsgs));
}
uow.Commit();
}
return Attempt.Succeed(new OperationStatus<IContentType, MoveOperationStatusType>(copy, MoveOperationStatusType.Success, evtMsgs));
}
/// <summary>
/// Saves a single <see cref="IMediaType"/> object
/// </summary>
@@ -291,5 +291,7 @@ namespace Umbraco.Core.Services
Attempt<OperationStatus<MoveOperationStatusType>> MoveMediaType(IMediaType toMove, int containerId);
Attempt<OperationStatus<MoveOperationStatusType>> MoveContentType(IContentType toMove, int containerId);
Attempt<OperationStatus<IMediaType, MoveOperationStatusType>> CopyMediaType(IMediaType toCopy, int containerId);
Attempt<OperationStatus<IContentType, MoveOperationStatusType>> CopyContentType(IContentType toCopy, int containerId);
}
}
+59 -28
View File
@@ -22,7 +22,7 @@ namespace Umbraco.Core
/// <summary>
/// A utility class to find all classes of a certain type by reflection in the current bin folder
/// of the web application.
/// of the web application.
/// </summary>
public static class TypeFinder
{
@@ -34,7 +34,7 @@ namespace Umbraco.Core
/// This is a modified version of: http://www.dominicpettifer.co.uk/Blog/44/how-to-get-a-reference-to-all-assemblies-in-the--bin-folder
/// </summary>
/// <remarks>
/// We do this because we cannot use AppDomain.Current.GetAssemblies() as this will return only assemblies that have been
/// We do this because we cannot use AppDomain.Current.GetAssemblies() as this will return only assemblies that have been
/// loaded in the CLR, not all assemblies.
/// See these threads:
/// http://issues.umbraco.org/issue/U5-198
@@ -136,7 +136,7 @@ namespace Umbraco.Core
});
/// <summary>
/// Return a list of found local Assemblies excluding the known assemblies we don't want to scan
/// Return a list of found local Assemblies excluding the known assemblies we don't want to scan
/// and exluding the ones passed in and excluding the exclusion list filter, the results of this are
/// cached for perforance reasons.
/// </summary>
@@ -190,6 +190,7 @@ namespace Umbraco.Core
/// </summary>
/// <remarks>
/// NOTE the comma vs period... comma delimits the name in an Assembly FullName property so if it ends with comma then its an exact name match
/// NOTE this means that "foo." will NOT exclude "foo.dll" but only "foo.*.dll"
/// </remarks>
internal static readonly string[] KnownAssemblyExclusionFilter = new[]
{
@@ -214,7 +215,7 @@ namespace Umbraco.Core
"RouteDebugger,",
"SqlCE4Umbraco,",
"umbraco.datalayer,",
"umbraco.interfaces,",
"umbraco.interfaces,",
//"umbraco.providers,",
//"Umbraco.Web.UI,",
"umbraco.webservices",
@@ -230,9 +231,9 @@ namespace Umbraco.Core
"AutoMapper,",
"AutoMapper.",
"AzureDirectory,",
"itextsharp,",
"itextsharp,",
"UrlRewritingNet.",
"HtmlAgilityPack,",
"HtmlAgilityPack,",
"MiniProfiler,",
"Moq,",
"nunit.framework,",
@@ -371,7 +372,7 @@ namespace Umbraco.Core
var assemblyList = assemblies.ToArray();
//find all assembly references that are referencing the attribute type's assembly since we
//find all assembly references that are referencing the attribute type's assembly since we
//should only be scanning those assemblies because any other assembly will definitely not
//contain a class that has this attribute.
var referencedAssemblies = TypeHelper.GetReferencedAssemblies(attributeType, assemblyList);
@@ -418,7 +419,7 @@ namespace Umbraco.Core
foreach (var subTypesInAssembly in allAttributeTypes.GroupBy(x => x.Assembly))
{
//So that we are not scanning too much, we need to group the sub types:
//So that we are not scanning too much, we need to group the sub types:
// * if there is more than 1 sub type in the same assembly then we should only search on the 'lowest base' type.
// * We should also not search for sub types if the type is sealed since you cannot inherit from a sealed class
// * We should not search for sub types if the type is static since you cannot inherit from them.
@@ -489,7 +490,7 @@ namespace Umbraco.Core
/// <summary>
/// Finds types that are assignable from the assignTypeFrom parameter and will scan for these types in the assembly
/// list passed in, however we will only scan assemblies that have a reference to the assignTypeFrom Type or any type
/// list passed in, however we will only scan assemblies that have a reference to the assignTypeFrom Type or any type
/// deriving from the base type.
/// </summary>
/// <param name="assignTypeFrom"></param>
@@ -513,7 +514,7 @@ namespace Umbraco.Core
var assemblyList = assemblies.ToArray();
//find all assembly references that are referencing the current type's assembly since we
//find all assembly references that are referencing the current type's assembly since we
//should only be scanning those assemblies because any other assembly will definitely not
//contain sub type's of the one we're currently looking for
var referencedAssemblies = TypeHelper.GetReferencedAssemblies(assignTypeFrom, assemblyList);
@@ -560,7 +561,7 @@ namespace Umbraco.Core
foreach (var subTypesInAssembly in allSubTypes.GroupBy(x => x.Assembly))
{
//So that we are not scanning too much, we need to group the sub types:
//So that we are not scanning too much, we need to group the sub types:
// * if there is more than 1 sub type in the same assembly then we should only search on the 'lowest base' type.
// * We should also not search for sub types if the type is sealed since you cannot inherit from a sealed class
// * We should not search for sub types if the type is static since you cannot inherit from them.
@@ -602,39 +603,69 @@ namespace Umbraco.Core
return foundAssignableTypes;
}
private static IEnumerable<Type> GetTypesWithFormattedException(Assembly a)
internal static IEnumerable<Type> GetTypesWithFormattedException(Assembly a)
{
//if the assembly is dynamic, do not try to scan it
if (a.IsDynamic)
return Enumerable.Empty<Type>();
var getAll = a.GetCustomAttribute<AllowPartiallyTrustedCallersAttribute>() == null;
try
{
//we need to detect if an assembly is partially trusted, if so we cannot go interrogating all of it's types
//only its exported types, otherwise we'll get exceptions.
if (a.GetCustomAttribute<AllowPartiallyTrustedCallersAttribute>() == null)
{
return a.GetTypes();
}
else
{
return a.GetExportedTypes();
}
return getAll ? a.GetTypes() : a.GetExportedTypes();
}
catch (ReflectionTypeLoadException ex)
catch (TypeLoadException ex) // GetExportedTypes *can* throw TypeLoadException!
{
var sb = new StringBuilder();
sb.AppendLine("Could not load types from assembly " + a.FullName + ", errors:");
foreach (var loaderException in ex.LoaderExceptions.WhereNotNull())
{
sb.AppendLine("Exception: " + loaderException);
}
throw new ReflectionTypeLoadException(ex.Types, ex.LoaderExceptions, sb.ToString());
AppendCouldNotLoad(sb, a, getAll);
AppendLoaderException(sb, ex);
// rethrow as ReflectionTypeLoadException (for consistency) with new message
throw new ReflectionTypeLoadException(new Type[0], new Exception[] { ex }, sb.ToString());
}
catch (ReflectionTypeLoadException rex) // GetTypes throws ReflectionTypeLoadException
{
var sb = new StringBuilder();
AppendCouldNotLoad(sb, a, getAll);
foreach (var loaderException in rex.LoaderExceptions.WhereNotNull())
AppendLoaderException(sb, loaderException);
// rethrow with new message
throw new ReflectionTypeLoadException(rex.Types, rex.LoaderExceptions, sb.ToString());
}
}
private static void AppendCouldNotLoad(StringBuilder sb, Assembly a, bool getAll)
{
sb.Append("Could not load ");
sb.Append(getAll ? "all" : "exported");
sb.Append(" types from \"");
sb.Append(a.FullName);
sb.AppendLine("\" due to LoaderExceptions, skipping:");
}
private static void AppendLoaderException(StringBuilder sb, Exception loaderException)
{
sb.Append(". ");
sb.Append(loaderException.GetType().FullName);
var tloadex = loaderException as TypeLoadException;
if (tloadex != null)
{
sb.Append(" on ");
sb.Append(tloadex.TypeName);
}
sb.Append(": ");
sb.Append(loaderException.Message);
sb.AppendLine();
}
#endregion
public static Type GetTypeByName(string typeName)
{
@@ -0,0 +1,100 @@
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Moq;
using NUnit.Framework;
using Semver;
using Umbraco.Core;
using Umbraco.Core.Events;
using Umbraco.Core.Logging;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Migrations;
using Umbraco.Core.Profiling;
using Umbraco.Core.Services;
using Umbraco.Web.Strategies.Migrations;
namespace Umbraco.Tests.Persistence.Migrations
{
[TestFixture]
public class MigrationStartupHandlerTests
{
[Test]
public void Executes_For_Any_Product_Name_When_Not_Specified()
{
var changed1 = new Args { CountExecuted = 0 };
var testHandler1 = new TestMigrationHandler(changed1);
testHandler1.OnApplicationStarting(Mock.Of<UmbracoApplicationBase>(), new ApplicationContext(CacheHelper.CreateDisabledCacheHelper(), new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>())));
var conn = new Mock<IDbConnection>();
conn.Setup(x => x.BeginTransaction(It.IsAny<IsolationLevel>())).Returns(Mock.Of<IDbTransaction>());
var db = new Mock<Database>(conn.Object);
var runner1 = new MigrationRunner(Mock.Of<IMigrationEntryService>(), Mock.Of<ILogger>(), new SemVersion(1), new SemVersion(2), "Test1",
new IMigration[] { Mock.Of<IMigration>() });
var result1 = runner1.Execute(db.Object, DatabaseProviders.SqlServerCE, false);
Assert.AreEqual(1, changed1.CountExecuted);
}
[Test]
public void Executes_Only_For_Specified_Product_Name()
{
var changed1 = new Args { CountExecuted = 0};
var testHandler1 = new TestMigrationHandler("Test1", changed1);
testHandler1.OnApplicationStarting(Mock.Of<UmbracoApplicationBase>(), new ApplicationContext(CacheHelper.CreateDisabledCacheHelper(), new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>())));
var changed2 = new Args { CountExecuted = 0 };
var testHandler2 = new TestMigrationHandler("Test2", changed2);
testHandler2.OnApplicationStarting(Mock.Of<UmbracoApplicationBase>(), new ApplicationContext(CacheHelper.CreateDisabledCacheHelper(), new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>())));
var conn = new Mock<IDbConnection>();
conn.Setup(x => x.BeginTransaction(It.IsAny<IsolationLevel>())).Returns(Mock.Of<IDbTransaction>());
var db = new Mock<Database>(conn.Object);
var runner1 = new MigrationRunner(Mock.Of<IMigrationEntryService>(), Mock.Of<ILogger>(), new SemVersion(1), new SemVersion(2), "Test1",
new IMigration[] { Mock.Of<IMigration>()});
var result1 = runner1.Execute(db.Object, DatabaseProviders.SqlServerCE, false);
Assert.AreEqual(1, changed1.CountExecuted);
Assert.AreEqual(0, changed2.CountExecuted);
var runner2 = new MigrationRunner(Mock.Of<IMigrationEntryService>(), Mock.Of<ILogger>(), new SemVersion(1), new SemVersion(2), "Test2",
new IMigration[] { Mock.Of<IMigration>() });
var result2 = runner2.Execute(db.Object, DatabaseProviders.SqlServerCE, false);
Assert.AreEqual(1, changed1.CountExecuted);
Assert.AreEqual(1, changed2.CountExecuted);
}
public class Args
{
public int CountExecuted { get; set; }
}
public class TestMigrationHandler : MigrationStartupHander
{
private readonly string _prodName;
private readonly Args _changed;
public TestMigrationHandler(Args changed)
{
_changed = changed;
}
public TestMigrationHandler(string prodName, Args changed)
{
_prodName = prodName;
_changed = changed;
}
protected override void AfterMigration(MigrationRunner sender, MigrationEventArgs e)
{
_changed.CountExecuted++;
}
public override string[] TargetProductNames
{
get { return _prodName.IsNullOrWhiteSpace() ? new string[] {} : new[] {_prodName}; }
}
}
}
}
@@ -51,6 +51,18 @@ namespace Umbraco.Tests.Persistence.Querying
Assert.AreEqual("-20%", sql.Arguments[1]);
}
[Test]
public void Where_Clause_With_EqualsFalse_Starts_With()
{
var level = 1;
var sql = new Sql("SELECT *").From<NodeDto>().Where<NodeDto>(x => x.Level == level && x.Path.StartsWith("-20") == false);
Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE ([umbracoNode].[level] = @0 AND NOT (upper([umbracoNode].[path]) LIKE upper(@1)))", sql.SQL.Replace("\n", " "));
Assert.AreEqual(2, sql.Arguments.Length);
Assert.AreEqual(level, sql.Arguments[0]);
Assert.AreEqual("-20%", sql.Arguments[1]);
}
[Test]
public void Where_Clause_With_Equals_Clause()
{
@@ -71,6 +83,16 @@ namespace Umbraco.Tests.Persistence.Querying
Assert.AreEqual(true, sql.Arguments[0]);
}
[Test]
public void Where_Clause_With_EqualsFalse_Boolean()
{
var sql = new Sql("SELECT *").From<NodeDto>().Where<NodeDto>(x => x.Trashed == false);
Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE (NOT ([umbracoNode].[trashed] = @0))", sql.SQL.Replace("\n", " "));
Assert.AreEqual(1, sql.Arguments.Length);
Assert.AreEqual(true, sql.Arguments[0]);
}
[Test]
public void Where_Clause_With_Boolean()
{
@@ -1,17 +1,20 @@
using System;
using System.Linq;
using Moq;
using NUnit.Framework;
using Umbraco.Core.Logging;
using Umbraco.Core.Models.Rdbms;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Migrations;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Tests.TestHelpers;
namespace Umbraco.Tests.Persistence.SyntaxProvider
{
[NUnit.Framework.Ignore("This doesn't actually test anything")]
//[NUnit.Framework.Ignore("This doesn't actually test anything")]
[TestFixture]
public class MySqlSyntaxProviderTests
public class MySqlSyntaxProviderTests : BaseUsingSqlCeSyntax
{
[SetUp]
public void SetUp()
@@ -20,6 +23,7 @@ namespace Umbraco.Tests.Persistence.SyntaxProvider
}
[Test]
[NUnit.Framework.Ignore]
public void Can_Generate_Create_Table_Statement()
{
var type = typeof(TagRelationshipDto);
@@ -48,5 +52,40 @@ namespace Umbraco.Tests.Persistence.SyntaxProvider
{
SqlSyntaxContext.SqlSyntaxProvider = null;
}
[Test]
public void U4_8017()
{
var logger = Mock.Of<ILogger>();
var migration = new TestMigration(SqlSyntaxContext.SqlSyntaxProvider, logger);
var context = new MigrationContext(DatabaseProviders.MySql, null, logger);
migration.Context = context;
migration.Up();
var x = context.Expressions;
Assert.AreEqual(1, x.Count);
var e = x.First().ToString();
// SQLCE provider *does* use UniqueIdentifier
// MySql using GUID...? because InitColumnTypeMap() missing in provider, fixed
Assert.AreEqual("ALTER TABLE `cmsPropertyTypeGroup` ADD COLUMN `uniqueID` char(36) NOT NULL", e);
}
[Migration("1.0.0", 0, "Test")]
private class TestMigration : MigrationBase
{
public TestMigration(ISqlSyntaxProvider sqlSyntax, ILogger logger) : base(sqlSyntax, logger)
{}
public override void Up()
{
Create.Column("uniqueID").OnTable("cmsPropertyTypeGroup").AsGuid().NotNullable().WithDefault(SystemMethods.NewGuid);
}
public override void Down()
{
throw new NotImplementedException();
}
}
}
}
@@ -9,11 +9,12 @@ using Umbraco.Core.Persistence.DatabaseModelDefinitions;
using Umbraco.Core.Persistence.Migrations.Syntax.Create.Index;
using Umbraco.Core.Persistence.Migrations.Syntax.Expressions;
using Umbraco.Core.Persistence.SqlSyntax;
using Umbraco.Tests.TestHelpers;
namespace Umbraco.Tests.Persistence.SyntaxProvider
{
[TestFixture]
public class SqlCeSyntaxProviderTests
public class SqlCeSyntaxProviderTests : BaseUsingSqlCeSyntax
{
[Test]
+2 -2
View File
@@ -79,8 +79,8 @@ namespace Umbraco.Tests.Plugins
var originalTypesFound = TypeFinderOriginal.FindClassesOfType<IApplicationStartupHandler>(_assemblies);
Assert.AreEqual(originalTypesFound.Count(), typesFound.Count());
Assert.AreEqual(8, typesFound.Count());
Assert.AreEqual(8, originalTypesFound.Count());
Assert.AreEqual(9, typesFound.Count());
Assert.AreEqual(9, originalTypesFound.Count());
}
[Test]
@@ -234,9 +234,9 @@ namespace Umbraco.Tests.PublishedContent
new PublishedPropertyType("prop1", 1, "?"),
};
var contentType1 = new PublishedContentType(1, "ContentType1", props);
var contentType2 = new PublishedContentType(2, "ContentType2", props);
var contentType2s = new PublishedContentType(3, "ContentType2Sub", props);
var contentType1 = new PublishedContentType(1, "ContentType1", Enumerable.Empty<string>(), props);
var contentType2 = new PublishedContentType(2, "ContentType2", Enumerable.Empty<string>(), props);
var contentType2s = new PublishedContentType(3, "ContentType2Sub", Enumerable.Empty<string>(), props);
cache.Add(new SolidPublishedContent(contentType1)
{
@@ -355,7 +355,11 @@ namespace Umbraco.Tests.PublishedContent
private static readonly PublishedPropertyType Default = new PublishedPropertyType("*", 0, "?");
public AutoPublishedContentType(int id, string alias, IEnumerable<PublishedPropertyType> propertyTypes)
: base(id, alias, propertyTypes)
: base(id, alias, Enumerable.Empty<string>(), propertyTypes)
{ }
public AutoPublishedContentType(int id, string alias, IEnumerable<string> compositionAliases, IEnumerable<PublishedPropertyType> propertyTypes)
: base(id, alias, compositionAliases, propertyTypes)
{ }
public override PublishedPropertyType GetPropertyType(string alias)
@@ -50,7 +50,8 @@ namespace Umbraco.Tests.PublishedContent
new PublishedPropertyType("content", 0, Constants.PropertyEditors.TinyMCEAlias),
new PublishedPropertyType("testRecursive", 0, "?"),
};
var type = new AutoPublishedContentType(0, "anything", propertyTypes);
var compositionAliases = new[] {"MyCompositionAlias"};
var type = new AutoPublishedContentType(0, "anything", compositionAliases, propertyTypes);
PublishedContentType.GetPublishedContentTypeCallback = (alias) => type;
}
@@ -468,6 +469,16 @@ namespace Umbraco.Tests.PublishedContent
Assert.IsNull(doc.FirstChild<IPublishedContent>());
}
[Test]
public void IsComposedOf()
{
var doc = GetNode(1173);
var isComposedOf = doc.IsComposedOf("MyCompositionAlias");
Assert.IsTrue(isComposedOf);
}
[Test]
public void HasProperty()
{
@@ -475,8 +486,7 @@ namespace Umbraco.Tests.PublishedContent
var hasProp = doc.HasProperty(Constants.Conventions.Content.UrlAlias);
Assert.AreEqual(true, (bool)hasProp);
Assert.IsTrue(hasProp);
}
[Test]
+3 -1
View File
@@ -175,6 +175,7 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Persistence\Migrations\MigrationStartupHandlerTests.cs" />
<Compile Include="Web\AngularIntegration\AngularAntiForgeryTests.cs" />
<Compile Include="Web\AngularIntegration\ContentModelSerializationTests.cs" />
<Compile Include="Web\AngularIntegration\JsInitializationTests.cs" />
@@ -244,6 +245,7 @@
<Compile Include="Models\UmbracoEntityTests.cs" />
<Compile Include="Models\UserTests.cs" />
<Compile Include="Models\UserTypeTests.cs" />
<Compile Include="Web\Mvc\RenderModelBinderTests.cs" />
<Compile Include="Web\Mvc\SurfaceControllerTests.cs" />
<Compile Include="Web\Mvc\UmbracoViewPageTests.cs" />
<Compile Include="BootManagers\CoreBootManagerTests.cs" />
@@ -758,7 +760,7 @@
xcopy "$(ProjectDir)"..\packages\SqlServerCE.4.0.0.1\x86\*.* "$(TargetDir)x86\" /Y /F /E /I /C /D</PreBuildEvent>
</PropertyGroup>
<Import Project="$(SolutionDir)\.nuget\nuget.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
@@ -0,0 +1,157 @@
using System.Collections.Generic;
using System.Globalization;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
using Moq;
using NUnit.Framework;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Web.Models;
using Umbraco.Web.Mvc;
namespace Umbraco.Tests.Web.Mvc
{
[TestFixture]
public class RenderModelBinderTests
{
[Test]
public void Returns_Binder_For_IPublishedContent_And_IRenderModel()
{
var binder = new RenderModelBinder();
var found = binder.GetBinder(typeof (IPublishedContent));
Assert.IsNotNull(found);
found = binder.GetBinder(typeof(IRenderModel));
Assert.IsNotNull(found);
found = binder.GetBinder(typeof(RenderModel));
Assert.IsNotNull(found);
found = binder.GetBinder(typeof(DynamicPublishedContent));
Assert.IsNotNull(found);
found = binder.GetBinder(typeof(MyContent));
Assert.IsNotNull(found);
found = binder.GetBinder(typeof(MyOtherContent));
Assert.IsNull(found);
}
[Test]
public void BindModel_Null_Source_Returns_Null()
{
Assert.IsNull(RenderModelBinder.BindModel(null, typeof(MyContent), CultureInfo.CurrentCulture));
}
[Test]
public void BindModel_Returns_If_Same_Type()
{
var content = new MyContent(Mock.Of<IPublishedContent>());
var bound = RenderModelBinder.BindModel(content, typeof (IPublishedContent), CultureInfo.CurrentCulture);
Assert.AreSame(content, bound);
}
[Test]
public void BindModel_RenderModel_To_IPublishedContent()
{
var content = new MyContent(Mock.Of<IPublishedContent>());
var renderModel = new RenderModel(content, CultureInfo.CurrentCulture);
var bound = RenderModelBinder.BindModel(renderModel, typeof(IPublishedContent), CultureInfo.CurrentCulture);
Assert.AreSame(content, bound);
}
[Test]
public void BindModel_IPublishedContent_To_RenderModel()
{
var content = new MyContent(Mock.Of<IPublishedContent>());
var bound = (IRenderModel)RenderModelBinder.BindModel(content, typeof(RenderModel), CultureInfo.CurrentCulture);
Assert.AreSame(content, bound.Content);
}
[Test]
public void BindModel_IPublishedContent_To_Generic_RenderModel()
{
var content = new MyContent(Mock.Of<IPublishedContent>());
var bound = (IRenderModel)RenderModelBinder.BindModel(content, typeof(RenderModel<MyContent>), CultureInfo.CurrentCulture);
Assert.AreSame(content, bound.Content);
}
[Test]
public void No_DataToken_Returns_Null()
{
var binder = new RenderModelBinder();
var routeData = new RouteData();
var result = binder.BindModel(new ControllerContext(Mock.Of<HttpContextBase>(), routeData, Mock.Of<ControllerBase>()),
new ModelBindingContext());
Assert.IsNull(result);
}
[Test]
public void Invalid_DataToken_Model_Type_Returns_Null()
{
var binder = new RenderModelBinder();
var routeData = new RouteData();
routeData.DataTokens[Core.Constants.Web.UmbracoDataToken] = "hello";
//the value provider is the default implementation
var valueProvider = new Mock<IValueProvider>();
//also IUnvalidatedValueProvider
var invalidatedValueProvider = valueProvider.As<IUnvalidatedValueProvider>();
invalidatedValueProvider.Setup(x => x.GetValue(It.IsAny<string>(), It.IsAny<bool>())).Returns(() =>
new ValueProviderResult(null, "", CultureInfo.CurrentCulture));
var controllerCtx = new ControllerContext(
Mock.Of<HttpContextBase>(http => http.Items == new Dictionary<object, object>()),
routeData,
Mock.Of<ControllerBase>());
var result = binder.BindModel(controllerCtx,
new ModelBindingContext
{
ValueProvider = valueProvider.Object,
ModelMetadata = new ModelMetadata(new EmptyModelMetadataProvider(), null, () => null, typeof(IPublishedContent), "content")
});
Assert.IsNull(result);
}
[Test]
public void IPublishedContent_DataToken_Model_Type_Uses_DefaultImplementation()
{
var content = new MyContent(Mock.Of<IPublishedContent>());
var binder = new RenderModelBinder();
var routeData = new RouteData();
routeData.DataTokens[Core.Constants.Web.UmbracoDataToken] = content;
//the value provider is the default implementation
var valueProvider = new Mock<IValueProvider>();
//also IUnvalidatedValueProvider
var invalidatedValueProvider = valueProvider.As<IUnvalidatedValueProvider>();
invalidatedValueProvider.Setup(x => x.GetValue(It.IsAny<string>(), It.IsAny<bool>())).Returns(() =>
new ValueProviderResult(content, "content", CultureInfo.CurrentCulture));
var controllerCtx = new ControllerContext(
Mock.Of<HttpContextBase>(http => http.Items == new Dictionary<object, object>()),
routeData,
Mock.Of<ControllerBase>());
var result = binder.BindModel(controllerCtx,
new ModelBindingContext
{
ValueProvider = valueProvider.Object,
ModelMetadata = new ModelMetadata(new EmptyModelMetadataProvider(), null, () => null, typeof(IPublishedContent), "content")
});
Assert.AreEqual(content, result);
}
public class MyOtherContent
{
}
public class MyContent : PublishedContentWrapped
{
public MyContent(IPublishedContent content) : base(content)
{
}
}
}
}
@@ -210,7 +210,7 @@ function submit()
if (findDepth(curLineHTML, cc) !== 0) {
// Cursor is inside a <tag>, don't set cursor:
curLineHTML = curLineHTML.replace(cc, '');
doc.setLine(pos.line, curLineHTML);
doc.getLineHandle(pos.line).text = curLineHTML;
}
// Submit HTML to TinyMCE:
+27 -7
View File
@@ -22,15 +22,35 @@ var packages = angular.module("umbraco.packages", []);
//module is initilized.
angular.module("umbraco.views", ["umbraco.viewcache"]);
angular.module("umbraco.viewcache", [])
.run(function($rootScope, $templateCache){
/** For debug mode, always clear template cache to cut down on
.run(function($rootScope, $templateCache) {
/** For debug mode, always clear template cache to cut down on
dev frustration and chrome cache on templates */
if(Umbraco.Sys.ServerVariables.isDebuggingEnabled){
//$rootScope.$on('$viewContentLoaded', function() {
$templateCache.removeAll();
//});
if (Umbraco.Sys.ServerVariables.isDebuggingEnabled) {
$templateCache.removeAll();
}
})
})
.config([
//This ensures that all of our angular views are cache busted, if the path starts with views/ and ends with .html, then
// we will append the cache busting value to it. This way all upgraded sites will not have to worry about browser cache.
"$provide", function($provide) {
return $provide.decorator("$http", [
"$delegate", function($delegate) {
var get = $delegate.get;
$delegate.get = function (url, config) {
if (Umbraco.Sys.ServerVariables.application && url.startsWith("views/") && url.endsWith(".html")) {
var rnd = Umbraco.Sys.ServerVariables.application.version + "." + Umbraco.Sys.ServerVariables.application.cdf;
var _op = (url.indexOf("?") > 0) ? "&" : "?";
url += _op + "umb__rnd=" + rnd;
}
return get(url, config);
};
return $delegate;
}
]);
}
]);
//Call a document callback if defined, this is sort of a dodgy hack to
// be able to configure angular values in the Default.cshtml
@@ -17,7 +17,7 @@
if(convert){
element.html("<i class='icon-section " + convert + "'></i>");
}else{
element.html("<img src='images/tray/" + icon + "'>");
element.html("<img class='icon-section' src='images/tray/" + icon + "'>");
}
//it's a file, normally legacy so look in the icon tray images
}
@@ -1,10 +1,13 @@
(function() {
'use strict';
function EditorHeaderDirective(iconHelper) {
function EditorHeaderDirective(iconHelper, variationsHelper) {
function link(scope, el, attr, ctrl) {
scope.showVariationsQuickSwitch = false;
scope.variations = variationsHelper.getVariations();
scope.openIconPicker = function() {
scope.dialogModel = {
view: "iconpicker",
@@ -24,6 +27,10 @@
}
};
};
scope.toggleVariationsQuickSwitch = function() {
scope.showVariationsQuickSwitch = !scope.showVariationsQuickSwitch;
};
}
var directive = {
@@ -14,7 +14,8 @@ angular.module("umbraco.directives")
templateUrl: 'views/components/imaging/umb-image-gravity.html',
scope: {
src: '=',
center: "="
center: "=",
onImageLoaded: "="
},
link: function(scope, element, attrs) {
@@ -26,6 +27,8 @@ angular.module("umbraco.directives")
top: 0
};
scope.loaded = false;
//elements
var $viewport = element.find(".viewport");
var $image = element.find("img");
@@ -42,6 +45,19 @@ angular.module("umbraco.directives")
};
};
scope.setFocalPoint = function(event) {
scope.$emit("imageFocalPointStart");
var offsetX = event.offsetX - 10;
var offsetY = event.offsetY - 10;
calculateGravity(offsetX, offsetY);
lazyEndEvent();
};
var setDimensions = function(){
scope.dimensions.width = $image.width();
scope.dimensions.height = $image.height();
@@ -54,9 +70,9 @@ angular.module("umbraco.directives")
}
};
var calculateGravity = function(){
scope.dimensions.left = $overlay[0].offsetLeft;
scope.dimensions.top = $overlay[0].offsetTop;
var calculateGravity = function(offsetX, offsetY){
scope.dimensions.left = offsetX;
scope.dimensions.top = offsetY;
scope.center.left = (scope.dimensions.left+10) / scope.dimensions.width;
scope.center.top = (scope.dimensions.top+10) / scope.dimensions.height;
@@ -80,7 +96,9 @@ angular.module("umbraco.directives")
},
stop: function() {
scope.$apply(function(){
calculateGravity();
var offsetX = $overlay[0].offsetLeft;
var offsetY = $overlay[0].offsetTop;
calculateGravity(offsetX, offsetY);
});
lazyEndEvent();
@@ -91,8 +109,26 @@ angular.module("umbraco.directives")
$image.load(function(){
$timeout(function(){
setDimensions();
scope.loaded = true;
scope.onImageLoaded();
});
});
$(window).on('resize.umbImageGravity', function(){
scope.$apply(function(){
$timeout(function(){
setDimensions();
});
var offsetX = $overlay[0].offsetLeft;
var offsetY = $overlay[0].offsetTop;
calculateGravity(offsetX, offsetY);
});
});
scope.$on('$destroy', function() {
$(window).off('.umbImageGravity');
});
}
};
});
@@ -26,6 +26,7 @@ angular.module("umbraco.directives")
link: function(scope, element, attrs) {
//// INIT /////
var $image = element.find("img");
scope.loaded = false;
$image.load(function(){
$timeout(function(){
@@ -52,6 +53,7 @@ angular.module("umbraco.directives")
}
setPreviewStyle();
scope.loaded = true;
});
});
@@ -0,0 +1,76 @@
(function() {
'use strict';
function WebsiteSelector() {
function link(scope, el, attr, ctrl) {
scope.showWebsiteDropdown = false;
scope.selectedWebsite = {};
function activate() {
for(var i = 0; i < scope.websites.length; i++) {
var website = scope.websites[i];
if(website.selected) {
scope.selectedWebsite = website;
}
}
}
scope.toggleWebsiteDropDown = function() {
scope.showWebsiteDropdown = !scope.showWebsiteDropdown;
};
scope.closeWebsiteDropDown = function() {
scope.showWebsiteDropdown = false;
};
scope.createWebsite = function() {
if(scope.onCreateWebsite) {
scope.onCreateWebsite();
scope.closeWebsiteDropDown();
}
};
scope.clickWebsite = function(website) {
if(scope.onClickWebsite) {
scope.onClickWebsite(website);
setSelectedWebsite(website, scope.websites);
scope.closeWebsiteDropDown();
}
};
function setSelectedWebsite(selectedWebsite, websites) {
for(var i = 0; i < websites.length; i++) {
var website = websites[i];
website.selected = false;
}
selectedWebsite.selected = true;
scope.selectedWebsite = selectedWebsite;
}
scope.$watch('websites', function(newValue, oldValue){
activate();
}, true);
}
var directive = {
restrict: 'E',
replace: true,
templateUrl: 'views/components/umb-website-selector.html',
link: link,
scope: {
websites: "=",
onCreateWebsite: "=",
onClickWebsite: "="
}
};
return directive;
}
angular.module('umbraco.directives').directive('umbWebsiteSelector', WebsiteSelector);
})();
@@ -509,6 +509,16 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
'Failed to check permission for item ' + id);
},
getPermissions: function (nodeIds) {
return umbRequestHelper.resourcePromise(
$http.post(
umbRequestHelper.getApiUrl(
"contentApiBaseUrl",
"GetPermissions"),
nodeIds),
'Failed to get permissions');
},
/**
* @ngdoc method
* @name umbraco.resources.contentResource#save
@@ -29,7 +29,7 @@ function contentTypeResource($q, $http, umbRequestHelper, umbDataFormatter) {
filterContentTypes: filterContentTypes,
filterPropertyTypes: filterPropertyTypes
};
return umbRequestHelper.resourcePromise(
$http.post(
umbRequestHelper.getApiUrl(
@@ -201,9 +201,9 @@ function contentTypeResource($q, $http, umbRequestHelper, umbDataFormatter) {
* .then(function() {
* alert("node was moved");
* }, function(err){
* alert("node didnt move:" + err.data.Message);
* alert("node didnt move:" + err.data.Message);
* });
* </pre>
* </pre>
* @param {Object} args arguments object
* @param {Int} args.idd the ID of the node to move
* @param {Int} args.parentId the ID of the parent node to move to
@@ -230,6 +230,26 @@ function contentTypeResource($q, $http, umbRequestHelper, umbDataFormatter) {
'Failed to move content');
},
copy: function(args) {
if (!args) {
throw "args cannot be null";
}
if (!args.parentId) {
throw "args.parentId cannot be null";
}
if (!args.id) {
throw "args.id cannot be null";
}
return umbRequestHelper.resourcePromise(
$http.post(umbRequestHelper.getApiUrl("contentTypeApiBaseUrl", "PostCopy"),
{
parentId: args.parentId,
id: args.id
}),
'Failed to copy content');
},
createContainer: function(parentId, name) {
return umbRequestHelper.resourcePromise(
@@ -237,7 +257,7 @@ function contentTypeResource($q, $http, umbRequestHelper, umbDataFormatter) {
'Failed to create a folder under parent id ' + parentId);
}
};
}
angular.module('umbraco.resources').factory('contentTypeResource', contentTypeResource);
@@ -53,7 +53,7 @@ function mediaTypeResource($q, $http, umbRequestHelper, umbDataFormatter) {
* .then(function(array) {
* $scope.type = type;
* });
* </pre>
* </pre>
* @param {Int} mediaId id of the media item to retrive allowed child types for
* @returns {Promise} resourcePromise object.
*
@@ -145,9 +145,9 @@ function mediaTypeResource($q, $http, umbRequestHelper, umbDataFormatter) {
* .then(function() {
* alert("node was moved");
* }, function(err){
* alert("node didnt move:" + err.data.Message);
* alert("node didnt move:" + err.data.Message);
* });
* </pre>
* </pre>
* @param {Object} args arguments object
* @param {Int} args.idd the ID of the node to move
* @param {Int} args.parentId the ID of the parent node to move to
@@ -174,6 +174,26 @@ function mediaTypeResource($q, $http, umbRequestHelper, umbDataFormatter) {
'Failed to move content');
},
copy: function (args) {
if (!args) {
throw "args cannot be null";
}
if (!args.parentId) {
throw "args.parentId cannot be null";
}
if (!args.id) {
throw "args.id cannot be null";
}
return umbRequestHelper.resourcePromise(
$http.post(umbRequestHelper.getApiUrl("mediaTypeApiBaseUrl", "PostCopy"),
{
parentId: args.parentId,
id: args.id
}),
'Failed to copy content');
},
createContainer: function(parentId, name) {
return umbRequestHelper.resourcePromise(
@@ -16,7 +16,7 @@ function treeResource($q, $http, umbRequestHelper) {
/** internal method to get the tree menu url */
function getTreeMenuUrl(node) {
if (!node.menuUrl) {
throw "No menuUrl property found on the tree node, cannot load menu";
return null;
}
return node.menuUrl;
}
@@ -26,10 +26,16 @@ function treeResource($q, $http, umbRequestHelper) {
/** Loads in the data to display the nodes menu */
loadMenu: function (node) {
return umbRequestHelper.resourcePromise(
$http.get(getTreeMenuUrl(node)),
"Failed to retrieve data for a node's menu " + node.id);
var treeMenuUrl = getTreeMenuUrl(node);
if (treeMenuUrl !== undefined && treeMenuUrl !== null && treeMenuUrl.length > 0) {
return umbRequestHelper.resourcePromise(
$http.get(getTreeMenuUrl(node)),
"Failed to retrieve data for a node's menu " + node.id);
} else {
return $q.reject({
errorMsg: "No tree menu url defined for node " + node.id
});
}
},
/** Loads in the data to display the nodes for an application */
@@ -55,7 +55,7 @@ function contentEditingHelper(fileManager, $q, $location, $routeParams, notifica
var deferred = $q.defer();
if (!args.scope.busy && formHelper.submitForm({ scope: args.scope, statusMessage: args.statusMessage })) {
if (!args.scope.busy && formHelper.submitForm({ scope: args.scope, statusMessage: args.statusMessage, action: args.action })) {
args.scope.busy = true;
@@ -50,7 +50,7 @@ function formHelper(angularHelper, serverValidationManager, $timeout, notificati
}
//the first thing any form must do is broadcast the formSubmitting event
args.scope.$broadcast("formSubmitting", { scope: args.scope });
args.scope.$broadcast("formSubmitting", { scope: args.scope, action: args.action });
//then check if the form is valid
if (!args.skipValidation) {
@@ -1,270 +1,323 @@
// This service was based on OpenJS library available in BSD License
// http://www.openjs.com/scripts/events/keyboard_shortcuts/index.php
angular.module('umbraco.services')
.factory('keyboardService', ['$window', '$timeout', function ($window, $timeout) {
var keyboardManagerService = {};
var defaultOpt = {
'type': 'keydown',
'propagate': false,
'inputDisabled': false,
'target': $window.document,
'keyCode': false
};
var isMac = navigator.platform.toUpperCase().indexOf('MAC')>=0;
function keyboardService($window, $timeout) {
var keyboardManagerService = {};
var defaultOpt = {
'type': 'keydown',
'propagate': false,
'inputDisabled': false,
'target': $window.document,
'keyCode': false
};
// Store all keyboard combination shortcuts
keyboardManagerService.keyboardEvent = {};
// Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken
var shift_nums = {
"`": "~",
"1": "!",
"2": "@",
"3": "#",
"4": "$",
"5": "%",
"6": "^",
"7": "&",
"8": "*",
"9": "(",
"0": ")",
"-": "_",
"=": "+",
";": ":",
"'": "\"",
",": "<",
".": ">",
"/": "?",
"\\": "|"
};
// Special Keys - and their codes
var special_keys = {
'esc': 27,
'escape': 27,
'tab': 9,
'space': 32,
'return': 13,
'enter': 13,
'backspace': 8,
// Add a new keyboard combination shortcut
keyboardManagerService.bind = function (label, callback, opt) {
'scrolllock': 145,
'scroll_lock': 145,
'scroll': 145,
'capslock': 20,
'caps_lock': 20,
'caps': 20,
'numlock': 144,
'num_lock': 144,
'num': 144,
//replace ctrl key with meta key
if(isMac && label !== "ctrl+space"){
label = label.replace("ctrl","meta");
}
'pause': 19,
'break': 19,
var fct, elt, code, k;
// Initialize opt object
opt = angular.extend({}, defaultOpt, opt);
label = label.toLowerCase();
elt = opt.target;
if(typeof opt.target === 'string'){
elt = document.getElementById(opt.target);
}
'insert': 45,
'home': 36,
'delete': 46,
'end': 35,
'pageup': 33,
'page_up': 33,
'pu': 33,
fct = function (e) {
e = e || $window.event;
'pagedown': 34,
'page_down': 34,
'pd': 34,
// Disable event handler when focus input and textarea
if (opt['inputDisabled']) {
var elt;
if (e.target){
elt = e.target;
}else if (e.srcElement){
elt = e.srcElement;
}
'left': 37,
'up': 38,
'right': 39,
'down': 40,
if (elt.nodeType === 3){elt = elt.parentNode;}
if (elt.tagName === 'INPUT' || elt.tagName === 'TEXTAREA'){return;}
}
'f1': 112,
'f2': 113,
'f3': 114,
'f4': 115,
'f5': 116,
'f6': 117,
'f7': 118,
'f8': 119,
'f9': 120,
'f10': 121,
'f11': 122,
'f12': 123
};
// Find out which key is pressed
if (e.keyCode){
code = e.keyCode;
}else if (e.which){
code = e.which;
}
var isMac = navigator.platform.toUpperCase().indexOf('MAC')>=0;
var character = String.fromCharCode(code).toLowerCase();
// The event handler for bound element events
function eventHandler(e) {
e = e || $window.event;
if (code === 188){character = ",";} // If the user presses , when the type is onkeydown
if (code === 190){character = ".";} // If the user presses , when the type is onkeydown
var code, k;
var keys = label.split("+");
// Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked
var kp = 0;
// Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken
var shift_nums = {
"`":"~",
"1":"!",
"2":"@",
"3":"#",
"4":"$",
"5":"%",
"6":"^",
"7":"&",
"8":"*",
"9":"(",
"0":")",
"-":"_",
"=":"+",
";":":",
"'":"\"",
",":"<",
".":">",
"/":"?",
"\\":"|"
};
// Special Keys - and their codes
var special_keys = {
'esc':27,
'escape':27,
'tab':9,
'space':32,
'return':13,
'enter':13,
'backspace':8,
// Find out which key is pressed
if (e.keyCode)
{
code = e.keyCode;
}
else if (e.which) {
code = e.which;
}
'scrolllock':145,
'scroll_lock':145,
'scroll':145,
'capslock':20,
'caps_lock':20,
'caps':20,
'numlock':144,
'num_lock':144,
'num':144,
var character = String.fromCharCode(code).toLowerCase();
'pause':19,
'break':19,
if (code === 188){character = ",";} // If the user presses , when the type is onkeydown
if (code === 190){character = ".";} // If the user presses , when the type is onkeydown
'insert':45,
'home':36,
'delete':46,
'end':35,
var propagate = true;
'pageup':33,
'page_up':33,
'pu':33,
//Now we need to determine which shortcut this event is for, we'll do this by iterating over each
//registered shortcut to find the match. We use Find here so that the loop exits as soon
//as we've found the one we're looking for
_.find(_.keys(keyboardManagerService.keyboardEvent), function(key) {
'pagedown':34,
'page_down':34,
'pd':34,
var shortcutLabel = key;
var shortcutVal = keyboardManagerService.keyboardEvent[key];
'left':37,
'up':38,
'right':39,
'down':40,
// Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked
var kp = 0;
'f1':112,
'f2':113,
'f3':114,
'f4':115,
'f5':116,
'f6':117,
'f7':118,
'f8':119,
'f9':120,
'f10':121,
'f11':122,
'f12':123
};
// Some modifiers key
var modifiers = {
shift: {
wanted: false,
pressed: e.shiftKey ? true : false
},
ctrl : {
wanted: false,
pressed: e.ctrlKey ? true : false
},
alt : {
wanted: false,
pressed: e.altKey ? true : false
},
meta : { //Meta is Mac specific
wanted: false,
pressed: e.metaKey ? true : false
}
};
// Foreach keys in label (split on +)
var l = keys.length;
for (var i = 0; i < l; i++) {
// Some modifiers key
var modifiers = {
shift: {
wanted: false,
pressed: e.shiftKey ? true : false
},
ctrl: {
wanted: false,
pressed: e.ctrlKey ? true : false
},
alt: {
wanted: false,
pressed: e.altKey ? true : false
},
meta: { //Meta is Mac specific
wanted: false,
pressed: e.metaKey ? true : false
}
};
var k=keys[i];
switch (k) {
case 'ctrl':
case 'control':
kp++;
modifiers.ctrl.wanted = true;
break;
case 'shift':
case 'alt':
case 'meta':
kp++;
modifiers[k].wanted = true;
break;
}
var keys = shortcutLabel.split("+");
var opt = shortcutVal.opt;
var callback = shortcutVal.callback;
if (k.length > 1) { // If it is a special key
if(special_keys[k] === code){
kp++;
}
// Foreach keys in label (split on +)
var l = keys.length;
for (var i = 0; i < l; i++) {
} else if (opt['keyCode']) { // If a specific key is set into the config
if (opt['keyCode'] === code) {
kp++;
}
var k = keys[i];
switch (k) {
case 'ctrl':
case 'control':
kp++;
modifiers.ctrl.wanted = true;
break;
case 'shift':
case 'alt':
case 'meta':
kp++;
modifiers[k].wanted = true;
break;
}
} else { // The special keys did not match
if(character === k) {
kp++;
}else {
if(shift_nums[character] && e.shiftKey) { // Stupid Shift key bug created by using lowercase
character = shift_nums[character];
if(character === k){
kp++;
}
}
}
}
if (k.length > 1) { // If it is a special key
if (special_keys[k] === code) {
kp++;
}
}
else if (opt['keyCode']) { // If a specific key is set into the config
if (opt['keyCode'] === code) {
kp++;
}
}
else { // The special keys did not match
if (character === k) {
kp++;
}
else {
if (shift_nums[character] && e.shiftKey) { // Stupid Shift key bug created by using lowercase
character = shift_nums[character];
if (character === k) {
kp++;
}
}
}
}
} //for end
} //for end
if(kp === keys.length &&
modifiers.ctrl.pressed === modifiers.ctrl.wanted &&
modifiers.shift.pressed === modifiers.shift.wanted &&
modifiers.alt.pressed === modifiers.alt.wanted &&
modifiers.meta.pressed === modifiers.meta.wanted) {
$timeout(function() {
callback(e);
}, 1);
if (kp === keys.length &&
modifiers.ctrl.pressed === modifiers.ctrl.wanted &&
modifiers.shift.pressed === modifiers.shift.wanted &&
modifiers.alt.pressed === modifiers.alt.wanted &&
modifiers.meta.pressed === modifiers.meta.wanted) {
if(!opt['propagate']) { // Stop the event
// e.cancelBubble is supported by IE - this will kill the bubbling process.
e.cancelBubble = true;
e.returnValue = false;
//found the right callback!
// e.stopPropagation works in Firefox.
if (e.stopPropagation) {
e.stopPropagation();
e.preventDefault();
}
return false;
}
}
};
// Store shortcut
keyboardManagerService.keyboardEvent[label] = {
'callback': fct,
'target': elt,
'event': opt['type']
};
// Disable event handler when focus input and textarea
if (opt['inputDisabled']) {
var elt;
if (e.target) {
elt = e.target;
} else if (e.srcElement) {
elt = e.srcElement;
}
//Attach the function with the event
if(elt.addEventListener){
elt.addEventListener(opt['type'], fct, false);
}else if(elt.attachEvent){
elt.attachEvent('on' + opt['type'], fct);
}else{
elt['on' + opt['type']] = fct;
}
};
// Remove the shortcut - just specify the shortcut and I will remove the binding
keyboardManagerService.unbind = function (label) {
label = label.toLowerCase();
var binding = keyboardManagerService.keyboardEvent[label];
delete(keyboardManagerService.keyboardEvent[label]);
if (elt.nodeType === 3) { elt = elt.parentNode; }
if (elt.tagName === 'INPUT' || elt.tagName === 'TEXTAREA') {
//This exits the Find loop
return true;
}
}
if(!binding){return;}
$timeout(function () {
callback(e);
}, 1);
var type = binding['event'],
if (!opt['propagate']) { // Stop the event
propagate = false;
}
//This exits the Find loop
return true;
}
//we haven't found one so continue looking
return false;
});
// Stop the event if required
if (!propagate) {
// e.cancelBubble is supported by IE - this will kill the bubbling process.
e.cancelBubble = true;
e.returnValue = false;
// e.stopPropagation works in Firefox.
if (e.stopPropagation) {
e.stopPropagation();
e.preventDefault();
}
return false;
}
}
// Store all keyboard combination shortcuts
keyboardManagerService.keyboardEvent = {};
// Add a new keyboard combination shortcut
keyboardManagerService.bind = function (label, callback, opt) {
//replace ctrl key with meta key
if(isMac && label !== "ctrl+space"){
label = label.replace("ctrl","meta");
}
var elt;
// Initialize opt object
opt = angular.extend({}, defaultOpt, opt);
label = label.toLowerCase();
elt = opt.target;
if(typeof opt.target === 'string'){
elt = document.getElementById(opt.target);
}
//Ensure we aren't double binding to the same element + type otherwise we'll end up multi-binding
// and raising events for now reason. So here we'll check if the event is already registered for the element
var boundValues = _.values(keyboardManagerService.keyboardEvent);
var found = _.find(boundValues, function (i) {
return i.target === elt && i.event === opt['type'];
});
// Store shortcut
keyboardManagerService.keyboardEvent[label] = {
'callback': callback,
'target': elt,
'opt': opt['type']
};
if (!found) {
//Attach the function with the event
if (elt.addEventListener) {
elt.addEventListener(opt['type'], eventHandler, false);
} else if (elt.attachEvent) {
elt.attachEvent('on' + opt['type'], eventHandler);
} else {
elt['on' + opt['type']] = eventHandler;
}
}
};
// Remove the shortcut - just specify the shortcut and I will remove the binding
keyboardManagerService.unbind = function (label) {
label = label.toLowerCase();
var binding = keyboardManagerService.keyboardEvent[label];
delete(keyboardManagerService.keyboardEvent[label]);
if(!binding){return;}
var type = binding['event'],
elt = binding['target'],
callback = binding['callback'];
if(elt.detachEvent){
elt.detachEvent('on' + type, callback);
}else if(elt.removeEventListener){
elt.removeEventListener(type, callback, false);
}else{
elt['on'+type] = false;
}
};
//
if(elt.detachEvent){
elt.detachEvent('on' + type, callback);
}else if(elt.removeEventListener){
elt.removeEventListener(type, callback, false);
}else{
elt['on'+type] = false;
}
};
//
return keyboardManagerService;
}]);
return keyboardManagerService;
}
@@ -1,288 +1,319 @@
(function() {
'use strict';
(function () {
'use strict';
function listViewHelper(localStorageService) {
function listViewHelper(localStorageService) {
var firstSelectedIndex = 0;
var localStorageKey = "umblistViewLayout";
var firstSelectedIndex = 0;
var localStorageKey = "umblistViewLayout";
function getLayout(nodeId, availableLayouts) {
function getLayout(nodeId, availableLayouts) {
var storedLayouts = [];
var storedLayouts = [];
if(localStorageService.get(localStorageKey)) {
storedLayouts = localStorageService.get(localStorageKey);
}
if (storedLayouts && storedLayouts.length > 0) {
for (var i = 0; storedLayouts.length > i; i++) {
var layout = storedLayouts[i];
if (layout.nodeId === nodeId) {
return setLayout(nodeId, layout, availableLayouts);
}
}
}
return getFirstAllowedLayout(availableLayouts);
}
function setLayout(nodeId, selectedLayout, availableLayouts) {
var activeLayout = {};
var layoutFound = false;
for (var i = 0; availableLayouts.length > i; i++) {
var layout = availableLayouts[i];
if (layout.path === selectedLayout.path) {
activeLayout = layout;
layout.active = true;
layoutFound = true;
} else {
layout.active = false;
}
}
if(!layoutFound) {
activeLayout = getFirstAllowedLayout(availableLayouts);
}
saveLayoutInLocalStorage(nodeId, activeLayout);
return activeLayout;
}
function saveLayoutInLocalStorage(nodeId, selectedLayout) {
var layoutFound = false;
var storedLayouts = [];
if(localStorageService.get(localStorageKey)) {
storedLayouts = localStorageService.get(localStorageKey);
}
if(storedLayouts.length > 0) {
for(var i = 0; storedLayouts.length > i; i++) {
var layout = storedLayouts[i];
if(layout.nodeId === nodeId) {
layout.path = selectedLayout.path;
layoutFound = true;
}
}
}
if(!layoutFound) {
var storageObject = {
"nodeId": nodeId,
"path": selectedLayout.path
};
storedLayouts.push(storageObject);
}
localStorageService.set(localStorageKey, storedLayouts);
}
function getFirstAllowedLayout(layouts) {
var firstAllowedLayout = {};
for (var i = 0; layouts.length > i; i++) {
var layout = layouts[i];
if (layout.selected === true) {
firstAllowedLayout = layout;
break;
if (localStorageService.get(localStorageKey)) {
storedLayouts = localStorageService.get(localStorageKey);
}
}
return firstAllowedLayout;
}
if (storedLayouts && storedLayouts.length > 0) {
for (var i = 0; storedLayouts.length > i; i++) {
var layout = storedLayouts[i];
if (layout.nodeId === nodeId) {
return setLayout(nodeId, layout, availableLayouts);
}
}
function selectHandler(selectedItem, selectedIndex, items, selection, $event) {
}
var start = 0;
var end = 0;
var item = null;
return getFirstAllowedLayout(availableLayouts);
if ($event.shiftKey === true) {
}
if(selectedIndex > firstSelectedIndex) {
function setLayout(nodeId, selectedLayout, availableLayouts) {
start = firstSelectedIndex;
end = selectedIndex;
var activeLayout = {};
var layoutFound = false;
for (; end >= start; start++) {
item = items[start];
selectItem(item, selection);
}
for (var i = 0; availableLayouts.length > i; i++) {
var layout = availableLayouts[i];
if (layout.path === selectedLayout.path) {
activeLayout = layout;
layout.active = true;
layoutFound = true;
} else {
layout.active = false;
}
}
if (!layoutFound) {
activeLayout = getFirstAllowedLayout(availableLayouts);
}
saveLayoutInLocalStorage(nodeId, activeLayout);
return activeLayout;
}
function saveLayoutInLocalStorage(nodeId, selectedLayout) {
var layoutFound = false;
var storedLayouts = [];
if (localStorageService.get(localStorageKey)) {
storedLayouts = localStorageService.get(localStorageKey);
}
if (storedLayouts.length > 0) {
for (var i = 0; storedLayouts.length > i; i++) {
var layout = storedLayouts[i];
if (layout.nodeId === nodeId) {
layout.path = selectedLayout.path;
layoutFound = true;
}
}
}
if (!layoutFound) {
var storageObject = {
"nodeId": nodeId,
"path": selectedLayout.path
};
storedLayouts.push(storageObject);
}
localStorageService.set(localStorageKey, storedLayouts);
}
function getFirstAllowedLayout(layouts) {
var firstAllowedLayout = {};
for (var i = 0; layouts.length > i; i++) {
var layout = layouts[i];
if (layout.selected === true) {
firstAllowedLayout = layout;
break;
}
}
return firstAllowedLayout;
}
function selectHandler(selectedItem, selectedIndex, items, selection, $event) {
var start = 0;
var end = 0;
var item = null;
if ($event.shiftKey === true) {
if (selectedIndex > firstSelectedIndex) {
start = firstSelectedIndex;
end = selectedIndex;
for (; end >= start; start++) {
item = items[start];
selectItem(item, selection);
}
} else {
start = firstSelectedIndex;
end = selectedIndex;
for (; end <= start; start--) {
item = items[start];
selectItem(item, selection);
}
}
} else {
start = firstSelectedIndex;
end = selectedIndex;
if (selectedItem.selected) {
deselectItem(selectedItem, selection);
} else {
selectItem(selectedItem, selection);
}
for (; end <= start; start--) {
item = items[start];
selectItem(item, selection);
}
firstSelectedIndex = selectedIndex;
}
} else {
}
if(selectedItem.selected) {
deselectItem(selectedItem, selection);
} else {
selectItem(selectedItem, selection);
function selectItem(item, selection) {
var isSelected = false;
for (var i = 0; selection.length > i; i++) {
var selectedItem = selection[i];
if (item.id === selectedItem.id) {
isSelected = true;
}
}
if (!isSelected) {
selection.push({ id: item.id });
item.selected = true;
}
}
function deselectItem(item, selection) {
for (var i = 0; selection.length > i; i++) {
var selectedItem = selection[i];
if (item.id === selectedItem.id) {
selection.splice(i, 1);
item.selected = false;
}
}
}
function clearSelection(items, folders, selection) {
var i = 0;
selection.length = 0;
if (angular.isArray(items)) {
for (i = 0; items.length > i; i++) {
var item = items[i];
item.selected = false;
}
}
firstSelectedIndex = selectedIndex;
}
}
function selectItem(item, selection) {
var isSelected = false;
for (var i = 0; selection.length > i; i++) {
var selectedItem = selection[i];
if (item.id === selectedItem.id) {
isSelected = true;
if (angular.isArray(items)) {
for (i = 0; folders.length > i; i++) {
var folder = folders[i];
folder.selected = false;
}
}
}
if(!isSelected) {
selection.push({id: item.id});
item.selected = true;
}
}
}
function deselectItem(item, selection) {
for (var i = 0; selection.length > i; i++) {
var selectedItem = selection[i];
if (item.id === selectedItem.id) {
selection.splice(i, 1);
item.selected = false;
function selectAllItems(items, selection, $event) {
var checkbox = $event.target;
var clearSelection = false;
if (!angular.isArray(items)) {
return;
}
}
}
function clearSelection(items, folders, selection) {
selection.length = 0;
var i = 0;
for (var i = 0; i < items.length; i++) {
selection.length = 0;
var item = items[i];
if (checkbox.checked) {
selection.push({ id: item.id });
} else {
clearSelection = true;
}
item.selected = checkbox.checked;
if(angular.isArray(items)) {
for(i = 0; items.length > i; i++) {
var item = items[i];
item.selected = false;
}
}
if(angular.isArray(items)) {
for(i = 0; folders.length > i; i++) {
var folder = folders[i];
folder.selected = false;
if (clearSelection) {
selection.length = 0;
}
}
}
function selectAllItems(items, selection, $event) {
}
var checkbox = $event.target;
var clearSelection = false;
function isSelectedAll(items, selection) {
if (!angular.isArray(items)) {
return;
}
var numberOfSelectedItem = 0;
selection.length = 0;
for (var itemIndex = 0; items.length > itemIndex; itemIndex++) {
var item = items[itemIndex];
for (var i = 0; i < items.length; i++) {
for (var selectedIndex = 0; selection.length > selectedIndex; selectedIndex++) {
var selectedItem = selection[selectedIndex];
var item = items[i];
if (item.id === selectedItem.id) {
numberOfSelectedItem++;
}
}
if (checkbox.checked) {
selection.push({id: item.id});
} else {
clearSelection = true;
}
}
item.selected = checkbox.checked;
if (numberOfSelectedItem === items.length) {
return true;
}
}
}
if (clearSelection) {
selection.length = 0;
}
function setSortingDirection(col, direction, options) {
return options.orderBy.toUpperCase() === col.toUpperCase() && options.orderDirection === direction;
}
}
function setSorting(field, allow, options) {
if (allow) {
options.orderBy = field;
function isSelectedAll(items, selection) {
if (options.orderDirection === "desc") {
options.orderDirection = "asc";
} else {
options.orderDirection = "desc";
}
}
}
//This takes in a dictionary of Ids with Permissions and determines
// the intersect of all permissions to return an object representing the
// listview button permissions
function getButtonPermissions(unmergedPermissions, currentIdsWithPermissions) {
if (currentIdsWithPermissions == null) {
currentIdsWithPermissions = {};
}
var numberOfSelectedItem = 0;
//merge the newly retrieved permissions to the main dictionary
_.each(unmergedPermissions, function (value, key, list) {
currentIdsWithPermissions[key] = value;
});
for(var itemIndex = 0; items.length > itemIndex; itemIndex++) {
var item = items[itemIndex];
//get the intersect permissions
var arr = [];
_.each(currentIdsWithPermissions, function (value, key, list) {
arr.push(value);
});
for(var selectedIndex = 0; selection.length > selectedIndex; selectedIndex++) {
var selectedItem = selection[selectedIndex];
//we need to use 'apply' to call intersection with an array of arrays,
//see: http://stackoverflow.com/a/16229480/694494
var intersectPermissions = _.intersection.apply(_, arr);
if(item.id === selectedItem.id) {
numberOfSelectedItem++;
}
}
return {
canCopy: _.contains(intersectPermissions, 'O'), //Magic Char = O
canCreate: _.contains(intersectPermissions, 'C'), //Magic Char = C
canDelete: _.contains(intersectPermissions, 'D'), //Magic Char = D
canMove: _.contains(intersectPermissions, 'M'), //Magic Char = M
canPublish: _.contains(intersectPermissions, 'U'), //Magic Char = U
canUnpublish: _.contains(intersectPermissions, 'U'), //Magic Char = Z (however UI says it can't be set, so if we can publish 'U' we can unpublish)
};
}
}
var service = {
getLayout: getLayout,
getFirstAllowedLayout: getFirstAllowedLayout,
setLayout: setLayout,
saveLayoutInLocalStorage: saveLayoutInLocalStorage,
selectHandler: selectHandler,
selectItem: selectItem,
deselectItem: deselectItem,
clearSelection: clearSelection,
selectAllItems: selectAllItems,
isSelectedAll: isSelectedAll,
setSortingDirection: setSortingDirection,
setSorting: setSorting,
getButtonPermissions: getButtonPermissions
};
if(numberOfSelectedItem === items.length) {
return true;
}
return service;
}
}
function setSortingDirection(col, direction, options) {
return options.orderBy.toUpperCase() === col.toUpperCase() && options.orderDirection === direction;
}
function setSorting(field, allow, options) {
if (allow) {
options.orderBy = field;
if (options.orderDirection === "desc") {
options.orderDirection = "asc";
} else {
options.orderDirection = "desc";
}
}
}
var service = {
getLayout: getLayout,
getFirstAllowedLayout: getFirstAllowedLayout,
setLayout: setLayout,
saveLayoutInLocalStorage: saveLayoutInLocalStorage,
selectHandler: selectHandler,
selectItem: selectItem,
deselectItem: deselectItem,
clearSelection: clearSelection,
selectAllItems: selectAllItems,
isSelectedAll: isSelectedAll,
setSortingDirection: setSortingDirection,
setSorting: setSorting
};
return service;
}
angular.module('umbraco.services').factory('listViewHelper', listViewHelper);
angular.module('umbraco.services').factory('listViewHelper', listViewHelper);
})();
@@ -21,6 +21,7 @@ function packageHelper(assetsService, treeService, eventsService, $templateCache
}
angular.module('umbraco.services').factory('packageHelper', packageHelper);
//TODO: I believe this is obsolete
function umbPhotoFolderHelper($compile, $log, $timeout, $filter, imageHelper, mediaHelper, umbRequestHelper) {
return {
/** sets the image's url, thumbnail and if its a folder */
@@ -319,7 +320,6 @@ function umbPhotoFolderHelper($compile, $log, $timeout, $filter, imageHelper, me
}
};
}
angular.module("umbraco.services").factory("umbPhotoFolderHelper", umbPhotoFolderHelper);
/**
@@ -0,0 +1,65 @@
(function() {
'use strict';
function variationsHelper() {
var variations = [];
function setMaster(master) {
master.master = true;
variations.push(master);
}
function getVariations() {
return variations;
}
function createVariation(variation) {
var newVariation = angular.copy(variation);
newVariation.master = false;
variations.push(newVariation);
}
function saveVariation(updatedVariation) {
for(var i = 0; i < variations.length; i++) {
var variation = variations[i];
if(variation.id === updatedVariation) {
variation.name = updatedVariation.name;
variation.description = updatedVariation.description;
}
}
}
function cloneVariation(variation) {
var variationClone = angular.copy(variation);
variationClone.master = false;
variationClone.published = false;
variations.push(variationClone);
console.log(variations);
}
function deleteVariation(variation, event, index) {
variations.splice(index, 1);
}
var service = {
setMaster: setMaster,
getVariations: getVariations,
createVariation: createVariation,
saveVariation: saveVariation,
cloneVariation: cloneVariation,
deleteVariation: deleteVariation
};
return service;
}
angular.module('umbraco.services').factory('variationsHelper', variationsHelper);
})();
@@ -155,6 +155,53 @@ function NavigationController($scope, $rootScope, $location, $log, $routeParams,
}
};
$scope.websites = [
{
name: "English",
language: "en-UK",
selected: true
},
{
name: "Dansk",
language: "da-DK",
selected: false
}
];
$scope.createWebsite = function() {
$scope.createWebsiteOverlay = {
view: "createwebsite",
title: "Create website",
submitButtonLabel: "Create website",
show: true,
submit: function(model) {
// deselct all current sites
for(var i = 0; i < $scope.websites.length; i++) {
var website = $scope.websites[i];
website.selected = false;
}
// set new site to selected and push to scope
model.website.selected = true;
$scope.websites.push(model.website);
// clsoe overlay
$scope.createWebsiteOverlay.show = false;
$scope.createWebsiteOverlay = null;
},
close: function() {
$scope.createWebsiteOverlay.show = false;
$scope.createWebsiteOverlay = null;
}
};
};
$scope.clickWebsite = function(website) {
};
//ensure to unregister from all events!
$scope.$on('$destroy', function () {
for (var e in evts) {
@@ -107,7 +107,9 @@
@import "components/umb-grid.less";
@import "components/umb-empty-state.less";
@import "components/umb-property-editor.less";
@import "components/umb-iconpicker.less";
@import "components/umb-website-selector.less";
@import "components/umb-dots.less";
@import "components/buttons/umb-button.less";
@import "components/buttons/umb-button-group.less";
@@ -152,6 +152,30 @@
}
}
/* ---------- OVERLAY TREE ---------- */
.umb-overlay.umb-overlay-tree {
position: absolute;
width: 500px;
top: 0;
left: 100%;
bottom: 0;
border: none;
//box-shadow: 0 0 20px rgba(0,0,0,0.19), 0 0 6px rgba(0,0,0,0.23);
box-shadow: 3px 0 7px #dbdbdb;
display: inline-block;
}
.umb-overlay.umb-overlay-tree .umb-overlay-header {
flex-basis: 100px;
padding: 20px;
box-sizing: border-box;
}
.umb-overlay.umb-overlay-tree .umb-overlay-container {
padding: 20px;
}
/* ---------- OVERLAY ITEM DETAILS ---------- */
.umb-overlay__item-details {
position: absolute;
@@ -0,0 +1,26 @@
.umb-dots {
position: relative;
width: 5px;
height: 5px;
background-color: @gray;
border-radius: 50%;
}
.umb-dots:before,
.umb-dots:after {
display: block;
position: absolute;
content: '';
width: 5px;
height: 5px;
background-color: @gray;
border-radius: 50%;
}
.umb-dots:before {
transform: translateX(-8px);
}
.umb-dots:after {
transform: translateX(8px);
}
@@ -0,0 +1,46 @@
.umb-iconpicker {
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin: 0;
}
.umb-iconpicker-item {
display: flex;
flex-direction: row;
flex: 0 0 14.28%;
justify-content: center;
align-items: center;
margin-bottom: 0;
overflow: hidden;
}
.umb-iconpicker-item a {
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 100%;
padding: 15px 0;
text-decoration: none;
}
.umb-iconpicker-item a:hover,
.umb-iconpicker-item a:focus{
background: darken(@grayLighter, 1%);
outline: none;
}
.umb-iconpicker-item a:active {
background: darken(@grayLighter, 4%);
}
.umb-iconpicker-item i {
font-size: 30px;
}
@@ -16,8 +16,23 @@
.umb-keyboard-shortcuts-overview__overlay-close {
position: absolute;
top: 10px;
right: 10px;
top: 20px;
right: 20px;
font-size: 25px;
border-radius: 20px;
width: 35px;
height: 35px;
display: flex;
justify-content: center;
align-items: center;
background-color: transparent;
line-height: 1em;
}
.umb-keyboard-shortcuts-overview__overlay-close:hover {
background-color: @blue;
color: #ffffff;
text-decoration: none;
}
.umb-keyboard-shortcuts-overview__overlay-content {
@@ -198,6 +198,7 @@ input.umb-table__input {
padding: 6px 2px;
text-align: left;
overflow:hidden;
}
.umb-table-cell > * {
@@ -0,0 +1,109 @@
.umb-website-selector {
border-bottom: 1px solid #d9d9d9;
display: flex;
align-items: stretch;
height: 50px;
position: relative;
}
.umb-website-selector__create-website {
display: flex;
width: 100%;
justify-content: center;
align-items: center;
color: @blue;
}
.umb-website-selector__dropdown-toggle {
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
width: 100%;
box-sizing: border-box;
padding-left: 20px;
padding-right: 20px;
font-weight: bold;
}
.umb-website-selector__dropdown-toggle:hover,
.umb-website-selector__dropdown-toggle:focus {
text-decoration: none;
}
.umb-website-selector__dropdown-toggle-content {
display: flex;
align-items: center;
}
.umb-website-selector__dropdown-toggle-name {
margin-right: 5px;
}
.umb-website-selector__dropdown {
position: absolute;
top: 50px;
left: 0;
right: 0;
z-index: 1;
background: #ffffff;
}
.umb-website-selector__websites {
margin-left: 0;
margin-bottom: 0;
list-style: none;
max-height: 300px;
overflow-y: auto;
}
.umb-website-selector__website-link {
display: flex;
align-items: center;
justify-content: space-between;
padding-top: 10px;
padding-right: 20px;
padding-bottom: 10px;
padding-left: 38px;
}
.umb-website-selector__website-link:hover,
.umb-website-selector__website-link.-selected {
background-color: @grayLighter;
text-decoration: none;
}
.umb-website-selector__dropdown-action {
display: flex;
justify-content: center;
align-items: center;
padding-top: 10px;
padding-bottom: 10px;
color: @blue;
font-size: 12px;
}
.umb-website-selector__dropdown-arrow {
width: 0;
height: 0;
margin-right: 10px;
}
.umb-website-selector__dropdown-arrow.-down {
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-top: 4px solid @gray;
}
.umb-website-selector__dropdown-arrow.-up {
border-left: 4px solid transparent;
border-right: 4px solid transparent;
border-bottom: 4px solid @gray;
}
.umb-website-selector__dropdown-action:hover {
text-decoration: none;
background: @blue;
color: #ffffff;
}
@@ -16,12 +16,12 @@ label small, .guiDialogTiny {
font-size: 11px
}
label.control-label {
label.control-label, .control-label {
padding: 0 10px 0 0 !important;
font-weight: bold;
}
.umb-status-label{
color: @gray !important;
}
@@ -164,7 +164,7 @@ textarea {
// Identify controls by their labels
label {
display: block;
display: inline-block;
margin-bottom: 5px;
}
+1 -1
View File
@@ -139,7 +139,7 @@ h5.-black {
}
/* LABELS*/
.umb-control-group label.control-label {
.umb-control-group label.control-label, .umb-control-group .control-label {
text-align: left;
}
.umb-control-group label.control-label > div > label {
@@ -9,13 +9,41 @@
color: @white;
position: absolute;
z-index: 10000;
top: 0px;
left: 0px;
margin: 0 !Important;
top: 0;
left: 0;
margin: 0 !important;
padding: 0;
border-radius: 0;
}
@media only screen and (-webkit-min-device-pixel-ratio: 1.5),
only screen and (min-resolution: 144dpi)
{
.login-overlay {
background-image: url(../img/application/logo@2x.png) !important;
}
}
@media only screen and (-webkit-min-device-pixel-ratio: 2),
only screen and (min-resolution: 192dpi)
{
.login-overlay {
background-image: url(../img/application/logo@2x.png) !important;
}
}
@media only screen and (-webkit-min-device-pixel-ratio: 3),
only screen and (min-resolution: 3dppx),
only screen and (min-resolution: 350dpi)
{
.login-overlay {
background-image: url(../img/application/logo@3x.png) !important;
}
}
.login-overlay .umb-modalcolumn {
background: none;
border: none;
@@ -62,7 +90,7 @@
}
#hrOr hr {
margin: 0px;
margin: 0;
border: none;
background-color: @gray;
height: 1px;
@@ -493,3 +493,66 @@ input.umb-panel-header-description {
.umb-editor-drawer-content__left-side {
margin-right: auto;
}
/* --- VARIATIONS --- */
.umb-variations-quick-switcher__toggle {
position: absolute;
top: 6px;
right: 10px;
font-size: 16px;
}
.umb-variations-quick-switcher_variations {
position: absolute;
top: 40px;
left: 0;
right: 0;
z-index: 20;
background-color: #ffffff;
max-height: 200px;
overflow-y: scroll;
}
.umb-variations-quick-switcher__variation {
display: flex;
flex-direction: row;
align-items: center;
padding: 10px 15px;
}
.umb-variations-quick-switcher__variation:last-child {
border-bottom: none;
}
.umb-variations-quick-switcher__variation:hover,
.umb-variations-quick-switcher__variation:focus {
background-color: @grayLighter;
text-decoration: none;
outline: none;
}
.umb-variations-quick-switcher__variation-published-state {
display: block;
width: 8px;
height: 8px;
border-radius: 50%;
background-color: @grayLight;
margin-right: 10px;
}
.umb-variations-quick-switcher__variation-published-state.-published {
background-color: @green;
}
.umb-variations-quick-switcher__variation-name {
font-size: 12px;
font-weight: bold;
}
.umb-variations-quick-switcher__variation-description {
font-size: 12px;
color: @gray;
margin-left: 10px;
}
@@ -81,6 +81,9 @@ div.umb-codeeditor .umb-btn-toolbar {
font-size:16px !important;
}
/* pre-value editor */
.rte-editor-preval .control-group .controls > div > label .mce-ico { line-height: 20px; }
//
// Color picker
@@ -275,11 +278,12 @@ ul.color-picker li a {
.umb-cropper{
position: relative;
padding: 10px;
}
.umb-cropper img, .umb-cropper-gravity img{
position: absolute;
position: relative;
max-width: 100%;
height: auto;
top: 0;
left: 0;
}
@@ -293,19 +297,22 @@ ul.color-picker li a {
left: 0;
cursor: move;
z-index: 6001;
position: absolute;
}
.umb-cropper .viewport{
overflow: hidden;
position: relative;
margin: auto;
max-width: 100%;
height: auto;
}
.umb-cropper-gravity .viewport{
overflow: hidden;
position: relative;
width: 400px;
height: 300px
width: 100%;
height: 100%;
}
@@ -335,27 +342,45 @@ ul.color-picker li a {
opacity: 0.8;
}
.umb-cropper-gravity .overlay i{
.umb-cropper-gravity .overlay i {
font-size: 26px;
line-height: 26px;
opacity: 0.8 !important;
}
.umb-cropper .crop-container{
.umb-cropper .crop-container {
text-align: center;
}
.umb-cropper .crop-slider{
vertical-align: middle;
padding: 10px 50px 10px 50px;
.umb-cropper .crop-slider {
padding: 10px;
border-top: 1px solid @grayLighter;
margin-top: 10px;
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
@media (min-width: 769px) {
padding: 10px 50px 10px 50px;
}
}
.umb-cropper .crop-slider i{color: @gray;}
.umb-cropper .crop-slider input{
margin-top: 7px;
width: 320px;
.umb-cropper .crop-slider i {
color: @gray;
flex: 0 0 25px;
padding: 0 5px;
box-sizing: border-box;
}
.umb-cropper .crop-slider i:first-of-type {
text-align: right;
}
.umb-cropper .crop-slider input {
flex: 0 1 auto;
}
.umb-cropper-gravity .viewport, .umb-cropper-gravity, .umb-cropper-imageholder {
display: inline-block;
@@ -372,55 +397,98 @@ ul.color-picker li a {
}
.gravity-container .viewport {
width: 494px;
max-width: 600px;
}
.gravity-container .viewport:hover {
cursor: pointer;
}
.imagecropper {
display: flex;
align-items: flex-start;
flex-direction: row;
@media (max-width: 768px) {
flex-direction: column;
float: left;
max-width: 100%;
}
}
.imagecropper .umb-cropper__container {
position: relative;
margin-bottom: 10px;
max-width: 100%;
border: 1px solid #f8f8f8;
@media (min-width: 769px) {
width: 600px;
}
}
.umb-close-cropper {
position: absolute;
top: 3px;
right: 3px;
cursor: pointer;
}
.umb-close-cropper:hover {
opacity: .9;
background: @grayLighter;
}
.imagecropper .umb-sortable-thumbnails {
border-left: 2px solid #f8f8f8;
margin-left: 4px;
padding-left: 2px;
float: left;
width: 100px;
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.imagecropper .umb-sortable-thumbnails li {
display: block;
}
display: flex;
flex-direction: column;
justify-content: space-between;
.imagecropper .umb-sortable-thumbnails li.current a, .imagecropper .umb-sortable-thumbnails li.current a:hover {
background: #eeeeee;
text-decoration: none;
}
.imagecropper .umb-sortable-thumbnails li:first-of-type {
padding: 8px;
margin-top: 0;
padding-top: 0;
}
.imagecropper .umb-sortable-thumbnails li .crop-name, .imagecropper .umb-sortable-thumbnails li .crop-size {
.imagecropper .umb-sortable-thumbnails li.current {
border-color: @grayLight;
background: @grayLighter;
color: @black;
cursor: pointer;
}
.imagecropper .umb-sortable-thumbnails li:hover,
.imagecropper .umb-sortable-thumbnails li.current:hover {
border-color: @grayLight;
background: @grayLighter;
color: @black;
cursor: pointer;
opacity: .95;
}
.imagecropper .umb-sortable-thumbnails li .crop-name,
.imagecropper .umb-sortable-thumbnails li .crop-size {
display: block;
text-align: left;
font-size: 11px;
font-size: 13px;
line-height: 1;
}
.imagecropper .umb-sortable-thumbnails li .crop-name {
font-weight: bold;
margin: 10px 0 5px;
}
.imagecropper .umb-sortable-thumbnails li .crop-size {
font-size: 10px;
font-style: italic;
color: #666;
}
.imagecropper .umb-sortable-thumbnails li a {
display: block;
padding: 5px;
}
.imagecropper .umb-sortable-thumbnails li a:hover {
background: #f8f8f8;
text-decoration: none;
}
.imagecropper .umb-sortable-thumbnails li a:hover .crop-text {
text-decoration: none;
margin: 0 0 5px;
}
.btn-crop-delete {
@@ -428,20 +496,6 @@ ul.color-picker li a {
text-align: left;
}
.imagecropper .umb-sortable-thumbnails.many {
width: 210px;
}
.imagecropper .umb-sortable-thumbnails.many li {
width: 85px;
float: left;
}
.imagecropper .umb-sortable-thumbnails.many li:nth-child(2) {
margin-top: 0;
padding-top: 0;
}
//
// folder-browser
// --------------------------------------------------
@@ -19,7 +19,8 @@ ul.sections li {
}
ul.sections li [class^="icon-"]:before,
ul.sections li [class*=" icon-"]:before{
ul.sections li [class*=" icon-"]:before,
ul.sections li img.icon-section {
font-size: 30px;
margin: 1px 0 0 0;
opacity: 0.4;
@@ -29,7 +30,8 @@ ul.sections li [class*=" icon-"]:before{
}
ul.sections:hover li [class^="icon-"]:before,
ul.sections:hover li [class*=" icon-"]:before {
ul.sections:hover li [class*=" icon-"]:before,
ul.sections:hover li img.icon-section {
opacity: 1
}
@@ -2,55 +2,48 @@
<div class="umb-panel-header">
<div class="umb-el-wrap umb-panel-buttons">
<div class="form-search">
<i class="icon-search"></i>
<i class="icon-search"></i>
<input type="text"
style="width: 100%"
ng-model="searchTerm"
class="umb-search-field search-query input-block-level"
style="width: 100%"
ng-model="searchTerm"
class="umb-search-field search-query input-block-level"
placeholder="Filter...">
</div>
</div>
</div>
<div class="umb-panel-body with-footer">
<div class="umb-control-group">
<select ng-model="color" class="input-block-level">
<option value="">Black</option>
<option value="color-green">Green</option>
<option value="color-yellow">Yellow</option>
<option value="color-green">Green</option>
<option value="color-yellow">Yellow</option>
<option value="color-orange">Orange</option>
<option value="color-blue">Blue</option>
<option value="color-blue">Blue</option>
<option value="color-red">Red</option>
</select>
<!--
<select class="input-block-level">
<option value="">Black</option>
<option value="color-green">Green</option>
<option value="color-blue">Turquoise</option>
<option value="color-purple">Purple</option>
<option value="color-red">Red</option>
<option value="color-orange">Orange</option>
<option value="color-sky-blue">Sky blue</option>
<option value="color-yellow">Yellow</option>
</select>-->
</div>
<div class="umb-loader" ng-hide="icons"></div>
<umb-load-indicator ng-if="loading"></umb-load-indicator>
<div class="umb-control-group">
<ul class="umb-thumbnails thumbnails" ng-class="color">
<li class="span1" ng-repeat="icon in icons|filter: searchTerm">
<a href="#" title="{{icon}}" class="thumbnail" ng-click="submitClass(icon)" prevent-default>
<i class="{{icon}} large" style="font-size: 32px"></i>
<div class="umb-control-group" ng-show="!loading">
<ul class="umb-iconpicker" ng-class="color" ng-show="icons">
<li class="umb-iconpicker-item" ng-repeat="icon in filtered = (icons | filter: searchTerm) track by $id(icon)">
<a href="#" title="{{icon}}" ng-click="submitClass(icon)" prevent-default>
<i class="{{icon}} large"></i>
</a>
</li>
</ul>
</div>
<umb-empty-state
ng-if="filtered.length === 0"
position="center">
<localize key="defaultdialogs_noIconsFound">No icons were found.</localize>
</umb-empty-state>
</div>
<div class="umb-panel-footer" >
<div class="umb-el-wrap umb-panel-buttons">
<div class="btn-toolbar umb-btn-toolbar pull-right">
@@ -0,0 +1,15 @@
(function() {
"use strict";
function CreateWebsiteOverlay($scope) {
var vm = this;
$scope.model.website = {};
}
angular.module("umbraco").controller("Umbraco.Overlay.CreateWebsiteOverlay", CreateWebsiteOverlay);
})();
@@ -0,0 +1,26 @@
<div ng-controller="Umbraco.Overlay.CreateWebsiteOverlay as vm">
<div class="umb-control-group control-group">
<label>Website name</label>
<input type="text" ng-model="model.website.name" />
</div>
<div class="umb-control-group control-group">
<label>Website language</label>
<select ng-model="model.website.language">
<option value="aa-DJ">Afar (Djinouti) [aa-DJ]</option>
<option value="aa-ER">Afar (Eritrea) [aa-ER]</option>
<option value="aa-ET">Afar (Ethiopia) [aa-ET]</option>
</select>
</div>
<div class="umb-control-group control-group">
<label>Create blank</label>
<input type="checkbox" ng-model="model.website.blank" />
<label>Copy all</label>
<input type="checkbox" ng-model="model.website.copyAll" />
<label>Copy selected</label>
<input type="checkbox" ng-model="model.website.copySelected" />
</div>
</div>
@@ -38,14 +38,19 @@
<umb-load-indicator ng-if="loading"></umb-load-indicator>
<div class="umb-control-group" ng-show="!loading">
<ul class="umb-thumbnails thumbnails" ng-class="color">
<li class="span1" ng-repeat="icon in icons|filter: searchTerm">
<a href="#" title="{{icon}}" class="thumbnail" ng-click="selectIcon(icon, color)" prevent-default>
<i class="{{icon}} large" style="font-size: 32px"></i>
<div class="umb-control-group" ng-show="!loading && filtered.length > 0 ">
<ul class="umb-iconpicker" ng-class="color" ng-show="icons">
<li class="umb-iconpicker-item" ng-repeat="icon in filtered = (icons | filter: searchTerm) track by $id(icon)">
<a href="#" title="{{icon}}" ng-click="selectIcon(icon, color)" prevent-default>
<i class="{{icon}} large"></i>
</a>
</li>
</ul>
</div>
<umb-empty-state
ng-if="filtered.length === 0"
position="center">
<localize key="defaultdialogs_noIconsFound">No icons were found.</localize>
</umb-empty-state>
</div>
@@ -65,8 +65,14 @@
</div>
<umb-website-selector
websites="websites"
on-create-website="createWebsite"
on-click-website="clickWebsite">
</umb-website-selector>
<!-- the tree -->
<div id="tree" class="umb-modalcolumn-body" ng-if="authenticated">
<div id="tree" ng-if="authenticated && websites.length > 0">
<umb-tree
cachekey="_"
eventhandler="treeEventHandler"
@@ -87,6 +93,12 @@
</umb-context-menu>
</div>
<umb-overlay
ng-if="createWebsiteOverlay.show"
model="createWebsiteOverlay"
view="createWebsiteOverlay.view"
position="tree">
</umb-overlay>
<!-- Tree dialogs -->
<div id="dialog" class='umb-modalcolumn fill shadow'
@@ -1,62 +1,62 @@
<div>
<div id="applications" ng-class="{faded:stickyNavigation}">
<ul class="sections">
<li class="avatar">
<a href="#" ng-click="avatarClick()" hotkey="ctrl+shift+u" title="{{user.name}}" prevent-default>
<img id="avatar-img" ng-src="{{avatar[0].value}}" ng-srcset="{{avatar[1].value}} 2x, {{avatar[2].value}} 3x" />
</a>
</li>
<li ng-repeat="section in sections | limitTo: maxSections" ng-class="{current: section.alias == currentSection}">
<a href="#/{{section.alias}}"
ng-dblclick="sectionDblClick(section)"
ng-click="sectionClick($event, section)"
prevent-default>
<section-icon icon="{{section.cssclass}}"></section-icon>
<span>{{section.name}}</span>
</a>
</li>
<li class="expand" ng-class="{ 'open': showTray === true }" ng-show="needTray">
<a href ng-click="trayClick()">
<i class="icon icon-arrow-right"></i>
</a>
</li>
<li class="help">
<a href class="help" hotkey="ctrl+shift+h" ng-click="helpClick()" prevent-default>
<i class="icon-help-alt"></i>
<span><localize key="sections_help">Help</localize></span>
</a>
</li>
</ul>
</div>
<div id="applications-tray" ng-show="showTray" ng-animate="trayAnimation()">
<ul class="sections sections-tray">
<li ng-repeat="section in sections | limitTo: overflowingSections" ng-class="{current: section.alias == currentSection}">
<a href="#/{{section.alias}}"
ng-dblclick="sectionDblClick(section)"
ng-click="sectionClick($event, section)"
prevent-default>
<section-icon icon="{{section.cssclass}}"></section-icon>
<span>{{section.name}}</span>
</a>
</li>
</ul>
</div>
<umb-overlay
ng-if="helpDialog.show"
model="helpDialog"
view="helpDialog.view"
position="left">
</umb-overlay>
<umb-overlay
ng-if="userDialog.show"
model="userDialog"
view="userDialog.view"
position="left">
</umb-overlay>
</div>
<div>
<div id="applications" ng-class="{faded:stickyNavigation}">
<ul class="sections">
<li class="avatar">
<a href="#" ng-click="avatarClick()" hotkey="ctrl+shift+u" title="{{user.name}}" prevent-default>
<img id="avatar-img" ng-src="{{avatar[0].value}}" ng-srcset="{{avatar[1].value}} 2x, {{avatar[2].value}} 3x" />
</a>
</li>
<li ng-repeat="section in sections | limitTo: maxSections" ng-class="{current: section.alias == currentSection}">
<a href="#/{{section.alias}}"
ng-dblclick="sectionDblClick(section)"
ng-click="sectionClick($event, section)"
prevent-default>
<section-icon icon="{{section.cssclass}}"></section-icon>
<span>{{section.name}}</span>
</a>
</li>
<li class="expand" ng-class="{ 'open': showTray === true }" ng-show="needTray">
<a href ng-click="trayClick()">
<i class="icon icon-arrow-right"></i>
</a>
</li>
<li class="help">
<a href class="help" hotkey="ctrl+shift+h" ng-click="helpClick()" prevent-default>
<i class="icon-help-alt"></i>
<span><localize key="sections_help">Help</localize></span>
</a>
</li>
</ul>
</div>
<div id="applications-tray" ng-show="showTray" ng-animate="trayAnimation()" style="display: none;">
<ul class="sections sections-tray">
<li ng-repeat="section in sections | limitTo: overflowingSections" ng-class="{current: section.alias == currentSection}">
<a href="#/{{section.alias}}"
ng-dblclick="sectionDblClick(section)"
ng-click="sectionClick($event, section)"
prevent-default>
<section-icon icon="{{section.cssclass}}"></section-icon>
<span>{{section.name}}</span>
</a>
</li>
</ul>
</div>
<umb-overlay
ng-if="helpDialog.show"
model="helpDialog"
view="helpDialog.view"
position="left">
</umb-overlay>
<umb-overlay
ng-if="userDialog.show"
model="userDialog"
view="userDialog.view"
position="left">
</umb-overlay>
</div>
@@ -31,10 +31,14 @@
<div class="umb-panel-header-name" ng-if="nameLocked">{{ name }}</div>
<umb-generate-alias class="umb-panel-header-alias"
ng-if="!hideAlias"
alias="$parent.alias"
alias-from="$parent.name"
<a class="umb-variations-quick-switcher__toggle" href="" ng-click="toggleVariationsQuickSwitch()">
<i class="icon-documents"></i>
</a>
<umb-generate-alias class="umb-panel-header-alias"
ng-if="!hideAlias"
alias="$parent.alias"
alias-from="$parent.name"
enable-lock="true"
server-validation-field="Alias"></umb-generate-alias>
@@ -1,12 +1,12 @@
<div class="umb-cropper-gravity">
<div class="gravity-container">
<div class="gravity-container" ng-show="loaded">
<div class="viewport">
<img ng-src="{{src}}" style="max-width: 100%; max-height: 100%" />
<img ng-src="{{src}}" style="max-width: 100%; max-height: 100%" ng-click="setFocalPoint($event)" draggable="false" />
<div class="overlay" ng-style="style()">
</div>
</div>
</div>
</div>
</div>
@@ -1,4 +1,5 @@
<div class="umb-crop-thumbnail-container"
ng-style="{height: height, width: width, overflow: 'hidden', position: 'relative'}">
<div class="umb-crop-thumbnail-container"
ng-style="{height: height, width: width, overflow: 'hidden', position: 'relative'}"
ng-show="loaded">
<img ng-src="{{src}}" alt="{{}}" ng-style="preview" class="noScale" />
</div>
</div>
@@ -1,5 +1,5 @@
<div class="umb-overlay umb-overlay-{{position}}" on-outside-click="closeOverLay()">
<form class="umb-overlay__form" name="overlayForm" ng-submit="submitForm(model)" novalidate val-form-manager>
<ng-form class="umb-overlay__form" name="overlayForm" novalidate val-form-manager>
<div class="umb-overlay-header">
<h4 class="umb-overlay__title">{{model.title}}</h4>
@@ -44,8 +44,9 @@
<umb-button
button-style="success"
label="Confirm"
type="submit"
disabled="!directive.enableConfirmButton">
type="button"
disabled="!directive.enableConfirmButton"
action="submitForm(model)">
</umb-button>
</div>
</div>
@@ -64,10 +65,11 @@
label-key="{{model.submitButtonLabelKey}}"
label="{{model.submitButtonLabel}}"
ng-if="model.submit && model.hideSubmitButton !== true"
type="submit">
type="button"
action="submitForm(model)">
</umb-button>
</div>
</div>
</form>
</ng-form>
</div>
@@ -1,19 +1,23 @@
<div>
<ul class="umb-tree">
<li class="root">
<ul class="umb-search-group">
<li ng-repeat="result in results">
<div style="padding-left: 20px">
<a class="umb-search-group-item-link" ng-class="{first:$first}" ng-click="selectResultCallback($event, result)">
<div class="umb-search-group-item-name">
<i class="icon umb-tree-icon sprTree {{result.icon}}"></i>
{{result.name}}
</div>
<small class="search-subtitle" ng-if="result.subTitle">{{result.subTitle}}</small>
</a>
</div>
</li>
</ul>
</li>
</ul>
</div>
<ul class="umb-tree">
<li class="root">
<ul class="umb-search-group">
<li ng-repeat="result in results">
<div style="padding-left: 20px" ng-class="{'umb-tree-node-checked' : result.selected}">
<a class="umb-search-group-item-link" ng-class="{first:$first}" ng-click="selectResultCallback($event, result)">
<div class="umb-search-group-item-name">
<i class="icon umb-tree-icon sprTree {{result.icon}}"></i>
{{result.name}}
</div>
<small class="search-subtitle" ng-if="result.subTitle">{{result.subTitle}}</small>
</a>
</div>
</li>
</ul>
</li>
</ul>
@@ -19,8 +19,8 @@
<div class="umb-keyboard-shortcuts-overview__overlay" ng-if="shortcutOverlay">
<a href="" ng-click="toggleShortcutsOverlay()" data-hotkey="esc">
<i class="umb-keyboard-shortcuts-overview__overlay-close icon-delete"></i>
<a href="" class="umb-keyboard-shortcuts-overview__overlay-close" ng-click="toggleShortcutsOverlay()" data-hotkey="esc" hotkey-when-hidden="true">
<i class="icon-delete"></i>
</a>
<div class="umb-keyboard-shortcuts-overview__overlay-content">
@@ -0,0 +1,32 @@
<div class="umb-website-selector" on-outside-click="closeWebsiteDropDown()">
<a class="umb-website-selector__create-website" ng-if="websites.length === 0" href="" ng-click="createWebsite()">
Create website
</span>
<a class="umb-website-selector__dropdown-toggle" ng-if="websites.length > 0" href="" ng-click="toggleWebsiteDropDown()">
<div class="umb-website-selector__dropdown-toggle-content">
<span ng-if="showWebsiteDropdown" class="umb-website-selector__dropdown-arrow -up"></span>
<span ng-if="!showWebsiteDropdown" class="umb-website-selector__dropdown-arrow -down"></span>
<span class="umb-website-selector__dropdown-toggle-name">{{ selectedWebsite.name }}</span>
<small>({{ selectedWebsite.language }})</small>
</div>
<div class="umb-dots"></div>
</a>
<div class="umb-website-selector__dropdown shadow-depth-3" ng-show="showWebsiteDropdown">
<ul class="umb-website-selector__websites">
<li class="umb-website-selector__website" ng-repeat="website in websites | filter:{ selected: '!'+true }">
<a class="umb-website-selector__website-link" ng-click="clickWebsite(website)" href="" ng-class="{'-selecetd': website.selected}">
<div>
<span class="umb-website-selector__website-name">{{ website.name}}</span>
<small>({{ website.language }})</small>
</div>
<div class="umb-dots"></div>
</a>
</li>
</ul>
<a class="umb-website-selector__dropdown-action" ng-click="createWebsite()" href="">Create website</a>
</div>
</div>
@@ -82,7 +82,8 @@ function ContentEditController($scope, $rootScope, $routeParams, $q, $timeout, $
statusMessage: args.statusMessage,
saveMethod: args.saveMethod,
scope: $scope,
content: $scope.content
content: $scope.content,
action: args.action
}).then(function (data) {
//success
init($scope.content);
@@ -195,15 +196,15 @@ function ContentEditController($scope, $rootScope, $routeParams, $q, $timeout, $
};
$scope.sendToPublish = function () {
return performSave({ saveMethod: contentResource.sendToPublish, statusMessage: "Sending..." });
return performSave({ saveMethod: contentResource.sendToPublish, statusMessage: "Sending...", action: "sendToPublish" });
};
$scope.saveAndPublish = function () {
return performSave({ saveMethod: contentResource.publish, statusMessage: "Publishing..." });
return performSave({ saveMethod: contentResource.publish, statusMessage: "Publishing...", action: "publish" });
};
$scope.save = function () {
return performSave({ saveMethod: contentResource.save, statusMessage: "Saving..." });
return performSave({ saveMethod: contentResource.save, statusMessage: "Saving...", action: "save" });
};
$scope.preview = function (content) {
@@ -0,0 +1,63 @@
angular.module("umbraco")
.controller("Umbraco.Editors.DocumentTypes.CopyController",
function ($scope, contentTypeResource, treeService, navigationService, notificationsService, appState, eventsService) {
var dialogOptions = $scope.dialogOptions;
$scope.dialogTreeEventHandler = $({});
function nodeSelectHandler(ev, args) {
args.event.preventDefault();
args.event.stopPropagation();
if ($scope.target) {
//un-select if there's a current one selected
$scope.target.selected = false;
}
$scope.target = args.node;
$scope.target.selected = true;
}
$scope.copy = function () {
$scope.busy = true;
$scope.error = false;
contentTypeResource.copy({ parentId: $scope.target.id, id: dialogOptions.currentNode.id })
.then(function (path) {
$scope.error = false;
$scope.success = true;
$scope.busy = false;
//get the currently edited node (if any)
var activeNode = appState.getTreeState("selectedNode");
//we need to do a double sync here: first sync to the copied content - but don't activate the node,
//then sync to the currenlty edited content (note: this might not be the content that was copied!!)
navigationService.syncTree({ tree: "documentTypes", path: path, forceReload: true, activate: false }).then(function (args) {
if (activeNode) {
var activeNodePath = treeService.getPath(activeNode).join();
//sync to this node now - depending on what was copied this might already be synced but might not be
navigationService.syncTree({ tree: "documentTypes", path: activeNodePath, forceReload: false, activate: true });
}
});
}, function (err) {
$scope.success = false;
$scope.error = err;
$scope.busy = false;
//show any notifications
if (angular.isArray(err.data.notifications)) {
for (var i = 0; i < err.data.notifications.length; i++) {
notificationsService.showNotification(err.data.notifications[i]);
}
}
});
};
$scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
$scope.$on('$destroy', function () {
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
});
});
@@ -0,0 +1,51 @@
<div class="umb-dialog umb-pane" ng-controller="Umbraco.Editors.DocumentTypes.CopyController">
<div class="umb-dialog-body">
<div class="umb-pane">
<p class="abstract" ng-hide="success">
<localize key="contentTypeEditor_folderToCopy">Select the folder to copy</localize> <strong>{{currentNode.name}}</strong>&nbsp;<localize key="contentTypeEditor_structureBelow">to in the tree structure below</localize>
</p>
<div class="umb-loader-wrapper" ng-show="busy">
<div class="umb-loader"></div>
</div>
<div ng-show="error">
<h5 class="text-error">{{error.errorMsg}}</h5>
<p class="text-error">{{error.data.message}}</p>
</div>
<div ng-show="success">
<h5 class="text-success">
<strong>{{currentNode.name}}</strong> <localize key="contentTypeEditor_copiedUnderneath">was copied underneath</localize>&nbsp;<strong>{{target.name}}</strong></h5>
<button class="btn btn-primary" ng-click="nav.hideDialog()">Ok</button>
</div>
<div ng-hide="success">
<div>
<umb-tree section="settings"
treealias="documentTypes"
customtreeparams="foldersonly=1"
hideheader="false"
hideoptions="true"
isdialog="true"
eventhandler="dialogTreeEventHandler"
enablecheckboxes="true">
</umb-tree>
</div>
</div>
</div>
</div>
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar" ng-hide="success">
<a class="btn btn-link" ng-click="nav.hideDialog()" ng-if="!busy">
<localize key="general_cancel">Cancel</localize>
</a>
<button class="btn btn-primary" ng-click="copy()" ng-disabled="busy">
<localize key="actions_copy">Copy</localize>
</button>
</div>
</div>
@@ -0,0 +1,63 @@
angular.module("umbraco")
.controller("Umbraco.Editors.MediaTypes.CopyController",
function ($scope, mediaTypeResource, treeService, navigationService, notificationsService, appState, eventsService) {
var dialogOptions = $scope.dialogOptions;
$scope.dialogTreeEventHandler = $({});
function nodeSelectHandler(ev, args) {
args.event.preventDefault();
args.event.stopPropagation();
if ($scope.target) {
//un-select if there's a current one selected
$scope.target.selected = false;
}
$scope.target = args.node;
$scope.target.selected = true;
}
$scope.copy = function () {
$scope.busy = true;
$scope.error = false;
mediaTypeResource.copy({ parentId: $scope.target.id, id: dialogOptions.currentNode.id })
.then(function (path) {
$scope.error = false;
$scope.success = true;
$scope.busy = false;
//get the currently edited node (if any)
var activeNode = appState.getTreeState("selectedNode");
//we need to do a double sync here: first sync to the copied content - but don't activate the node,
//then sync to the currenlty edited content (note: this might not be the content that was copied!!)
navigationService.syncTree({ tree: "mediaTypes", path: path, forceReload: true, activate: false }).then(function (args) {
if (activeNode) {
var activeNodePath = treeService.getPath(activeNode).join();
//sync to this node now - depending on what was copied this might already be synced but might not be
navigationService.syncTree({ tree: "mediaTypes", path: activeNodePath, forceReload: false, activate: true });
}
});
}, function (err) {
$scope.success = false;
$scope.error = err;
$scope.busy = false;
//show any notifications
if (angular.isArray(err.data.notifications)) {
for (var i = 0; i < err.data.notifications.length; i++) {
notificationsService.showNotification(err.data.notifications[i]);
}
}
});
};
$scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
$scope.$on('$destroy', function () {
$scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
});
});
@@ -0,0 +1,51 @@
<div class="umb-dialog umb-pane" ng-controller="Umbraco.Editors.MediaTypes.CopyController">
<div class="umb-dialog-body">
<div class="umb-pane">
<p class="abstract" ng-hide="success">
<localize key="contentTypeEditor_folderToCopy">Select the folder to copy</localize> <strong>{{currentNode.name}}</strong>&nbsp;<localize key="contentTypeEditor_structureBelow">to in the tree structure below</localize>
</p>
<div class="umb-loader-wrapper" ng-show="busy">
<div class="umb-loader"></div>
</div>
<div ng-show="error">
<h5 class="text-error">{{error.errorMsg}}</h5>
<p class="text-error">{{error.data.message}}</p>
</div>
<div ng-show="success">
<h5 class="text-success">
<strong>{{currentNode.name}}</strong> <localize key="contentTypeEditor_copiedUnderneath">was copied underneath</localize>&nbsp;<strong>{{target.name}}</strong></h5>
<button class="btn btn-primary" ng-click="nav.hideDialog()">Ok</button>
</div>
<div ng-hide="success">
<div>
<umb-tree section="settings"
treealias="mediaTypes"
customtreeparams="foldersonly=1"
hideheader="false"
hideoptions="true"
isdialog="true"
eventhandler="dialogTreeEventHandler"
enablecheckboxes="true">
</umb-tree>
</div>
</div>
</div>
</div>
<div class="umb-dialog-footer btn-toolbar umb-btn-toolbar" ng-hide="success">
<a class="btn btn-link" ng-click="nav.hideDialog()" ng-if="!busy">
<localize key="general_cancel">Cancel</localize>
</a>
<button class="btn btn-primary" ng-click="copy()" ng-disabled="busy">
<localize key="actions_copy">Copy</localize>
</button>
</div>
</div>
@@ -4,6 +4,11 @@ function booleanEditorController($scope, $rootScope, assetsService) {
$scope.renderModel = {
value: false
};
if ($scope.model.config && $scope.model.config.default && $scope.model.config.default.toString() === "1" && $scope.model && !$scope.model.value) {
$scope.renderModel.value = true;
}
if ($scope.model && $scope.model.value && ($scope.model.value.toString() === "1" || angular.lowercase($scope.model.value) === "true")) {
$scope.renderModel.value = true;
}
@@ -14,7 +19,7 @@ function booleanEditorController($scope, $rootScope, assetsService) {
$scope.$watch("renderModel.value", function (newVal) {
$scope.model.value = newVal === true ? "1" : "0";
});
//here we declare a special method which will be called whenever the value has changed from the server
//this is instead of doing a watch on the model.value = faster
$scope.model.onValueChanged = function (newVal, oldVal) {
@@ -23,4 +28,4 @@ function booleanEditorController($scope, $rootScope, assetsService) {
};
}
angular.module("umbraco").controller("Umbraco.PropertyEditors.BooleanController", booleanEditorController);
angular.module("umbraco").controller("Umbraco.PropertyEditors.BooleanController", booleanEditorController);
@@ -5,6 +5,7 @@ angular.module('umbraco')
function ($rootScope, $routeParams, $scope, $log, mediaHelper, cropperHelper, $timeout, editorState, umbRequestHelper, fileManager, angularHelper) {
var config = angular.copy($scope.model.config);
$scope.imageIsLoaded = false;
//move previously saved value to the editor
if ($scope.model.value) {
@@ -71,6 +72,10 @@ angular.module('umbraco')
}
};
$scope.imageLoaded = function() {
$scope.imageIsLoaded = true;
};
//on image selected, update the cropper
$scope.$on("filesSelected", function (ev, args) {
$scope.model.value = config;
@@ -16,10 +16,10 @@
<div class="imagecropper clearfix">
<div ng-if="currentCrop" style="float:left;" class="clearfix">
<div style="position: relative; margin-bottom: 10px; width: 492px; border: 1px solid #f8f8f8;">
<div ng-if="currentCrop" style="float:left; max-width: 100%;" class="clearfix">
<div class="umb-cropper__container">
<i ng-click="done()" style="opacity: 0.5; position: absolute; top: 3px; right: 3px" class="icon icon-delete btn-round"></i>
<i ng-click="done()" class="icon icon-delete btn-round umb-close-cropper"></i>
<div>
<umb-image-crop height="{{currentCrop.height}}"
@@ -27,7 +27,8 @@
crop="currentCrop.coordinates"
center="model.value.focalPoint"
max-size="450"
src="imageSrc" />
src="imageSrc">
</umb-image-crop>
</div>
<a href style="margin:auto; text-align: center; font-size: 11px;" class="btn btn-link red"
@@ -36,30 +37,36 @@
</a>
</div>
</div>
<div ng-if="!currentCrop" class="umb-cropper-imageholder clearfix">
<umb-image-gravity src="imageSrc"
center="model.value.focalPoint" />
<umb-image-gravity
src="imageSrc"
center="model.value.focalPoint"
on-image-loaded="imageLoaded">
</umb-image-gravity>
<a href class="btn btn-link btn-crop-delete" ng-show="imageIsLoaded" ng-click="clear()"><i class="icon-delete red"></i> <localize key="content_uploadClear">Remove file</localize></a>
</div>
<ul class="umb-sortable-thumbnails cropList clearfix" ng-class="{'many':model.value.crops.length >= 4}">
<li ng-repeat=" (key,value) in model.value.crops" ng-class="{'current':currentCrop.alias === value.alias}">
<a href title="{{value.alias}}: {{value.width}}px x {{value.height}}px" ng-click="crop(value)">
<umb-image-thumbnail center="model.value.focalPoint"
crop="value.coordinates"
src="imageSrc"
height="{{value.height}}"
width="{{value.width}}"
max-size="75"></umb-image-thumbnail>
<ul class="umb-sortable-thumbnails cropList clearfix">
<li ng-repeat=" (key,value) in model.value.crops" ng-class="{'current':currentCrop.alias === value.alias}" ng-click="crop(value)">
<umb-image-thumbnail center="model.value.focalPoint"
crop="value.coordinates"
src="imageSrc"
height="{{value.height}}"
width="{{value.width}}"
max-size="75">
</umb-image-thumbnail>
<div class="crop-information">
<span class="crop-name crop-text">{{value.alias}}</span>
<span class="crop-size crop-text">{{value.width}}px x {{value.height}}px</span>
</a>
</div>
</li>
</ul>
</div>
<a href class="btn btn-link btn-crop-delete" ng-click="clear()"><i class="icon-delete red"></i> <localize key="content_uploadClear">Remove file</localize></a>
</div>
</div>
</div>
@@ -1,4 +1,4 @@
function listViewController($rootScope, $scope, $routeParams, $injector, $cookieStore, notificationsService, iconHelper, dialogService, editorState, localizationService, $location, appState, $timeout, $q, mediaResource, listViewHelper) {
function listViewController($rootScope, $scope, $routeParams, $injector, $cookieStore, notificationsService, iconHelper, dialogService, editorState, localizationService, $location, appState, $timeout, $q, mediaResource, listViewHelper, userService) {
//this is a quick check to see if we're in create mode, if so just exit - we cannot show children for content
// that isn't created yet, if we continue this will use the parent id in the route params which isn't what
@@ -58,8 +58,66 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie
totalPages: 0,
items: []
};
//when this is null, we don't check permissions
$scope.buttonPermissions = null;
//When we are dealing with 'content', we need to deal with permissions on child nodes.
// Currently there is no real good way to
if ($scope.entityType === "content") {
var idsWithPermissions = null;
$scope.buttonPermissions = {
canCopy: true,
canCreate: true,
canDelete: true,
canMove: true,
canPublish: true,
canUnpublish: true
};
$scope.$watch(function() {
return $scope.selection.length;
}, function(newVal, oldVal) {
if ((idsWithPermissions == null && newVal > 0) || (idsWithPermissions != null)) {
//get all of the selected ids
var ids = _.map($scope.selection, function(i) {
return i.id.toString();
});
//remove the dictionary items that don't have matching ids
var filtered = {};
_.each(idsWithPermissions, function (value, key, list) {
if (_.contains(ids, key)) {
filtered[key] = value;
}
});
idsWithPermissions = filtered;
//find all ids that we haven't looked up permissions for
var existingIds = _.keys(idsWithPermissions);
var missingLookup = _.map(_.difference(ids, existingIds), function (i) {
return Number(i);
});
if (missingLookup.length > 0) {
contentResource.getPermissions(missingLookup).then(function(p) {
$scope.buttonPermissions = listViewHelper.getButtonPermissions(p, idsWithPermissions);
});
}
else {
$scope.buttonPermissions = listViewHelper.getButtonPermissions({}, idsWithPermissions);
}
}
});
}
$scope.options = {
displayAtTabNumber: $scope.model.config.displayAtTabNumber ? $scope.model.config.displayAtTabNumber : 1,
pageSize: $scope.model.config.pageSize ? $scope.model.config.pageSize : 10,
pageNumber: ($routeParams.page && Number($routeParams.page) != NaN && Number($routeParams.page) > 0) ? $routeParams.page : 1,
filter: '',
@@ -165,9 +223,8 @@ function listViewController($rootScope, $scope, $routeParams, $injector, $cookie
getListResultsCallback(id, $scope.options).then(function(data) {
$scope.actionInProgress = false;
$scope.listViewResultSet = data;
//update all values for display
if ($scope.listViewResultSet.items) {
_.each($scope.listViewResultSet.items, function(e, index) {
@@ -10,7 +10,7 @@
<umb-editor-sub-header-content-left>
<umb-editor-sub-header-section ng-if="listViewAllowedTypes && listViewAllowedTypes.length > 0 && !isAnythingSelected()">
<umb-editor-sub-header-section ng-if="(listViewAllowedTypes && listViewAllowedTypes.length > 0 && !isAnythingSelected()) && currentNodePermissions.canCreate">
<div class="btn-group">
<a class="btn dropdown-toggle" data-toggle="dropdown" href="#">
<localize key="actions_create">Create</localize>
@@ -82,7 +82,7 @@
<umb-editor-sub-header-section ng-if="isAnythingSelected()">
<umb-button
ng-if="options.allowBulkPublish"
ng-if="options.allowBulkPublish && (buttonPermissions == null || buttonPermissions.canPublish)"
type="button"
button-style="link"
label="Publish"
@@ -93,7 +93,7 @@
</umb-button>
<umb-button
ng-if="options.allowBulkUnpublish"
ng-if="options.allowBulkUnpublish && (buttonPermissions == null || buttonPermissions.canUnpublish)"
type="button"
button-style="link"
label="Unpublish"
@@ -104,7 +104,7 @@
</umb-button>
<umb-button
ng-if="options.allowBulkCopy"
ng-if="options.allowBulkCopy && (buttonPermissions == null || buttonPermissions.canCopy)"
type="button"
button-style="link"
label="Copy"
@@ -115,7 +115,7 @@
</umb-button>
<umb-button
ng-if="options.allowBulkMove"
ng-if="options.allowBulkMove && (buttonPermissions == null || buttonPermissions.canMove)"
type="button"
button-style="link"
label="Move"
@@ -126,7 +126,7 @@
</umb-button>
<umb-button
ng-if="options.allowBulkDelete"
ng-if="options.allowBulkDelete && (buttonPermissions == null || buttonPermissions.canDelete)"
type="button"
button-style="link"
label="Delete"
@@ -261,7 +261,7 @@ angular.module("umbraco")
};
});
//Create the embedded plugin
tinyMceService.createInsertEmbeddedMedia(editor, $scope, function() {
@@ -1,5 +1,5 @@
angular.module("umbraco").controller("Umbraco.PrevalueEditors.RteController",
function ($scope, $timeout, $log, tinyMceService, stylesheetResource) {
function ($scope, $timeout, $log, tinyMceService, stylesheetResource, assetsService) {
var cfg = tinyMceService.defaultPrevalues();
if($scope.model.value){
@@ -23,6 +23,14 @@ angular.module("umbraco").controller("Umbraco.PrevalueEditors.RteController",
tinyMceService.configuration().then(function(config){
$scope.tinyMceConfig = config;
// extend commands with properties for font-icon and if it is a custom command
$scope.tinyMceConfig.commands = _.map($scope.tinyMceConfig.commands, function (obj) {
var icon = getFontIcon(obj.frontEndCommand);
return angular.extend(obj, {
fontIcon: icon.name,
isCustom: icon.isCustom
});
});
});
stylesheetResource.getAll().then(function(stylesheets){
@@ -57,6 +65,43 @@ angular.module("umbraco").controller("Umbraco.PrevalueEditors.RteController",
$scope.model.value.stylesheets.splice(index, 1);
}
};
// map properties for specific commands
function getFontIcon(alias) {
var icon = { name: alias, isCustom: false };
switch (alias) {
case "codemirror":
icon.name = "code";
icon.isCustom = false;
break;
case "styleselect":
icon.name = "icon-list";
icon.isCustom = true;
break;
case "umbembeddialog":
icon.name = "icon-tv";
icon.isCustom = true;
break;
case "umbmediapicker":
icon.name = "icon-picture";
icon.isCustom = true;
break;
case "umbmacro":
icon.name = "icon-settings-alt";
icon.isCustom = true;
break;
case "umbmacro":
icon.name = "icon-settings-alt";
icon.isCustom = true;
break;
default:
icon.name = alias;
icon.isCustom = false;
}
return icon;
}
var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
@@ -65,9 +110,11 @@ angular.module("umbraco").controller("Umbraco.PrevalueEditors.RteController",
});
//when the scope is destroyed we need to unsubscribe
// when the scope is destroyed we need to unsubscribe
$scope.$on('$destroy', function () {
unsubscribe();
});
});
// load TinyMCE skin which contains css for font-icons
assetsService.loadCss("lib/tinymce/skins/umbraco/skin.min.css");
});
@@ -1,4 +1,4 @@
<div ng-controller="Umbraco.PrevalueEditors.RteController">
<div ng-controller="Umbraco.PrevalueEditors.RteController" class="rte-editor-preval">
<umb-control-group label="Toolbar" hide-label="false">
<div ng-repeat="cmd in tinyMceConfig.commands">
@@ -8,9 +8,10 @@
ng-model="cmd.selected"
ng-change="selectCommand(cmd)" />
<img ng-src="{{cmd.icon}}" />
<!--<img ng-src="{{cmd.icon}}" />-->
<i class="mce-ico" ng-class="(cmd.isCustom ? ' mce-i-custom ' : ' mce-i-') + cmd.fontIcon"></i>
{{cmd.frontEndCommand}}
{{cmd.name}}
</label>
</div>
</umb-control-group>
@@ -27,12 +28,12 @@
</div>
</umb-control-group>
<umb-control-group label="Dimensions" description="Width x Height">
<umb-control-group label="Dimensions" description="Width x Height">
<div class="vertical-align-items">
<input type="number" min="0" ng-model="model.value.dimensions.width" class="umb-editor-tiny" placeholder="Width" /> &times;
<input type="number" min="0" ng-model="model.value.dimensions.width" class="umb-editor-tiny" placeholder="Width" /> &times;
<input type="number" min="0" ng-model="model.value.dimensions.height" class="umb-editor-tiny" placeholder="Height" /> Pixels
</div>
</umb-control-group>
</div>
</umb-control-group>
<umb-control-group label="Maximum size for inserted images" description="0 to disable resizing">
<div class="vertical-align-items">
@@ -5,7 +5,8 @@ var app = angular.module('umbraco', [
'umbraco.services',
'umbraco.mocks',
'umbraco.security',
'ngCookies'
'ngCookies',
'LocalStorageModule'
]);
/* For Angular 1.2: we need to load in Routing separately
@@ -26,7 +26,7 @@ module.exports = function(karma) {
'lib/../build/belle/lib/underscore/underscore-min.js',
'lib/umbraco/Extensions.js',
'lib/../build/belle/lib/rgrove-lazyload/lazyload.js',
'lib/../build/belle/lib/angular-local-storage/angular-local-storage.min.js',
'test/config/app.unit.js',
'src/common/mocks/umbraco.servervariables.js',
@@ -0,0 +1,48 @@
describe('list view helper tests', function () {
var $scope, listViewHelper;
beforeEach(module('LocalStorageModule'));
beforeEach(module('umbraco.services'));
beforeEach(inject(function ($injector) {
$scope = $injector.get('$rootScope');
listViewHelper = $injector.get('listViewHelper');
}));
describe('getButtonPermissions', function () {
it('should update the currentIdsWithPermissions dictionary', function () {
var currentIdsWithPermissions = {};
var result = listViewHelper.getButtonPermissions({ "1234": ["A", "B", "C"] }, currentIdsWithPermissions);
expect(_.has(currentIdsWithPermissions, "1234")).toBe(true);
expect(_.keys(currentIdsWithPermissions).length).toEqual(1);
});
it('returns button permissions', function () {
var currentIdsWithPermissions = {};
var result1 = listViewHelper.getButtonPermissions({ "1234": ["O", "C", "D", "M", "U"] }, currentIdsWithPermissions);
expect(result1["canCopy"]).toBe(true);
expect(result1["canCreate"]).toBe(true);
expect(result1["canDelete"]).toBe(true);
expect(result1["canMove"]).toBe(true);
expect(result1["canPublish"]).toBe(true);
expect(result1["canUnpublish"]).toBe(true);
var result2 = listViewHelper.getButtonPermissions({ "1234": ["A", "B"] }, currentIdsWithPermissions);
expect(result2["canCopy"]).toBe(false);
expect(result2["canCreate"]).toBe(false);
expect(result2["canDelete"]).toBe(false);
expect(result2["canMove"]).toBe(false);
expect(result2["canPublish"]).toBe(false);
expect(result2["canUnpublish"]).toBe(false);
});
});
});
@@ -7,9 +7,18 @@
'Failed to generate.')
.then(function (result) {
$scope.generating = false;
$scope.dashboard = result;
});
};
$scope.reload = function () {
$scope.ready = false;
modelsBuilderResource.getDashboard().then(function (result) {
$scope.dashboard = result;
$scope.ready = true;
});
};
function init() {
modelsBuilderResource.getDashboard().then(function(result) {
$scope.dashboard = result;
@@ -1,5 +1,9 @@
<div id="modelsBuilder" ng-controller="Umbraco.Dashboard.ModelsBuilderController">
<div ng-show="ready" style="float: right;">
<button type="button" class="btn" ng-click="reload()"><span>Reload</span></button>
</div>
<h3>Models Builder</h3>
<div ng-show="!ready">
@@ -10,7 +14,8 @@
<div ng-bind-html-unsafe="dashboard.text"></div>
<div ng-if="dashboard.outOfDateModels">
<p>Models are <strong>out-of-date</strong>.</p>
<p>Models are <strong>out-of-date</strong>.
</p>
</div>
<div ng-if="dashboard.canGenerate">
@@ -26,6 +31,11 @@
<div class="umb-loader"></div>
</div>
</div>
<div ng-if="dashboard.lastError" style="margin-top: 32px;" ng-show="!generating">
<span style="color: red; font-weight: bold;">Last generation failed with the following error:</span>
<pre style="width: 80%; white-space: pre-line; background: #f8f8f8; padding: 4px; font-size: small;">{{dashboard.lastError}}</pre>
</div>
</div>
</div>
+2 -7
View File
@@ -348,8 +348,8 @@
<Name>umbraco.providers</Name>
</ProjectReference>
<Reference Include="System.Xml.Linq" />
<Reference Include="Umbraco.ModelsBuilder, Version=3.0.0.90, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Umbraco.ModelsBuilder.3.0.0\lib\Umbraco.ModelsBuilder.dll</HintPath>
<Reference Include="Umbraco.ModelsBuilder, Version=3.0.1.92, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Umbraco.ModelsBuilder.3.0.1\lib\Umbraco.ModelsBuilder.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="UrlRewritingNet.UrlRewriter, Version=2.0.7.0, Culture=neutral, processorArchitecture=MSIL">
@@ -2014,14 +2014,9 @@
<Content Include="Umbraco\Translation\default.aspx" />
<Content Include="Umbraco\Translation\preview.aspx" />
<Content Include="Umbraco\Translation\xml.aspx" />
<Content Include="Umbraco\Create\content.ascx" />
<Content Include="Umbraco\Create\language.ascx">
<SubType>UserControl</SubType>
</Content>
<Content Include="Umbraco\Create\member.ascx" />
<Content Include="Umbraco\Create\nodeType.ascx">
<SubType>UserControl</SubType>
</Content>
<Content Include="Umbraco\Create\simple.ascx" />
<Content Include="Umbraco\Create\xslt.ascx">
<SubType>UserControl</SubType>
@@ -2,221 +2,246 @@
<!-- Any changes to this file requires the application (umbraco) to restart -->
<!-- This can be done by touching the web.config or recycling the application pool -->
<tinymceConfig>
<commands>
<command>
<umbracoAlias>code</umbracoAlias>
<icon>images/editor/code.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="code">code</tinyMceCommand>
<priority>1</priority>
</command>
<command>
<commands>
<command>
<umbracoAlias>code</umbracoAlias>
<name>Code</name>
<icon>images/editor/code.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="code">code</tinyMceCommand>
<priority>1</priority>
</command>
<command>
<umbracoAlias>codemirror</umbracoAlias>
<name>Code mirror</name>
<icon>images/editor/code.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="codemirror">codemirror</tinyMceCommand>
<priority>1</priority>
</command>
<command>
<umbracoAlias>removeformat</umbracoAlias>
<icon>images/editor/removeformat.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="removeformat">removeformat</tinyMceCommand>
<priority>2</priority>
</command>
<command>
<umbracoAlias>Undo</umbracoAlias>
<icon>images/editor/undo.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="undo">undo</tinyMceCommand>
<priority>11</priority>
</command>
<command>
<umbracoAlias>Redo</umbracoAlias>
<icon>images/editor/redo.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="redo">redo</tinyMceCommand>
<priority>12</priority>
</command>
<command>
<umbracoAlias>Cut</umbracoAlias>
<icon>images/editor/cut.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="cut">cut</tinyMceCommand>
<priority>13</priority>
</command>
<command>
<umbracoAlias>Copy</umbracoAlias>
<icon>images/editor/copy.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="copy">copy</tinyMceCommand>
<priority>14</priority>
</command>
<command>
<umbracoAlias>styleselect</umbracoAlias>
<icon>images/editor/showStyles.png</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="styleselect">styleselect</tinyMceCommand>
<priority>20</priority>
</command>
<command>
<umbracoAlias>bold</umbracoAlias>
<icon>images/editor/bold.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="bold">bold</tinyMceCommand>
<priority>21</priority>
</command>
<command>
<umbracoAlias>italic</umbracoAlias>
<icon>images/editor/italic.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="italic">italic</tinyMceCommand>
<priority>22</priority>
</command>
<command>
<umbracoAlias>Underline</umbracoAlias>
<icon>images/editor/underline.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="underline">underline</tinyMceCommand>
<priority>23</priority>
</command>
<command>
<umbracoAlias>Strikethrough</umbracoAlias>
<icon>images/editor/strikethrough.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="strikethrough">strikethrough</tinyMceCommand>
<priority>24</priority>
</command>
<command>
<umbracoAlias>JustifyLeft</umbracoAlias>
<icon>images/editor/justifyleft.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="alignleft">justifyleft</tinyMceCommand>
<priority>31</priority>
</command>
<command>
<umbracoAlias>JustifyCenter</umbracoAlias>
<icon>images/editor/justifycenter.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="aligncenter">justifycenter</tinyMceCommand>
<priority>32</priority>
</command>
<command>
<umbracoAlias>JustifyRight</umbracoAlias>
<icon>images/editor/justifyright.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="alignright">justifyright</tinyMceCommand>
<priority>33</priority>
</command>
<command>
<umbracoAlias>JustifyFull</umbracoAlias>
<icon>images/editor/justifyfull.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="alignjustify">alignjustify</tinyMceCommand>
<priority>34</priority>
</command>
<command>
<umbracoAlias>bullist</umbracoAlias>
<icon>images/editor/bullist.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="bullist">bullist</tinyMceCommand>
<priority>41</priority>
</command>
<command>
<umbracoAlias>numlist</umbracoAlias>
<icon>images/editor/numlist.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="numlist">numlist</tinyMceCommand>
<priority>42</priority>
</command>
<command>
<umbracoAlias>Outdent</umbracoAlias>
<icon>images/editor/outdent.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="outdent">outdent</tinyMceCommand>
<priority>43</priority>
</command>
<command>
<umbracoAlias>Indent</umbracoAlias>
<icon>images/editor/indent.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="indent">indent</tinyMceCommand>
<priority>44</priority>
</command>
<command>
<umbracoAlias>mceLink</umbracoAlias>
<icon>images/editor/link.gif</icon>
<tinyMceCommand value="" userInterface="true" frontendCommand="link">link</tinyMceCommand>
<priority>51</priority>
</command>
<command>
<umbracoAlias>unlink</umbracoAlias>
<icon>images/editor/unLink.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="unlink">unlink</tinyMceCommand>
<priority>52</priority>
</command>
<command>
<umbracoAlias>mceInsertAnchor</umbracoAlias>
<icon>images/editor/anchor.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="anchor">anchor</tinyMceCommand>
<priority>53</priority>
</command>
<command>
<umbracoAlias>mceImage</umbracoAlias>
<icon>images/editor/image.gif</icon>
<tinyMceCommand value="" userInterface="true" frontendCommand="umbmediapicker">image</tinyMceCommand>
<priority>61</priority>
</command>
<command>
<umbracoAlias>umbracomacro</umbracoAlias>
<icon>images/editor/insMacro.gif</icon>
<tinyMceCommand value="" userInterface="true" frontendCommand="umbmacro">umbracomacro</tinyMceCommand>
<priority>62</priority>
</command>
<command>
<umbracoAlias>mceInsertTable</umbracoAlias>
<icon>images/editor/table.gif</icon>
<tinyMceCommand value="" userInterface="true" frontendCommand="table">table</tinyMceCommand>
<priority>63</priority>
</command>
<command>
<umbracoAlias>umbracoembed</umbracoAlias>
<icon>images/editor/media.gif</icon>
<tinyMceCommand value="" userInterface="true" frontendCommand="umbembeddialog">umbracoembed</tinyMceCommand>
<priority>66</priority>
</command>
<command>
<umbracoAlias>inserthorizontalrule</umbracoAlias>
<icon>images/editor/hr.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="hr">hr</tinyMceCommand>
<priority>71</priority>
</command>
<command>
<umbracoAlias>subscript</umbracoAlias>
<icon>images/editor/sub.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="subscript">subscript</tinyMceCommand>
<priority>72</priority>
</command>
<command>
<umbracoAlias>superscript</umbracoAlias>
<icon>images/editor/sup.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="superscript">superscript</tinyMceCommand>
<priority>73</priority>
</command>
<command>
<umbracoAlias>mceCharMap</umbracoAlias>
<icon>images/editor/charmap.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="charmap">charmap</tinyMceCommand>
<priority>74</priority>
</command>
</commands>
<plugins>
<umbracoAlias>removeformat</umbracoAlias>
<name>Remove format</name>
<icon>images/editor/removeformat.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="removeformat">removeformat</tinyMceCommand>
<priority>2</priority>
</command>
<command>
<umbracoAlias>undo</umbracoAlias>
<name>Undo</name>
<name>Remove Format</name>
<icon>images/editor/undo.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="undo">undo</tinyMceCommand>
<priority>11</priority>
</command>
<command>
<umbracoAlias>redo</umbracoAlias>
<name>Redo</name>
<icon>images/editor/redo.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="redo">redo</tinyMceCommand>
<priority>12</priority>
</command>
<command>
<umbracoAlias>cut</umbracoAlias>
<name>Cut</name>
<icon>images/editor/cut.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="cut">cut</tinyMceCommand>
<priority>13</priority>
</command>
<command>
<umbracoAlias>copy</umbracoAlias>
<name>Copy</name>
<icon>images/editor/copy.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="copy">copy</tinyMceCommand>
<priority>14</priority>
</command>
<command>
<umbracoAlias>paste</umbracoAlias>
<name>Paste</name>
<icon>images/editor/paste.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="paste">paste</tinyMceCommand>
<priority>15</priority>
</command>
<command>
<umbracoAlias>styleselect</umbracoAlias>
<name>Style select</name>
<icon>images/editor/showStyles.png</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="styleselect">styleselect</tinyMceCommand>
<priority>20</priority>
</command>
<command>
<umbracoAlias>bold</umbracoAlias>
<name>Bold</name>
<icon>images/editor/bold.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="bold">bold</tinyMceCommand>
<priority>21</priority>
</command>
<command>
<umbracoAlias>italic</umbracoAlias>
<name>Italic</name>
<icon>images/editor/italic.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="italic">italic</tinyMceCommand>
<priority>22</priority>
</command>
<command>
<umbracoAlias>underline</umbracoAlias>
<name>Underline</name>
<icon>images/editor/underline.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="underline">underline</tinyMceCommand>
<priority>23</priority>
</command>
<command>
<umbracoAlias>strikethrough</umbracoAlias>
<name>Strikethrough</name>
<icon>images/editor/strikethrough.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="strikethrough">strikethrough</tinyMceCommand>
<priority>24</priority>
</command>
<command>
<umbracoAlias>justifyleft</umbracoAlias>
<name>Justify left</name>
<icon>images/editor/justifyleft.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="alignleft">justifyleft</tinyMceCommand>
<priority>31</priority>
</command>
<command>
<umbracoAlias>justifycenter</umbracoAlias>
<name>Justify center</name>
<icon>images/editor/justifycenter.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="aligncenter">justifycenter</tinyMceCommand>
<priority>32</priority>
</command>
<command>
<umbracoAlias>justifyright</umbracoAlias>
<name>Justify right</name>
<icon>images/editor/justifyright.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="alignright">justifyright</tinyMceCommand>
<priority>33</priority>
</command>
<command>
<umbracoAlias>justifyfull</umbracoAlias>
<name>Justify full</name>
<icon>images/editor/justifyfull.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="alignjustify">alignjustify</tinyMceCommand>
<priority>34</priority>
</command>
<command>
<umbracoAlias>bullist</umbracoAlias>
<name>Bullet list</name>
<icon>images/editor/bullist.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="bullist">bullist</tinyMceCommand>
<priority>41</priority>
</command>
<command>
<umbracoAlias>numlist</umbracoAlias>
<name>Numbered list</name>
<icon>images/editor/numlist.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="numlist">numlist</tinyMceCommand>
<priority>42</priority>
</command>
<command>
<umbracoAlias>outdent</umbracoAlias>
<name>Decrease indent</name>
<icon>images/editor/outdent.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="outdent">outdent</tinyMceCommand>
<priority>43</priority>
</command>
<command>
<umbracoAlias>indent</umbracoAlias>
<name>Increase indent</name>
<icon>images/editor/indent.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="indent">indent</tinyMceCommand>
<priority>44</priority>
</command>
<command>
<umbracoAlias>mceLink</umbracoAlias>
<name>Insert/edit link</name>
<icon>images/editor/link.gif</icon>
<tinyMceCommand value="" userInterface="true" frontendCommand="link">link</tinyMceCommand>
<priority>51</priority>
</command>
<command>
<umbracoAlias>unlink</umbracoAlias>
<name>Remove link</name>
<icon>images/editor/unLink.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="unlink">unlink</tinyMceCommand>
<priority>52</priority>
</command>
<command>
<umbracoAlias>mceInsertAnchor</umbracoAlias>
<name>Anchor</name>
<icon>images/editor/anchor.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="anchor">anchor</tinyMceCommand>
<priority>53</priority>
</command>
<command>
<umbracoAlias>mceImage</umbracoAlias>
<name>Image</name>
<icon>images/editor/image.gif</icon>
<tinyMceCommand value="" userInterface="true" frontendCommand="umbmediapicker">image</tinyMceCommand>
<priority>61</priority>
</command>
<command>
<umbracoAlias>umbracomacro</umbracoAlias>
<name>Macro</name>
<icon>images/editor/insMacro.gif</icon>
<tinyMceCommand value="" userInterface="true" frontendCommand="umbmacro">umbracomacro</tinyMceCommand>
<priority>62</priority>
</command>
<command>
<umbracoAlias>mceInsertTable</umbracoAlias>
<name>Table</name>
<icon>images/editor/table.gif</icon>
<tinyMceCommand value="" userInterface="true" frontendCommand="table">table</tinyMceCommand>
<priority>63</priority>
</command>
<command>
<umbracoAlias>umbracoembed</umbracoAlias>
<name>Embed</name>
<icon>images/editor/media.gif</icon>
<tinyMceCommand value="" userInterface="true" frontendCommand="umbembeddialog">umbracoembed</tinyMceCommand>
<priority>66</priority>
</command>
<command>
<umbracoAlias>inserthorizontalrule</umbracoAlias>
<name>Horizontal rule</name>
<icon>images/editor/hr.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="hr">hr</tinyMceCommand>
<priority>71</priority>
</command>
<command>
<umbracoAlias>subscript</umbracoAlias>
<name>Subscript</name>
<icon>images/editor/sub.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="subscript">subscript</tinyMceCommand>
<priority>72</priority>
</command>
<command>
<umbracoAlias>superscript</umbracoAlias>
<name>Superscript</name>
<icon>images/editor/sup.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="superscript">superscript</tinyMceCommand>
<priority>73</priority>
</command>
<command>
<umbracoAlias>mceCharMap</umbracoAlias>
<name>Character map</name>
<icon>images/editor/charmap.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="charmap">charmap</tinyMceCommand>
<priority>74</priority>
</command>
</commands>
<plugins>
<plugin loadOnFrontend="true">code</plugin>
<plugin loadOnFrontend="true">codemirror</plugin>
<plugin loadOnFrontend="true">paste</plugin>
<plugin loadOnFrontend="true">umbracolink</plugin>
<plugin loadOnFrontend="true">anchor</plugin>
<plugin loadOnFrontend="true">charmap</plugin>
<plugin loadOnFrontend="true">table</plugin>
<plugin loadOnFrontend="true">codemirror</plugin>
<plugin loadOnFrontend="true">paste</plugin>
<plugin loadOnFrontend="true">umbracolink</plugin>
<plugin loadOnFrontend="true">anchor</plugin>
<plugin loadOnFrontend="true">charmap</plugin>
<plugin loadOnFrontend="true">table</plugin>
<plugin loadOnFrontend="true">lists</plugin>
<plugin loadOnFrontend="true">hr</plugin>
</plugins>
<validElements>
<![CDATA[+a[id|style|rel|data-id|rev|charset|hreflang|dir|lang|tabindex|accesskey|type|name|href|target|title|class|onfocus|onblur|onclick|
<plugin loadOnFrontend="true">hr</plugin>
</plugins>
<validElements>
<![CDATA[+a[id|style|rel|data-id|rev|charset|hreflang|dir|lang|tabindex|accesskey|type|name|href|target|title|class|onfocus|onblur|onclick|
ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup],-strong/-b[class|style],-em/-i[class|style],
-strike[class|style],-u[class|style],#p[id|style|dir|class|align],-ol[class|reversed|start|style|type],-ul[class|style],-li[class|style],br[class],
img[id|dir|lang|longdesc|usemap|style|class|src|onmouseover|onmouseout|border|alt=|title|hspace|vspace|width|height|align|umbracoorgwidth|umbracoorgheight|onresize|onresizestart|onresizeend|rel|data-id],
@@ -228,24 +253,24 @@ thead[id|class],tfoot[id|class],#td[id|lang|dir|class|colspan|rowspan|width|heig
-h3[id|dir|class|align|style],-h4[id|dir|class|align|style],-h5[id|dir|class|align|style],-h6[id|style|dir|class|align|style],hr[class|style],
dd[id|class|title|style|dir|lang],dl[id|class|title|style|dir|lang],dt[id|class|title|style|dir|lang],object[class|id|width|height|codebase|*],
param[name|value|_value|class],embed[type|width|height|src|class|*],map[name|class],area[shape|coords|href|alt|target|class],bdo[class],button[class],iframe[*]]]>
</validElements>
<invalidElements>font</invalidElements>
</validElements>
<invalidElements>font</invalidElements>
<!-- this area is for custom config settings that should be added during TinyMCE initialization -->
<customConfig>
<!-- <config key="myKey">mySetting</config>-->
<config key="entity_encoding">raw</config>
<config key="codemirror">
{
"indentOnInit": false,
"path": "../../../../lib/codemirror",
"config": {
},
"jsFiles": [
],
"cssFiles": [
]
}
</config>
</customConfig>
<!-- this area is for custom config settings that should be added during TinyMCE initialization -->
<customConfig>
<!-- <config key="myKey">mySetting</config>-->
<config key="entity_encoding">raw</config>
<config key="codemirror">
{
"indentOnInit": false,
"path": "../../../../lib/codemirror",
"config": {
},
"jsFiles": [
],
"cssFiles": [
]
}
</config>
</customConfig>
</tinymceConfig>
+51 -27
View File
@@ -5,204 +5,228 @@
<commands>
<command>
<umbracoAlias>code</umbracoAlias>
<name>Code</name>
<icon>images/editor/code.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="code">code</tinyMceCommand>
<priority>1</priority>
</command>
<command>
<umbracoAlias>codemirror</umbracoAlias>
<name>Code mirror</name>
<icon>images/editor/code.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="codemirror">codemirror</tinyMceCommand>
<priority>1</priority>
</command>
<command>
<umbracoAlias>removeformat</umbracoAlias>
<name>Remove format</name>
<icon>images/editor/removeformat.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="removeformat">removeformat</tinyMceCommand>
<priority>2</priority>
</command>
<command>
<umbracoAlias>Undo</umbracoAlias>
<umbracoAlias>undo</umbracoAlias>
<name>Undo</name>
<icon>images/editor/undo.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="undo">undo</tinyMceCommand>
<priority>11</priority>
</command>
<command>
<umbracoAlias>Redo</umbracoAlias>
<umbracoAlias>redo</umbracoAlias>
<name>Redo</name>
<icon>images/editor/redo.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="redo">redo</tinyMceCommand>
<priority>12</priority>
</command>
<command>
<umbracoAlias>Cut</umbracoAlias>
<umbracoAlias>cut</umbracoAlias>
<name>Cut</name>
<icon>images/editor/cut.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="cut">cut</tinyMceCommand>
<priority>13</priority>
</command>
<command>
<umbracoAlias>Copy</umbracoAlias>
<umbracoAlias>copy</umbracoAlias>
<name>Copy</name>
<icon>images/editor/copy.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="copy">copy</tinyMceCommand>
<priority>14</priority>
</command>
<command>
<umbracoAlias>paste</umbracoAlias>
<name>Paste</name>
<icon>images/editor/paste.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="paste">paste</tinyMceCommand>
<priority>15</priority>
</command>
<command>
<umbracoAlias>styleselect</umbracoAlias>
<name>Style select</name>
<icon>images/editor/showStyles.png</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="styleselect">styleselect</tinyMceCommand>
<priority>20</priority>
</command>
<command>
<umbracoAlias>bold</umbracoAlias>
<name>Bold</name>
<icon>images/editor/bold.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="bold">bold</tinyMceCommand>
<priority>21</priority>
</command>
<command>
<umbracoAlias>italic</umbracoAlias>
<name>Italic</name>
<icon>images/editor/italic.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="italic">italic</tinyMceCommand>
<priority>22</priority>
</command>
<command>
<umbracoAlias>Underline</umbracoAlias>
<umbracoAlias>underline</umbracoAlias>
<name>Underline</name>
<icon>images/editor/underline.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="underline">underline</tinyMceCommand>
<priority>23</priority>
</command>
<command>
<umbracoAlias>Strikethrough</umbracoAlias>
<umbracoAlias>strikethrough</umbracoAlias>
<name>Strikethrough</name>
<icon>images/editor/strikethrough.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="strikethrough">strikethrough</tinyMceCommand>
<priority>24</priority>
</command>
<command>
<umbracoAlias>JustifyLeft</umbracoAlias>
<umbracoAlias>justifyleft</umbracoAlias>
<name>Justify left</name>
<icon>images/editor/justifyleft.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="alignleft">justifyleft</tinyMceCommand>
<priority>31</priority>
</command>
<command>
<umbracoAlias>JustifyCenter</umbracoAlias>
<umbracoAlias>justifycenter</umbracoAlias>
<name>Justify center</name>
<icon>images/editor/justifycenter.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="aligncenter">justifycenter</tinyMceCommand>
<priority>32</priority>
</command>
<command>
<umbracoAlias>JustifyRight</umbracoAlias>
<umbracoAlias>justifyright</umbracoAlias>
<name>Justify right</name>
<icon>images/editor/justifyright.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="alignright">justifyright</tinyMceCommand>
<priority>33</priority>
</command>
<command>
<umbracoAlias>JustifyFull</umbracoAlias>
<umbracoAlias>justifyfull</umbracoAlias>
<name>Justify full</name>
<icon>images/editor/justifyfull.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="alignjustify">alignjustify</tinyMceCommand>
<priority>34</priority>
</command>
<command>
<umbracoAlias>bullist</umbracoAlias>
<name>Bullet list</name>
<icon>images/editor/bullist.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="bullist">bullist</tinyMceCommand>
<priority>41</priority>
</command>
<command>
<umbracoAlias>numlist</umbracoAlias>
<name>Numbered list</name>
<icon>images/editor/numlist.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="numlist">numlist</tinyMceCommand>
<priority>42</priority>
</command>
<command>
<umbracoAlias>Outdent</umbracoAlias>
<umbracoAlias>outdent</umbracoAlias>
<name>Decrease indent</name>
<icon>images/editor/outdent.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="outdent">outdent</tinyMceCommand>
<priority>43</priority>
</command>
<command>
<umbracoAlias>Indent</umbracoAlias>
<umbracoAlias>indent</umbracoAlias>
<name>Increase indent</name>
<icon>images/editor/indent.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="indent">indent</tinyMceCommand>
<priority>44</priority>
</command>
<command>
<umbracoAlias>mceLink</umbracoAlias>
<name>Insert/edit link</name>
<icon>images/editor/link.gif</icon>
<tinyMceCommand value="" userInterface="true" frontendCommand="link">link</tinyMceCommand>
<priority>51</priority>
</command>
<command>
<umbracoAlias>unlink</umbracoAlias>
<name>Remove link</name>
<icon>images/editor/unLink.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="unlink">unlink</tinyMceCommand>
<priority>52</priority>
</command>
<command>
<umbracoAlias>mceInsertAnchor</umbracoAlias>
<name>Anchor</name>
<icon>images/editor/anchor.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="anchor">anchor</tinyMceCommand>
<priority>53</priority>
</command>
<command>
<umbracoAlias>mceImage</umbracoAlias>
<name>Image</name>
<icon>images/editor/image.gif</icon>
<tinyMceCommand value="" userInterface="true" frontendCommand="umbmediapicker">image</tinyMceCommand>
<priority>61</priority>
</command>
<command>
<umbracoAlias>umbracomacro</umbracoAlias>
<name>Macro</name>
<icon>images/editor/insMacro.gif</icon>
<tinyMceCommand value="" userInterface="true" frontendCommand="umbmacro">umbracomacro</tinyMceCommand>
<priority>62</priority>
</command>
<command>
<umbracoAlias>mceInsertTable</umbracoAlias>
<name>Table</name>
<icon>images/editor/table.gif</icon>
<tinyMceCommand value="" userInterface="true" frontendCommand="table">table</tinyMceCommand>
<priority>63</priority>
</command>
<command>
<umbracoAlias>umbracoembed</umbracoAlias>
<name>Embed</name>
<icon>images/editor/media.gif</icon>
<tinyMceCommand value="" userInterface="true" frontendCommand="umbembeddialog">umbracoembed</tinyMceCommand>
<priority>66</priority>
</command>
<command>
<umbracoAlias>inserthorizontalrule</umbracoAlias>
<name>Horizontal rule</name>
<icon>images/editor/hr.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="hr">hr</tinyMceCommand>
<priority>71</priority>
</command>
<command>
<umbracoAlias>subscript</umbracoAlias>
<name>Subscript</name>
<icon>images/editor/sub.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="subscript">subscript</tinyMceCommand>
<priority>72</priority>
</command>
<command>
<umbracoAlias>superscript</umbracoAlias>
<name>Superscript</name>
<icon>images/editor/sup.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="superscript">superscript</tinyMceCommand>
<priority>73</priority>
</command>
<command>
<umbracoAlias>mceCharMap</umbracoAlias>
<name>Character map</name>
<icon>images/editor/charmap.gif</icon>
<tinyMceCommand value="" userInterface="false" frontendCommand="charmap">charmap</tinyMceCommand>
<priority>74</priority>
</command>
</commands>
<plugins>
<plugin loadOnFrontend="true">code</plugin>
@@ -247,4 +271,4 @@ param[name|value|_value|class],embed[type|width|height|src|class|*],map[name|cla
}
</config>
</customConfig>
</tinymceConfig>
</tinymceConfig>
+1 -1
View File
@@ -35,6 +35,6 @@
<package id="SqlServerCE" version="4.0.0.1" targetFramework="net45" />
<package id="System.Collections.Immutable" version="1.1.36" targetFramework="net45" />
<package id="System.Reflection.Metadata" version="1.0.21" targetFramework="net45" />
<package id="Umbraco.ModelsBuilder" version="3.0.0" targetFramework="net45" />
<package id="Umbraco.ModelsBuilder" version="3.0.1" targetFramework="net45" />
<package id="UrlRewritingNet.UrlRewriter" version="2.0.7" targetFramework="net45" />
</packages>
@@ -265,6 +265,7 @@
<key alias="selectContent">Select content</key>
<key alias="selectMember">Select member</key>
<key alias="selectMemberGroup">Select member group</key>
<key alias="noIconsFound">No icons were found</key>
<key alias="noMacroParams">There are no parameters for this macro</key>
@@ -1054,7 +1055,9 @@ To manage your website, simply open the Umbraco back office and start adding con
<key alias="yesDelete">Yes, delete</key>
<key alias="movedUnderneath">was moved underneath</key>
<key alias="copiedUnderneath">was copied underneath</key>
<key alias="folderToMove">Select the folder to move</key>
<key alias="folderToCopy">Select the folder to copy</key>
<key alias="structureBelow">to in the tree structure below</key>
<key alias="allDocumentTypes">All Document types</key>
@@ -1051,7 +1051,9 @@ To manage your website, simply open the Umbraco back office and start adding con
<key alias="yesDelete">Yes, delete</key>
<key alias="movedUnderneath">was moved underneath</key>
<key alias="copiedUnderneath">was copied underneath</key>
<key alias="folderToMove">Select the folder to move</key>
<key alias="folderToCopy">Select the folder to copy</key>
<key alias="structureBelow">to in the tree structure below</key>
<key alias="allDocumentTypes">All Document types</key>
@@ -1,27 +0,0 @@
<%@ Control Language="c#" AutoEventWireup="True" Codebehind="content.ascx.cs" Inherits="umbraco.cms.presentation.create.controls.content" TargetSchema="http://schemas.microsoft.com/intellisense/ie5" %>
<asp:literal id="typeJs" runat="server"/>
<div><%=umbraco.ui.Text("name")%>:<br /></div>
<asp:TextBox id="rename" Runat="server" CssClass="bigInput"></asp:TextBox><br /><br />
<asp:RequiredFieldValidator id="RequiredFieldValidator1" ErrorMessage="*" ControlToValidate="rename" runat="server">*</asp:RequiredFieldValidator>
<span style="margin-left: -7px;"><%=umbraco.ui.Text("choose")%> <%=umbraco.ui.Text("documentType")%>:<br /></span>
<asp:ListBox id="nodeType" Runat="server" cssClass="bigInput" Rows="1" SelectionMode="Single"></asp:ListBox>
<asp:RequiredFieldValidator id="RequiredFieldValidator2" ErrorMessage="*" ControlToValidate="nodeType" runat="server">*</asp:RequiredFieldValidator>
<br />
<!-- added to support missing postback on enter in IE -->
<asp:TextBox runat="server" style="visibility:hidden;display:none;" ID="Textbox1"/>
<div id="typeDescription" class="createDescription">
<asp:Literal ID="descr" runat="server"></asp:Literal>
</div>
<div style="margin-right: 15px;">
<asp:Button id="sbmt" Runat="server" style="Width: 90px; margin-right: 6px;" onclick="sbmt_Click"></asp:Button>
<em> <%= umbraco.ui.Text("or") %> </em>
<a href="#" style="color: Blue; margin-left: 6px;" onclick="UmbClientMgr.closeModalWindow()"><%=umbraco.ui.Text("cancel")%></a>
<!--
<input type="button" value="" onClick="if (confirm('<%=umbraco.ui.Text("areyousure")%>')) window.close()" style="width: 90px; margin-left: 6px;"/>
-->
</div>
@@ -1,48 +0,0 @@
<%@ Control Language="c#" AutoEventWireup="True" CodeBehind="member.ascx.cs" Inherits="umbraco.cms.presentation.create.controls.member"
TargetSchema="http://schemas.microsoft.com/intellisense/ie5" %>
<asp:ValidationSummary runat="server" DisplayMode="BulletList" ID="validationSummary"
CssClass="error"></asp:ValidationSummary>
<asp:Literal ID="nameLiteral" runat="server"></asp:Literal>:<asp:RequiredFieldValidator
ID="nameRequired" ErrorMessage="*" ControlToValidate="rename" runat="server">*</asp:RequiredFieldValidator>
<br />
<asp:TextBox ID="rename" runat="server" Width="350px" CssClass="bigInput"></asp:TextBox>
<asp:Panel ID="memberChooser" runat="server">
<%=umbraco.ui.Text("choose")%>
<%=umbraco.ui.Text("membertype")%>:<asp:RequiredFieldValidator ID="memberTypeRequired" ErrorMessage="*" ControlToValidate="nodeType"
runat="server">*</asp:RequiredFieldValidator><br />
<asp:ListBox ID="nodeType" runat="server" Width="350px" CssClass="bigInput" Rows="1"
SelectionMode="Single"></asp:ListBox>
</asp:Panel>
<p>
Login Name:<asp:RequiredFieldValidator ID="loginRequired" ErrorMessage="*" ControlToValidate="Login"
runat="server">*</asp:RequiredFieldValidator>
<asp:CustomValidator ID="loginExistsCheck" runat="server" ErrorMessage="*" ControlToValidate="Login" ValidateEmptyText="false" OnServerValidate="LoginExistsCheck"></asp:CustomValidator>
<br />
<asp:TextBox ID="Login" runat="server" Width="350px" CssClass="bigInput"></asp:TextBox><br />
</p>
<p>
E-mail:
<asp:RequiredFieldValidator ID="emailRequired" ErrorMessage="*" ControlToValidate="Email"
runat="server">*</asp:RequiredFieldValidator>
<asp:CustomValidator ID="emailExistsCheck" runat="server" ErrorMessage="*" ControlToValidate="Email" ValidateEmptyText="false" OnServerValidate="EmailExistsCheck"></asp:CustomValidator>
<asp:CustomValidator runat="server" ID="EmailValidator" OnServerValidate="EmailValidator_OnServerValidate"
ControlToValidate="Email"
ErrorMessage="Invalid email address"
Display="None"/>
<br />
<asp:TextBox ID="Email" runat="server" Width="350px" CssClass="bigInput"></asp:TextBox><br />
</p>
<p>
Password: <em>
<asp:Literal runat="server" ID="PasswordRules"></asp:Literal></em><asp:RequiredFieldValidator
ID="passwordRequired" ControlToValidate="Password" runat="server">*</asp:RequiredFieldValidator><br />
<asp:TextBox ID="Password" runat="server" Width="350px" CssClass="bigInput"></asp:TextBox><br />
</p>
<!-- added to support missing postback on enter in IE -->
<asp:TextBox runat="server" Style="visibility: hidden; display: none;" ID="Textbox1" />
<div style="padding-top: 15px;">
<asp:Button ID="sbmt" runat="server" Style="margin-top: 14px" Width="90" OnClick="sbmt_Click">
</asp:Button>
&nbsp; <em>
<%= umbraco.ui.Text("or") %></em> &nbsp;<a href="#" style="color: blue" onclick="UmbClientMgr.closeModalWindow()"><%=umbraco.ui.Text("cancel")%></a>
</div>
@@ -1,32 +0,0 @@
<%@ Control Language="c#" AutoEventWireup="True" Codebehind="nodeType.ascx.cs" Inherits="umbraco.cms.presentation.create.controls.nodeType" TargetSchema="http://schemas.microsoft.com/intellisense/ie5"%>
<%@ Register TagPrefix="cc1" Namespace="umbraco.uicontrols" Assembly="controls" %>
<cc1:Pane runat="server">
<cc1:PropertyPanel runat="server" id="pp_name" text="Name">
<asp:TextBox id="rename" Runat="server" CssClass="bigInput input-large-type input-block-level"></asp:TextBox>
<asp:RequiredFieldValidator id="RequiredFieldValidator1" ErrorMessage="*" ControlToValidate="rename" runat="server">*</asp:RequiredFieldValidator>
</cc1:PropertyPanel>
<cc1:PropertyPanel runat="server" text="Master Document Type" ID="pp_MasterDocumentType">
<asp:ListBox id="masterType" Runat="server" cssClass="bigInput input-large-type input-block-level" Rows="1" SelectionMode="Single"></asp:ListBox>
<asp:Literal ID="masterTypePreDefined" runat="server" Visible="false"></asp:Literal>
</cc1:PropertyPanel>
<cc1:PropertyPanel runat="server">
<asp:CheckBox ID="createTemplate" Runat="server" Checked="true" Text="Create matching template"></asp:CheckBox>
</cc1:PropertyPanel>
<asp:TextBox runat="server" style="visibility:hidden;display:none;" ID="Textbox1"/>
<asp:CustomValidator ID="CustomValidation1" ErrorMessage="* A document type with this name/alias already exists" OnServerValidate="validationDoctypeName" ControlToValidate="rename" ForeColor="red" runat="server" />
<asp:CustomValidator ID="CustomValidation2" ErrorMessage="<br/>* The name of the document type will result in an invalid alias" OnServerValidate="validationDoctypeAlias" ControlToValidate="rename" ForeColor="red" runat="server" />
</cc1:Pane>
<cc1:Pane runat="server" CssClass="btn-toolbar umb-btn-toolbar">
<a href="#" class="btn btn-link" onclick="UmbClientMgr.closeModalWindow()"><%=umbraco.ui.Text("cancel")%></a>
<asp:Button id="sbmt" Runat="server" CssClass="btn btn-primary" onclick="sbmt_Click"></asp:Button>
</cc1:Pane>

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