Compare commits

...

393 Commits

Author SHA1 Message Date
Stephan 5dbc95a604 Fix StandaloneTests 2019-05-16 14:48:04 +02:00
Bjarke Berg 206f47bf52 Added missing nuget dependencies to the nuspec-file of UmbracoCms.Core 2019-05-16 14:24:09 +02:00
Niels Lyngsø 9fac00d91b Fixed documentation mistake 2019-05-16 10:50:24 +02:00
Niels Lyngsø 4456a202e4 Merge remote-tracking branch 'origin/pr_5448' into v8/dev 2019-05-16 10:36:57 +02:00
Niels Lyngsø b503becaf3 Only show if we do have pasteable items. 2019-05-16 10:27:00 +02:00
Sebastiaan Janssen 1090d54763 Update to the latest caniuse-lite to fix the build
Fixes #5455
2019-05-14 13:32:28 +02:00
Kenn Jacobsen d9027e04f3 Hide "Create new" header in Nested Content create item dialog if all items are filtered out 2019-05-10 21:58:55 +02:00
Shannon Deminick a43359e440 Merge pull request #5272 from umbraco/v8/spike/api-docs
Regenerating API docs
2019-05-10 13:53:37 +10:00
Shannon 8fce680430 removes unused line, updates gitignore 2019-05-10 13:07:06 +10:00
Warren Buckley 1815112ae7 Merge pull request #5353 from umbraco/v8/feature/ux-copy-paste-service-for-nested-content
V8: ClipboardService + implementation for nested content
2019-05-09 15:42:30 +01:00
Niels Lyngsø 66d12ddab2 fix spelling 2019-05-09 15:30:07 +02:00
Niels Lyngsø 2a592bfe8c remove comments 2019-05-09 15:30:01 +02:00
Shannon Deminick 3bf5160895 Merge pull request #5412 from umbraco/v8/bugfix/5131-remember-focus-for-search
Remember focus from before search opened + unbind shortcuts when backdrop is open
2019-05-09 23:08:41 +10:00
Niels Lyngsø 041fdc40e7 using localStorageService + applied further documentation 2019-05-09 15:02:22 +02:00
Niels Lyngsø 9c599868cc documentation for truncate fitler + only space between dots and words in wordwise mode. 2019-05-09 14:38:13 +02:00
Warren Buckley ac52960938 Merge pull request #5389 from umbraco/v8/feature/ui-improve-focus-state-of-umb-form-check
V8 improved focus state of umb-form-check inputs
2019-05-09 10:39:29 +01:00
Warren Buckley 3995c7c521 Merge pull request #5226 from umbraco/v8/bugfix/ui-sharpen-look-of-umb-tags
Accessibility and UI update of umb-tags
2019-05-09 10:13:49 +01:00
Niels Lyngsø b952156027 corrected documentation 2019-05-08 15:10:46 +02:00
Niels Lyngsø 4c23d7fec9 removed properties, replaced with a getter method. 2019-05-08 15:09:01 +02:00
elitsa 3d80d511a4 Adding a parameter for enabling docfx into the script. 2019-05-08 14:27:44 +02:00
elitsa fc0f996500 Excluding no longer needed paths. 2019-05-08 12:11:06 +02:00
Rasmus John Pedersen 16b88ca2ff Merge pull request #5419 from kjac/v8-fix-convert-media-urls-migration
V8: Fix duplicate alias exception in "convert media URLs" migration
2019-05-08 11:06:29 +02:00
Rasmus John Pedersen 6cf82669fb Update media urls migration to only fetch/update needed fields from db 2019-05-08 10:52:05 +02:00
Kenn Jacobsen 6baea68a7d Fix duplicate alias exception in "convert media URLs" migration 2019-05-08 07:53:11 +02:00
Niels Lyngsø e906808a9b unbind keyboard shortcuts for editors when backdrop is active 2019-05-07 10:59:09 +02:00
Niels Lyngsø c4dbb90d10 remember focus from before opening search 2019-05-07 10:46:52 +02:00
Shannon ef24c2e2f2 Fixes a migration syntax 2019-05-07 18:33:15 +10:00
Niels Lyngsø 4b55f99493 rename copy.service to clipboard.service 2019-05-07 09:08:32 +02:00
Shannon Deminick 3332e93d4c Merge pull request #5375 from umbraco/v8/feature/5373-make-async-file-logging-possible-with-serilog
V8: Make async file logging possible with serilog
2019-05-07 17:06:01 +10:00
Shannon Deminick ed88ce8ae2 Merge pull request #5209 from umbraco/v8/feature/4940-save-media-reference-instead-of-media-url
Save media reference instead of media url
2019-05-07 16:33:30 +10:00
Bjarke Berg 96cd42b316 #5373 - Removed configuration options that we don't want to support. The other options can be archived using the original file sink. 2019-05-07 08:25:43 +02:00
Shannon 2e7aa11211 Adds TODO, removes the data-udi or data-id attribute from inserted links 2019-05-07 15:47:40 +10:00
Niels Lyngsø 4c1129e944 added missing documentation 2019-05-06 14:30:23 +02:00
Niels Lyngsø 74cbff5ee5 minor rename 2019-05-06 14:27:15 +02:00
Niels Lyngsø bfdeb6c987 requires alias to be parsed in copy method + minor renaming 2019-05-06 14:23:25 +02:00
Niels Lyngsø 07f4295810 rename copyService to clipboardService 2019-05-06 14:18:15 +02:00
Shannon Deminick 74be040298 Merge pull request #5390 from umbraco/v8/bugfix/ui-2fa-login-view
Add back the ability to use a custom 2-factor auth screen
2019-05-06 16:23:18 +10:00
Sebastiaan Janssen c03a4d978b Use int.MinValue instead of calculating from SuperUserId 2019-05-06 08:22:03 +02:00
Shannon 64eff0ba0f adds serilog xdt file 2019-05-06 15:51:28 +10:00
Bjarke Berg f81fd8f35f #5373 - Handle the serilog fallback pattern in log viewer. The fallback pattern is that a "_NNN" is added to the file name before the file extension, if the file is locked when serilog needs to write to it. 2019-05-03 09:41:26 +02:00
Bjarke Berg 0222f929df #5373 - Changed the logging to be buffered 2019-05-03 08:39:01 +02:00
Shannon Deminick f34b2edb08 Merge pull request #5371 from umbraco/v8/bugfix/remove-old-doc
Removing a no longer relevant section
2019-05-03 13:16:28 +10:00
Sebastiaan Janssen e5839a89cd Fixes references to the "SuperUser" which used to have user Id 0, but now has userId -1 2019-05-02 14:56:12 +02:00
Sebastiaan Janssen 503d6d0265 Make the callback do something and cleanup code a little bit to limit it to only what we actually need 2019-05-02 14:44:33 +02:00
Bjarke Berg 6adec17b26 #5236 - Added options to set (and set default as) the log file is closed after each log event 2019-05-02 14:19:48 +02:00
Niels Lyngsø 3a5538730b only remove gray border when checked. 2019-05-02 13:32:16 +02:00
Niels Lyngsø fe3c1bc089 remove console.log 2019-05-02 13:25:19 +02:00
Niels Lyngsø 8031562ea2 better focus state 2019-05-02 10:54:59 +02:00
Sebastiaan Janssen 4881fb76e4 Merge pull request #5387 from umbraco/v8/bugfix/ui-umb-button-spacing
Added margin-left: 5px; to achieve the needed whitespace, couldn't figu…
2019-05-02 10:29:57 +02:00
Niels Lyngsø e9b06701cc Merge remote-tracking branch 'origin/v8/dev' into v8/feature/ux-copy-paste-service-for-nested-content 2019-05-02 10:10:48 +02:00
Niels Lyngsø 496d5d7791 added margin-left 5px; to achive the needed whitespace, could'nt figure out how it had been done before. 2019-05-02 10:01:16 +02:00
Marc Goodson b92fbffd7c Remove the Link to the out-of-date editors manual
Editors manual is for v7.1
2019-05-02 07:56:44 +02:00
Bjarke Berg 29b4da4dca #5373 - Disposes the logger on application end if disposable and implementes the CloseAndFlush in the dispose method of SerilogLogger 2019-05-01 15:50:43 +02:00
Elitsa Marinovska 6cd77df1ad Updating the base link 2019-05-01 15:30:58 +02:00
Elitsa Marinovska adf762bdf8 Integrate docs script with the main build script 2019-05-01 15:25:47 +02:00
Elitsa Marinovska 6b17248f64 Updating base link 2019-05-01 15:22:10 +02:00
Bjarke Berg a5684f867a #5373 - Added custom extension method to configure the file serilog file sink to be wrapped in the async sink 2019-05-01 15:15:29 +02:00
Niels Lyngsø e2730f2b66 use vm.login and vm.password, not parsing it. 2019-05-01 14:36:51 +02:00
Niels Lyngsø b4368666ca return to login-view on submit 2019-05-01 14:31:26 +02:00
Niels Lyngsø b60fe9cc0a use external view 2019-05-01 13:56:34 +02:00
Niels Lyngsø 3aabe424a8 example of 2fa login view 2019-05-01 13:44:18 +02:00
Elitsa Marinovska 9c667414bc Removing a no longer relevant section 2019-05-01 13:36:34 +02:00
Niels Lyngsø 5d5fa3fac8 changed localstorage key to umbCopyService 2019-05-01 10:14:33 +02:00
Niels Lyngsø d23f25beba finishing requestDeleteNode 2019-05-01 10:02:43 +02:00
Niels Lyngsø c0ad64d259 Merge remote-tracking branch 'origin/v8/dev' into v8/feature/ux-copy-paste-service-for-nested-content 2019-05-01 09:57:59 +02:00
Niels Lyngsø 6802716cf1 use requestDeleteNode 2019-05-01 09:57:11 +02:00
Niels Lyngsø 23a27c3519 adding paste feature + cleaning css 2019-05-01 09:40:38 +02:00
Rasmus John Pedersen 0e636b4ce1 Set href to # if url can't be resolved 2019-05-01 09:20:40 +02:00
Rasmus John Pedersen f00a230d12 Merge branch 'v8/dev' into v8/feature/4940-save-media-reference-instead-of-media-url 2019-05-01 08:55:55 +02:00
Shannon Deminick 009e373178 Merge pull request #5354 from umbraco/v8/feature/5350-fluent-type-collection
Make TypeCollectionBuilderBase fluent
2019-05-01 16:45:00 +10:00
Shannon Deminick 3c6d3280d8 Merge pull request #5266 from umbraco/v8/bugfix/5187-mapper-issue
Fix mapper concurrency issue
2019-05-01 15:25:54 +10:00
Callum Whyte 43d84a37a3 Pointing parent doctype links to correct edit pages in doctype builder
Links to parent doctype in doctype builder go to the wrong place
2019-04-30 22:20:30 +02:00
shane Prendergast 264958f097 #5277 Adding correct button element,styling to remove default styles 2019-04-30 22:18:59 +02:00
Kenn Jacobsen 99dedac375 Vertically center the button carets in the grid RTE 2019-04-30 22:17:29 +02:00
Kenn Jacobsen 078a7d5679 Fix the active state for nested content in nested content 2019-04-30 22:16:30 +02:00
Kenn Jacobsen 1df2cf5935 Fix info button icon color 2019-04-30 22:08:09 +02:00
Kenn Jacobsen 86c56ae844 Make sure to use the specified content template name when creating content templates from content 2019-04-30 22:05:00 +02:00
Sebastiaan Janssen 16322bed31 Merge pull request #4784 from kjac/v8-fix-content-template-mixed-variance
V8: Handle mixed variance when creating content templates from content
2019-04-30 22:04:21 +02:00
Sebastiaan Janssen 044decc0dc v8: Fix table cells collapsing when sorting doctypes in Nested Content (#4832) 2019-04-30 22:00:35 +02:00
Sebastiaan Janssen b9482fc867 Merge branch 'v8/dev' into pr_4832 2019-04-30 21:59:50 +02:00
Kenn Jacobsen 4d8e5e1416 Make sure to hide the member types when creating a new member 2019-04-30 21:56:00 +02:00
Samuel Butler 958c8b1214 Umbraco installer double-encodes connection string password fix (#4820) 2019-04-30 21:54:35 +02:00
Kenn Jacobsen d04b967fe6 V8: Hide "umbContent" app if the content has no properties (#4840) 2019-04-30 21:34:00 +02:00
Kenn Jacobsen 6bfcc7bb34 Don't "Create matching template" before the content type is created 2019-04-30 21:25:46 +02:00
Kenn Jacobsen 6274a08a4f Don't allow opening an uncreated template 2019-04-30 21:24:52 +02:00
Kenn Jacobsen 4ebfd8ca37 Remove accordion group behavior from media editing 2019-04-30 21:23:40 +02:00
Kenn Jacobsen 1370894b38 Remove accordion group behavior from member editing 2019-04-30 21:23:16 +02:00
Kenn Jacobsen c5f1d2d885 Use standard pickers in MNTP config 2019-04-30 21:22:14 +02:00
Kenn Jacobsen 4df63c7f04 V8: Save the slider default values on the model if no value is set (#4931) 2019-04-30 21:19:34 +02:00
Marc Goodson a822e18719 Patch/update published content request comments (#4945) 2019-04-30 21:13:59 +02:00
Matt Darby 1605b6f909 Adjust naming in Nested Content configuration to fit ElementType (#4946) 2019-04-30 21:08:49 +02:00
Kenn Jacobsen 5e8d73cd20 V8: Add tooltip/title to unselectable items in MNTP (#4964) 2019-04-30 20:57:28 +02:00
Bjarne Fyrstenborg f05915ef08 v8: Fix package download (#4968) 2019-04-30 20:47:37 +02:00
Bjarne Fyrstenborg 5fd423dbb6 Increase z-index of .umb-editor-footer so dropup is above grid editor hover overlay and doctype inherited label. 2019-04-30 20:45:30 +02:00
Kenn Jacobsen 1758d0cd1a Fix glitch in umb-checkbox background 2019-04-30 20:43:15 +02:00
Kenn Jacobsen d698aa56d0 Use umb-checkbox in the delete mediatype dialog 2019-04-30 20:41:07 +02:00
Kenn Jacobsen 0478a37b00 Use umb-checkbox in the delete datatype dialog 2019-04-30 20:40:20 +02:00
Kenn Jacobsen 6def4d6248 Use umb-checkbox in the delete membertype dialog 2019-04-30 20:39:38 +02:00
Kenn Jacobsen 2835da8e96 Use umb-checkbox for "open in new window" in the link picker 2019-04-30 20:37:45 +02:00
Sebastiaan Janssen f895900ec5 Merge branch 'v7/dev' into v8/dev
# Conflicts:
#	src/Umbraco.Web.UI.Client/src/common/services/tinymce.service.js
2019-04-30 20:36:45 +02:00
Kenn Jacobsen 21e91ac4e1 RTE: Don't assume "mailto:" protocol in links with "@" 2019-04-30 20:34:26 +02:00
Anders Bjerner ecc7a3b96e Added parameters to the docs for specifying an already selected icon 2019-04-30 20:31:47 +02:00
Kenn Jacobsen 9598d2c2e6 Make header name input look ok when disabled (reverts input height adjustment from ff8f9083) 2019-04-30 20:30:16 +02:00
Andy Butland 966bfafe22 Fixed casing of editorService open method inline documentation for the size parameter 2019-04-30 20:25:29 +02:00
Peter Duncanson f2a5e5da87 Added in new browser targets for Babel config
Fixes #4894
2019-04-30 20:24:20 +02:00
Kenn Jacobsen 5eb0f6f92f V8: Show info message if Nested Content is configured without content types (#5342) 2019-04-30 16:45:23 +02:00
Sebastiaan Janssen f2e01d8f65 Merge pull request #5343 from kjac/v8-fix-mntp-bounds-validation
V8: Fix the MNTP min/max items validation
2019-04-30 16:15:34 +02:00
Sebastiaan Janssen d328a53590 Merge pull request #5355 from kjac/v8-fix-media-library-open-file
V8: Make it possible to open/view files in the media library
2019-04-30 16:06:17 +02:00
Niels Lyngsø 27d5b258df truncate + cache header for create new + different title for overlay depending on situation 2019-04-30 15:53:38 +02:00
Niels Lyngsø b271c77d97 fixing size to only work for target overlay 2019-04-30 15:52:37 +02:00
Niels Lyngsø 906c7a4ccd added angularJS truncate filter 2019-04-30 15:52:00 +02:00
Niels Lyngsø 5942bce7da control size of umb-overlay 2019-04-30 15:23:56 +02:00
Niels Lyngsø ab2f0c3a1c go to four lines if more than 6 items in Item-picker 2019-04-30 15:00:52 +02:00
Niels Lyngsø 85905f7a77 fix variant error for collection tabs 2019-04-30 15:00:31 +02:00
Niels Lyngsø 85456bbb9b correct lang file 2019-04-30 14:59:34 +02:00
Niels Lyngsø 8e925c930b sort items by dragging the item header 2019-04-30 14:05:20 +02:00
Niels Lyngsø 18c7680baf remove unused CSS 2019-04-30 13:53:06 +02:00
Niels Lyngsø 77407a9446 correcting text 2019-04-30 13:39:17 +02:00
Niels Lyngsø 62e72a54b7 Merge commit 'a7ebf9bed3f78c68f5da8a67d27a8ffa0e961d3b' into v8/feature/ux-copy-paste-service-for-nested-content 2019-04-30 13:34:56 +02:00
Niels Lyngsø 5d7aa4bcf5 remove edit and paste button. 2019-04-30 13:34:35 +02:00
Niels Lyngsø 90912a4b2a restyled umb-overlay + added paste features in nested-content create-overlay 2019-04-30 12:49:37 +02:00
Niels Lyngsø 01116e21f4 finished copy service 2019-04-30 12:48:44 +02:00
Claus a7ebf9bed3 Merge pull request #5318 from umbraco/v8/bugfix/5075-rte-update-model
update RTE model on changing code or media
2019-04-30 10:31:35 +02:00
Claus a01efcb59f fix for vs2019 release build tools. 2019-04-29 13:59:16 +02:00
Elitsa Marinovska 880e86820e Updating with correct directory refferences 2019-04-28 21:15:59 +02:00
Elitsa Marinovska 7e064cee83 Optimizing scripts 2019-04-28 21:14:32 +02:00
Kenn Jacobsen cc7bf4cef5 Make it possible to open/view files in the media library 2019-04-27 22:28:00 +02:00
Stephan 70203512fb Make TypeCollectionBuilderBase fluent 2019-04-27 09:07:49 +02:00
Niels Lyngsø 48ceb0d41d working prototype 2019-04-26 15:15:27 +02:00
Stephan 173df80e3d Fix recycle bin moves 2019-04-26 15:01:16 +02:00
Bjarne Fyrstenborg 9b62269bde v8: Update image cropper slider (#4487) 2019-04-26 14:12:57 +02:00
Niels Lyngsø 4d3154c7fa prototype, not working correctly. 2019-04-26 13:34:38 +02:00
Niels Lyngsø e139fa6719 first version of copyService 2019-04-26 13:22:00 +02:00
Warren Buckley 09617d9b50 Merge pull request #5337 from umbraco/v8/feature/ui-prettier-focus-outlines
Created umb-outline to make it easy to apply pretty focus outline for elements.
2019-04-26 10:29:22 +01:00
Warren Buckley 00e33fb156 Merge pull request #5338 from umbraco/v8/feature/ui-app-header-action-focus-outline
V8: app header action focus outline
2019-04-26 10:26:14 +01:00
Warren Buckley dc27bd148a Merge pull request #5340 from umbraco/v8/feature/ux-disable-tabbing-state-with-a-mouse-click
Disable tabbing state if user clicks
2019-04-26 10:19:24 +01:00
Warren Buckley 6dc343f9d8 Merge pull request #5339 from umbraco/v8/feature/ui-hover-and-focus-outline-on-umb-checkbox-and-umb-radio
focus outline + hover states for umb-checkbox and umb-radio
2019-04-26 10:18:33 +01:00
Pete Duncanson 2470a2737f Added gulp-angular-embed-template (#4871)
Fixed #4845 by embedded the angularjs templates for directives in the directives, cuts down on network traffic and increases speed to render
2019-04-26 11:06:00 +02:00
Warren Buckley 1753ddbfc4 Merge pull request #5330 from umbraco/v8/feature/ui-umb-button-nicer-outline
V8: prettier outline for buttons, and only shown when tabbing is active.
2019-04-26 10:00:14 +01:00
Warren Buckley 4230ad27f3 Merge pull request #5329 from umbraco/v8/feature/ui-nested-content-add-content-button
V8: nested content consistent "add content"-button, and other adjustments.
2019-04-26 09:56:44 +01:00
Warren Buckley 9bca5e0347 Merge pull request #5332 from umbraco/v8/feature/ui-prettier-outline-on-media-picker
V8: prettier outline on media picker
2019-04-26 09:31:21 +01:00
Bjarne Fyrstenborg f82dff597b v8: Imagepicker prevalue and grid setting/styles as infinite editor (#4971) 2019-04-25 13:31:29 +02:00
Stephan 56d7755487 Merge branch 'v8/dev' into v8/spike/api-docs 2019-04-25 09:05:21 +02:00
Kenn Jacobsen 82f966ca24 Fix MNTP bounds min/max items validation 2019-04-24 22:09:00 +02:00
Sebastiaan Janssen 2179e85638 Merge pull request #5336 from umbraco/v8/feature/snupkg
Create new Nuget Symbol packags - snupkg
2019-04-24 16:10:33 +02:00
Niels Lyngsø defbb8e821 disables the tabbing-state if the user performes a mouse-click that reaches the window. 2019-04-24 15:56:37 +02:00
Niels Lyngsø f7dce756a7 focus outline + hover states for umb-checkbox and umb-radio 2019-04-24 15:50:57 +02:00
Niels Lyngsø 30385789c8 only show focus-outline on sections if tabbing is active 2019-04-24 14:15:24 +02:00
Niels Lyngsø 8bac388f73 prettier focus outline for app-header-actions 2019-04-24 14:15:02 +02:00
Niels Lyngsø 53c7df36b0 umb-outline to make it easy to apply pretty focus outline for elements. 2019-04-24 13:55:31 +02:00
Sebastiaan Janssen 5f5b21b43e Make Nested Content work with hidden item icons (#5324) 2019-04-24 13:37:48 +02:00
Sebastiaan Janssen 64f7cc1c29 General clean up, use === and double quotes everywhere 2019-04-24 13:35:24 +02:00
Sebastiaan Janssen c80187938b Make sure to parse as boolean in case old models still use "1" or the string "true" 2019-04-24 13:34:48 +02:00
Sebastiaan Janssen bb4be11a0b Merge branch 'v8/dev' into pr_5324 2019-04-24 13:32:29 +02:00
Warren Buckley 103c92bc69 Update powershell to use the snupkg format for symbol package to be hosted on nuget.org symbol server
Advisory from Nuget team is to no longer include the C# .cs files in the src folder of a nuget package
2019-04-24 12:31:05 +01:00
Warren Buckley 950849a4c6 Update jQuery to latest 3.4.0 (#5331)
Seems good
2019-04-24 13:21:24 +02:00
Elitsa Marinovska da125405ea Merge pull request #4722 from kjac/v8-fix-media-picker-create-folder
V8: Return folder creation to non-active state in media picker
2019-04-24 12:35:23 +02:00
Niels Lyngsø d05e188d00 prettier outline on media picker 2019-04-24 12:03:43 +02:00
elitsa 4cf55a8837 Getting the current user start nodes 2019-04-24 11:52:38 +02:00
Niels Lyngsø 5436478dfb prettier outline for buttons, and only shown when tabbing is active. 2019-04-24 11:37:03 +02:00
Warren Buckley 9333426985 Merge pull request #5304 from MMasey/v8/feature/tab-accessibility-improvements
V8: Login form accessibility improvements and form input tabbed focus styles
2019-04-24 10:25:13 +01:00
Warren Buckley c21b740c71 Merge pull request #5320 from shane-sigma/temp-5277-4
Re-adding outline to the umb-button__button for focus states
2019-04-24 10:00:44 +01:00
Niels Lyngsø 9e03103cbb using new ligther gray for background of nested content 2019-04-24 10:34:57 +02:00
Niels Lyngsø e889ec1fa9 added new lighter gray 2019-04-24 10:34:41 +02:00
Niels Lyngsø dc66807d13 changed the look of nested content 2019-04-24 10:31:30 +02:00
Warren Buckley fe57ef329b Revert the change to the gitignore - no web.config should be in ui.client folder anyway 2019-04-24 09:26:33 +01:00
elitsa 5ce226104b Merge branch 'v8/dev' into v8-fix-media-picker-create-folder 2019-04-24 09:41:48 +02:00
Niels Lyngsø 43586e6bb7 first step for changing the add-content button 2019-04-24 09:27:47 +02:00
Kenn Jacobsen fecf561279 Make Nested Content work with hidden item icons 2019-04-23 22:57:10 +02:00
Kenn Jacobsen 61cc22dccf V8: Send notifications for changes in permissions (#5287) 2019-04-23 22:00:35 +02:00
Kenn Jacobsen e7f4f61f93 V8: Send notifications for changes in public access (#5288)
Co-authored-by: Sebastiaan Janssen <sebastiaan@umbraco.com>
2019-04-23 21:55:42 +02:00
Kenn Jacobsen a6d8b48ab4 V8: Remove obsolete umb-permission styling (#5308) 2019-04-23 21:50:28 +02:00
Kenn Jacobsen 7cc9747b2f V8: Allow content to be shown before list view (#5074) 2019-04-23 21:31:48 +02:00
Kenn Jacobsen 72d588287f V8: Add option to create nonclustered primary keys using ICreateBuilder (#5261) 2019-04-23 21:03:50 +02:00
Sebastiaan Janssen 700fe9b787 Merge branch 'v7/dev' into v8/dev
# Conflicts:
#	src/Umbraco.Core/Persistence/Repositories/MediaRepository.cs
#	src/Umbraco.Core/Persistence/Repositories/VersionableRepositoryBase.cs
#	src/Umbraco.Web.UI.Client/src/common/security/securityinterceptor.js
2019-04-23 20:37:38 +02:00
Kenn Jacobsen d5858fe1be Enable manual sorting on contentTypeAlias 2019-04-23 20:28:17 +02:00
Kenn Jacobsen 6dba751167 Fix "sort by document type" in listviews 2019-04-23 20:28:17 +02:00
Kenn Jacobsen b367ae6c80 Fix "sort by document type" in media listviews 2019-04-23 20:27:25 +02:00
Kenn Jacobsen 07684bb1d6 Fix "sort by document type" in content listviews 2019-04-23 20:26:55 +02:00
Dennis Flæng 7eadcf66ed added submit button for row and layoutconfig (#5136) 2019-04-23 20:17:38 +02:00
Stephan 977bf91409 Merge branch 'v8/feature/4942-media-url-provider' into v8/dev 2019-04-23 19:32:30 +02:00
Kenn Jacobsen fab025bf66 V8: Don't use floats in the slider config as it only supports integers (#4821) 2019-04-23 17:27:34 +02:00
Ondrej Pialek 8d382fb9b7 Backoffice session timeout on custom-URL backoffices leads to high browser CPU and self-inflicted backend DDoS (#5210) 2019-04-23 16:37:37 +02:00
Stephan c19be0c64e Misc cleanup 2019-04-23 16:23:06 +02:00
Kenn Jacobsen 67e046e477 V8: Allow nested content without blueprints (#4777)
* Don't assume there is at least one NC blueprint
* NC disabled icon styling (hover pointer type)
* Allow and handle NC configs without blueprints
2019-04-23 16:14:26 +02:00
Kenn Jacobsen aba409600b V8: Improve notifications save button style and interaction (#5097) 2019-04-23 15:59:57 +02:00
Kenn Jacobsen fdfcb75a71 Make sure datatype configs are validated in infinite editing (#4776) 2019-04-23 15:41:45 +02:00
shane Prendergast ac44f800a6 Re-adding outline to the umb-button__button for focus states 2019-04-23 13:56:48 +01:00
Kenn Jacobsen 7eddc22bba V8: Send notifications for move, restore, copy and delete actions (#5255) 2019-04-23 14:24:45 +02:00
Kenn Jacobsen 9280c74062 V8: Use umb-checkbox for RTE configuration (#5119) 2019-04-23 14:19:08 +02:00
Sebastiaan Janssen 90cbdbf2cd Merge pull request #5316 from umbraco/v8/bugfix/5315-paging-error-nucache
Fix paging error in NuCache
2019-04-23 14:05:56 +02:00
Sebastiaan Janssen fdc9adfe83 Merge pull request #5278 from kjac/v8-fix-macro-parameter-configuration
V8: Fix "multiple" macro parameter property editor configuration
2019-04-23 14:02:45 +02:00
Stephan e6f6c498a5 Merge branch v8/dev into v8/feature/4942-media-url-provider 2019-04-23 13:58:17 +02:00
Kenn Jacobsen 5472297245 Add busy state to <umb-confirm/> OK button 2019-04-23 13:45:42 +02:00
Niels Lyngsø 71bea2bc25 update RTE model on changing code or media 2019-04-23 13:43:36 +02:00
Stephan d9653026de Merge branch 'v8/bugfix/4963-fixing-models-and-member-repo' into v8/dev 2019-04-23 13:41:36 +02:00
Stephan 3185f7ae97 Fix member type builtin properties handling 2019-04-23 13:07:57 +02:00
Kenn Jacobsen 417b270f59 V8: Allow sorting manually by name in listviews (#5252) 2019-04-23 13:05:04 +02:00
Stephan 509b1151a2 Fix tests 2019-04-23 12:09:22 +02:00
Stephan 0cf857e8bc Cleanup 2019-04-23 12:09:13 +02:00
Stephan 50f6779c17 Merge branch v8/dev into v8/bugfix/4963-fixing-models-and-member-repo 2019-04-23 11:31:47 +02:00
Stephan 5d0010a993 Fix paging error in NuCache 2019-04-23 11:11:53 +02:00
Stephan f47cfe155a Merge branch 'v8/dev' of https://github.com/umbraco/Umbraco-CMS into v8/dev 2019-04-23 11:02:15 +02:00
Stephan 6c08828887 Merge branch 'temp8-4682-ui-selection-of-users-and-user-groups' into v8/dev 2019-04-23 11:01:50 +02:00
Niels Lyngsø 74b4689059 corrected spacing 2019-04-23 10:59:53 +02:00
Stephan 2f1687cd4f Merge branch 'v8/dev' into temp8-4682-ui-selection-of-users-and-user-groups 2019-04-23 10:54:07 +02:00
Stephan 9443599382 Merge pull request #5307 from kjac/v8-fix-search-result-mapping
V8: Fix mapping for search results
2019-04-23 10:43:12 +02:00
Sebastiaan Janssen 160d140167 Merge branch 'v7/dev' into v8/dev
# Conflicts:
#	src/Umbraco.Web/Strategies/NotificationsHandler.cs
2019-04-22 13:22:15 +02:00
Sebastiaan Janssen db7ae9a7e2 V7: Send notifications for changes in permissions (#5306)
V7: Send notifications for changes in permissions
2019-04-22 13:21:03 +02:00
Sebastiaan Janssen 2e6f032222 Merge branch 'v7/dev' into pr_5306
# Conflicts:
#	src/Umbraco.Web/Strategies/NotificationsHandler.cs
2019-04-22 13:20:15 +02:00
Sebastiaan Janssen 9fc33d71e4 V7: Send notifications when an item is copied (#5302)
V7: Send notifications when an item is copied
2019-04-22 13:15:44 +02:00
Sebastiaan Janssen 916cd999d5 Merge branch 'v7/dev' into pr_5302
# Conflicts:
#	src/Umbraco.Web/Strategies/NotificationsHandler.cs
2019-04-22 13:14:32 +02:00
Sebastiaan Janssen a75506d60b V7: Send notifications when an item is moved or restored (#5303) 2019-04-22 13:04:14 +02:00
Sebastiaan Janssen 6631a50a44 Merge branch 'v7/dev' into pr_5303
# Conflicts:
#	src/Umbraco.Web/Strategies/NotificationsHandler.cs
2019-04-22 13:03:00 +02:00
Sebastiaan Janssen 9611791f31 Merge branch 'v7/dev' into v8/dev
# Conflicts:
#	src/Umbraco.Web/Strategies/NotificationsHandler.cs
2019-04-22 12:52:25 +02:00
Kenn Jacobsen c35a3fa702 Send notifications for rollbacks 2019-04-22 12:51:37 +02:00
Kenn Jacobsen 153ac58d2a Send notifications for rollbacks 2019-04-22 12:50:44 +02:00
Kenn Jacobsen a969ff6e10 Make sure Nested Content scaffolds are listed in defined sort order 2019-04-22 12:34:19 +02:00
Kenn Jacobsen c7b4d1b206 Always show file names for media/files without thumbnail 2019-04-22 12:31:01 +02:00
Sebastiaan Janssen aaf8ba0211 Merge branch 'v7/dev' into v8/dev
# Conflicts:
#	src/Umbraco.Core/IO/MediaFileSystem.cs
2019-04-22 12:28:33 +02:00
Kenn Jacobsen 072c014055 Read image dimensions via GDI if EXIF fails with an exception 2019-04-22 12:21:55 +02:00
Kenn Jacobsen 655befde42 Read image dimensions via GDI if EXIF fails with an exception 2019-04-22 12:19:36 +02:00
Sebastiaan Janssen 344b7731ce Fix JS unit tests 2019-04-22 12:10:53 +02:00
Sebastiaan Janssen 687cc4630f Fix missing semicolon 2019-04-22 10:47:00 +02:00
Kenn Jacobsen e180bb6722 V8: Fix broken listview pagination when using the back link (#5149) 2019-04-22 10:44:29 +02:00
Kenn Jacobsen 32104fff41 V8: Add back button to listviews for members (#5158)
* Add back button to edit member

* Don't set illegal location (with querystring params)
2019-04-22 10:21:38 +02:00
Kenn Jacobsen 8b6fbee47e V8: Add back button to listviews in media (#5116) 2019-04-22 10:00:51 +02:00
Kenn Jacobsen 59df7f1399 Ensure consistency in the way panels are spaced 2019-04-22 09:57:44 +02:00
Kenn Jacobsen f55e05da79 Don't explode when passing bad parameters to log resource 2019-04-22 09:55:38 +02:00
Kenn Jacobsen 2a43170915 V8: Add toggle group (#5096)
V8: Add toggle group
2019-04-22 09:16:41 +02:00
Kenn Jacobsen 717f8c9944 Fix mapping for search results 2019-04-21 21:00:34 +02:00
Kenn Jacobsen ff4fe2cd79 Send notifications for changes in permissions 2019-04-21 13:22:49 +02:00
Mike 233f00e2d4 improvment: update tabbed focus colour to use blueExtraDark 2019-04-20 20:37:22 +01:00
Mike 18a2871419 feat: return focus to password field on password reveal toggle 2019-04-20 20:20:30 +01:00
Mike 8c954ef433 feat: add clear tabbed focus state to form inputs 2019-04-20 20:15:33 +01:00
Mike b232d3c694 feat: add a 'tabbing-active' class when a person starts tabbing 2019-04-20 20:05:18 +01:00
Kenn Jacobsen d2f727a1ba Send notifications when an item is moved or restored 2019-04-20 20:40:52 +02:00
Kenn Jacobsen 38bb98b099 Send notifications when an item is copied 2019-04-20 20:31:36 +02:00
Kenn Jacobsen d87464b8e4 Fix the style of the public access confirmation button 2019-04-18 13:48:54 +02:00
Sebastiaan Janssen aba9c89ff4 Merge pull request #5090 from deMD/temp8-5069-getTreePackageFolder-use-localeCompare
V8 Plugins: Changed treeService.getTreePackageFolder to use localeCompare
2019-04-18 12:42:17 +02:00
Sebastiaan Janssen 74f98d51cd Compare to 0 to get the desired result 2019-04-18 12:37:52 +02:00
Sebastiaan Janssen 1e475bfc6f Merge branch 'v8/dev' into pr_5090 2019-04-18 12:11:24 +02:00
Kenn Jacobsen e7f3f8da68 Remove unused translations from area"editcontenttype" 2019-04-18 12:05:17 +02:00
Kenn Jacobsen a3af3d6d2b Use "group" instead of "tab" on Nested Content config 2019-04-18 11:47:36 +02:00
Kenn Jacobsen 29a542a0dd Support stylesheets in subfolders in the RTE 2019-04-18 11:38:34 +02:00
Kenn Jacobsen 73e4c6022d Update the title of the macro view picker 2019-04-18 09:38:20 +02:00
Sebastiaan Janssen eb10d71bff Don't just Parse, the value might be null, have to use TryParse 2019-04-17 16:47:23 +02:00
Sebastiaan Janssen 9cf69d53c2 Merge branch 'v7/dev' into v8/dev
# Conflicts:
#	src/Umbraco.Core/Services/ContentService.cs
#	src/Umbraco.Core/Services/IContentService.cs
#	src/Umbraco.Core/Services/IMediaService.cs
#	src/Umbraco.Core/Services/MediaService.cs
#	src/Umbraco.Web/Editors/ContentController.cs
#	src/Umbraco.Web/Editors/MediaController.cs
2019-04-17 16:39:10 +02:00
Kenn Jacobsen 2a930e5a66 Log the ID of the current user when emptying the media recycle bin 2019-04-17 16:01:18 +02:00
Kenn Jacobsen 2d32863fc9 Audit current user when moving media + clean up a few audit related things 2019-04-17 16:00:21 +02:00
Sebastiaan Janssen 2c32fabd36 Merge pull request #5054 from kjac/fix-content-empty-trash-audit-user
V7: Log correct user ID when emptying the content recycle bin
2019-04-17 15:58:43 +02:00
Kenn Jacobsen a48d97e631 Create explicit overloads for UrlAbsolute 2019-04-17 15:38:47 +02:00
Kenn Jacobsen 4107f47588 Add optional culture parameter to UrlAbsolute extension 2019-04-17 15:38:47 +02:00
Kenn Jacobsen bdac2a4a41 Use umb-checkbox for user filters 2019-04-17 15:35:57 +02:00
Stephan 791581f502 Use ConcurrentDictionary specific methods 2019-04-17 14:52:38 +02:00
Sebastiaan Janssen 1941c0dd1c Merge branch 'v7/dev' into v8/dev
# Conflicts:
#	src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
#	src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs
#	src/Umbraco.Core/Services/ContentService.cs
#	src/Umbraco.Core/Services/IContentService.cs
#	src/Umbraco.Core/UriExtensions.cs
#	src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js
#	src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js
#	src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js
#	src/Umbraco.Web.UI.Client/src/common/services/search.service.js
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/contentpicker/contentpicker.html
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/linkpicker/linkpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/linkpicker/linkpicker.html
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/mediaPicker/mediapicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/treepicker/treepicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/treepicker/treepicker.html
#	src/Umbraco.Web.UI.Client/src/views/components/content/umb-content-node-info.html
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/media.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/rte.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/multiurlpicker/multiurlpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/relatedlinks/relatedlinks.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.prevalues.html
#	src/Umbraco.Web/Cache/UnpublishedPageCacheRefresher.cs
#	src/Umbraco.Web/Editors/ContentController.cs
#	src/Umbraco.Web/Editors/EntityController.cs
#	src/Umbraco.Web/Editors/MediaController.cs
#	src/Umbraco.Web/PropertyEditors/ContentPicker2PropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/MediaPicker2PropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/MultiNodeTreePicker2PropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/MultiUrlPickerPropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/RelatedLinks2PropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/RichTextPreValueEditor.cs
#	src/Umbraco.Web/PublishedCache/ContextualPublishedCache.cs
#	src/Umbraco.Web/PublishedCache/ContextualPublishedContentCache.cs
#	src/Umbraco.Web/PublishedCache/ContextualPublishedMediaCache.cs
#	src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs
#	src/Umbraco.Web/Search/UmbracoTreeSearcher.cs
#	src/Umbraco.Web/Trees/ContentTreeControllerBase.cs
#	src/Umbraco.Web/Trees/TreeControllerBase.cs
#	src/Umbraco.Web/Trees/TreeQueryStringParameters.cs
#	src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForContentAttribute.cs
#	src/Umbraco.Web/WebApi/Filters/FilterAllowedOutgoingMediaAttribute.cs
#	src/Umbraco.Web/umbraco.presentation/content.cs
#	src/Umbraco.Web/umbraco.presentation/umbraco/preview/PreviewContent.cs
2019-04-17 14:52:35 +02:00
Sebastiaan Janssen 650ef39780 Merge branch 'v8/dev' into v8/merge/5061-from-v7 2019-04-17 14:44:10 +02:00
Sebastiaan Janssen 7db0440b5c Merge branch 'v7/dev' into v8/dev
# Conflicts:
#	src/Umbraco.Core/Persistence/Repositories/ContentRepository.cs
#	src/Umbraco.Core/Persistence/Repositories/Interfaces/IContentRepository.cs
#	src/Umbraco.Core/Services/ContentService.cs
#	src/Umbraco.Core/Services/IContentService.cs
#	src/Umbraco.Core/UriExtensions.cs
#	src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js
#	src/Umbraco.Web.UI.Client/src/common/resources/entity.resource.js
#	src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js
#	src/Umbraco.Web.UI.Client/src/common/services/search.service.js
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/contentpicker/contentpicker.html
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/linkpicker/linkpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/linkpicker/linkpicker.html
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/mediaPicker/mediapicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/treepicker/treepicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/common/overlays/treepicker/treepicker.html
#	src/Umbraco.Web.UI.Client/src/views/components/content/umb-content-node-info.html
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/contentpicker/contentpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/media.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/grid/editors/rte.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/mediapicker/mediapicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/multiurlpicker/multiurlpicker.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/relatedlinks/relatedlinks.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.controller.js
#	src/Umbraco.Web.UI.Client/src/views/propertyeditors/rte/rte.prevalues.html
#	src/Umbraco.Web/Cache/UnpublishedPageCacheRefresher.cs
#	src/Umbraco.Web/Editors/ContentController.cs
#	src/Umbraco.Web/Editors/EntityController.cs
#	src/Umbraco.Web/Editors/MediaController.cs
#	src/Umbraco.Web/PropertyEditors/ContentPicker2PropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/GridPropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/MediaPicker2PropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/MultiNodeTreePicker2PropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/MultiUrlPickerPropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/RelatedLinks2PropertyEditor.cs
#	src/Umbraco.Web/PropertyEditors/RichTextPreValueEditor.cs
#	src/Umbraco.Web/PublishedCache/ContextualPublishedCache.cs
#	src/Umbraco.Web/PublishedCache/ContextualPublishedContentCache.cs
#	src/Umbraco.Web/PublishedCache/ContextualPublishedMediaCache.cs
#	src/Umbraco.Web/PublishedCache/XmlPublishedCache/PublishedContentCache.cs
#	src/Umbraco.Web/Search/UmbracoTreeSearcher.cs
#	src/Umbraco.Web/Trees/ContentTreeControllerBase.cs
#	src/Umbraco.Web/Trees/TreeControllerBase.cs
#	src/Umbraco.Web/Trees/TreeQueryStringParameters.cs
#	src/Umbraco.Web/WebApi/Filters/EnsureUserPermissionForContentAttribute.cs
#	src/Umbraco.Web/WebApi/Filters/FilterAllowedOutgoingMediaAttribute.cs
#	src/Umbraco.Web/umbraco.presentation/content.cs
#	src/Umbraco.Web/umbraco.presentation/umbraco/preview/PreviewContent.cs
2019-04-17 14:35:59 +02:00
Shannon a2a247b413 removes the enforcement of non duplicate property type aliases for now 2019-04-17 21:00:15 +10:00
Shannon 0b6a369047 When removing a property group, we need to first remove the group and then re-assign the property types so that duplicates are not added 2019-04-17 17:12:34 +10:00
Shannon 522fdefb8c Ensures that ALL membership properties are created by the installer, removes the logic that updates a membertype while fetching it, fixes the logic of mapping membership properties when fetching and they don't exist. 2019-04-17 16:42:17 +10:00
Shannon 4d8d10f07a adds comments, ignores test for now 2019-04-17 16:03:36 +10:00
Shannon Deminick 1ad19edfbd Merge pull request #5262 from kjac/v8-fix-listview-annotation-order
V8: Tree node annotation "pending changes" should take precendence over "is listview"
2019-04-17 15:25:12 +10:00
Shannon Deminick 637cf6a608 Merge pull request #5276 from 0Neji/temp-5273
Make DropDownFlexibleConfiguration class public
2019-04-17 15:22:02 +10:00
Rasmus John Pedersen a3ee718824 Add media url provider tests 2019-04-16 15:36:21 +02:00
Rasmus John Pedersen d0701ae34e Add media url provider support 2019-04-16 15:36:21 +02:00
Kenn Jacobsen 3668b68155 Merge with v8/dev 2019-04-16 11:48:20 +02:00
Kenn Jacobsen e8e29c9390 Merge branch 'v8/dev' into v8-fix-macro-parameter-configuration 2019-04-16 11:25:48 +02:00
Kenn Jacobsen 0787824fba Pass default configuration to configuration editor for macro parameter editors 2019-04-16 11:23:22 +02:00
Ben Palmer 40d2898fb8 Make DropDownFlexibleConfiguration class public to allow configuration to be set when creating a new data type 2019-04-16 09:21:24 +01:00
Shannon 6f44e4fd09 Fixes INotifyCollectionChanged collections to raise the correct events, ensures that no duplicate property type aliases can be added/updated to 2019-04-16 17:37:42 +10:00
Rasmus John Pedersen 27b4329c1e Rename udiHelper to udiParser 2019-04-16 08:50:19 +02:00
Shannon 02ddf80014 Adds a unit test 2019-04-16 15:39:28 +10:00
Shannon Deminick 9f9d24e6b3 Merge pull request #5246 from umbraco/v8/bugfix/5216-cache-getbyudi
Add GetById(Udi) to published caches
2019-04-16 12:08:39 +10:00
Shannon e4f6794c59 Merge branch 'kjac-v8-feature-tree-annotations-visibility' into v8/dev 2019-04-16 11:42:22 +10:00
Shannon 440ac40674 Merge branch 'v8-feature-tree-annotations-visibility' of https://github.com/kjac/Umbraco-CMS into kjac-v8-feature-tree-annotations-visibility 2019-04-16 11:42:04 +10:00
Elitsa Marinovska dba241ef50 Adding build script for API docs 2019-04-15 22:04:55 +02:00
Elitsa Marinovska 3b22480b5d Update with correct paths 2019-04-15 21:46:09 +02:00
Kenn Jacobsen 52bc4b04b3 Fix annotation hover background color 2019-04-15 21:16:59 +02:00
Kenn Jacobsen 3f5ccb302d Make the tree annotations easier to see 2019-04-15 21:10:09 +02:00
Rasmus John Pedersen 32197f0bd1 Add angular udi helper service 2019-04-15 10:31:10 +02:00
Stephan 6cb55789bd Fix mapper concurrency issue 2019-04-15 10:25:29 +02:00
Shannon 723d9eddd1 unbreaks a ctor change preventing 8.0.2 from being dropped into the bin 2019-04-15 18:15:52 +10:00
Shannon fa655b812c Fix composers ordering 2019-04-15 17:55:22 +10:00
Shannon Deminick 747a8cba2e Merge pull request #5175 from umbraco/v8/bugfix/5174-composer-ordering
Fix composers ordering
2019-04-15 17:54:00 +10:00
Stephan 7e64f455b2 Remove leaked Console.WriteLine 2019-04-15 08:30:04 +02:00
Shannon 576c10cd50 NuCache: fix vanishing content when refreshing content types 2019-04-15 12:56:45 +10:00
Shannon Deminick 0cf609fdce Merge pull request #5240 from umbraco/v8/bugfix/5222-nucache-vanishing-content
NuCache: fix vanishing content when refreshing content types
2019-04-15 12:55:43 +10:00
Shannon Deminick 3a26443f58 Merge pull request #5247 from umbraco/v8/bugfix/bad-local-temp-path
Fix bad local temp path
2019-04-15 12:24:41 +10:00
Kenn Jacobsen 9953aea156 Make tree item annotation "has pending changes" take precendence over "is listview" 2019-04-14 21:03:24 +02:00
Stephan aa75fcfdb3 Fix bad local temp path 2019-04-12 17:40:10 +02:00
Stephan d4ba1298d5 Add GetById(Udi) to published caches 2019-04-12 16:05:43 +02:00
Stephan 14f9445ffb Ensure entities type in content caches GetById(Udi) 2019-04-12 15:34:06 +02:00
Stephan 7f7c9d2796 Merge branch 'v7/bugfix/5216' into v7/dev 2019-04-12 15:33:21 +02:00
Warren Buckley ba4bb843de Merge pull request #5076 from umbraco/temp8-4521-umb-property-editor-css-width
4521 umb-property-editor css width-limitation
2019-04-12 13:56:31 +01:00
Warren Buckley 43fc926f1b Merge pull request #5157 from umbraco/v8/bugfix/5129-ui-app-header-focus
V8: Visually more catching focus highlighting
2019-04-12 10:49:51 +01:00
Elitsa Marinovska e06d18330c Merge pull request #4721 from kjac/v8-fix-invalid-hostname
V8: Handle invalid hostnames
2019-04-12 11:38:03 +02:00
elitsa fb3f2101f0 Merge branch 'v8/dev' into v8-fix-invalid-hostname
# Resolved Conflicts:
#	src/Umbraco.Web.UI/Umbraco/config/lang/en.xml
#	src/Umbraco.Web.UI/Umbraco/config/lang/en_us.xml
2019-04-12 11:27:43 +02:00
Warren Buckley f8f28ec46a Merge branch 'v8/dev' into v8/bugfix/5129-ui-app-header-focus 2019-04-12 09:40:02 +01:00
Elitsa Marinovska 6323dfcf9c Merge pull request #5164 from kjac/v8-fix-navigation-partial-template
V8: Fix navigation partial view template
2019-04-12 10:00:39 +02:00
Elitsa Marinovska 108e3e527f Merge pull request #5178 from kjac/v8-fix-content-type-matching-template-model
V8: Use the content type model when creating a "matching template"
2019-04-12 09:48:00 +02:00
elitsa ebe4c1b3c3 Fixing formatting 2019-04-12 08:56:18 +02:00
Elitsa Marinovska 93f382fc0f Merge pull request #5159 from poornimanayar/error-message-style-hostname
Fix the colour of the error message in the domains overlay
2019-04-12 08:52:46 +02:00
Stephan 8b509656cd NuCache: fix vanishing content when refreshing content types 2019-04-11 18:55:40 +02:00
Kenn Jacobsen 179afe7e0d Add IsVisible extension on IPublishedElement 2019-04-11 17:44:16 +02:00
Kenn Jacobsen a09e612e1f V8: Fix the layout for editing datatypes in infinite edit mode (#5194)
### Prerequisites

- [x] I have added steps to test this contribution in the description below

If there's an existing issue for this PR then this fixes https://github.com/umbraco/Umbraco-CMS/issues/5154

### Description

This PR fixes the layout of the datatype editor when editing datatypes in infinite editing mode (see #5154 for details).

When applied the editor behaves like this:

![dataype-infinite-editing](https://user-images.githubusercontent.com/7405322/55711636-5df57780-59ed-11e9-958d-0deb05cb17bf.gif)
2019-04-10 15:31:55 +02:00
Niels Lyngsø 9ad5dad710 additional spacing added 2019-04-10 14:59:16 +02:00
Niels Lyngsø 7afd01ff5c Styling update for umb-tags 2019-04-10 14:52:54 +02:00
Niels Lyngsø f8af9fd895 correct spacing between properties 2019-04-10 14:52:39 +02:00
Niels Lyngsø ac1d462bc5 ability to remove tag by pressing delete or backspace 2019-04-10 14:52:16 +02:00
Warren Buckley a4e00b62b3 Merge pull request #5219 from umbraco/v8/bugfix/ui-doc-type-editor
bigger area for add-property + only hover-state if you can edit property
2019-04-10 14:09:03 +02:00
Niels Lyngsø ed8ba3ddcf changed inline-styling into a appearance property 2019-04-10 13:40:06 +02:00
Warren Buckley 9928b770f7 Merge pull request #5221 from umbraco/v8/bugfix/ui-make-toggle-round
Making Umb-Toggle round
2019-04-10 13:28:00 +02:00
Niels Lyngsø 43759fbef3 applied icons again 2019-04-10 12:10:01 +02:00
Niels Lyngsø 94334ff04f style updates 2019-04-10 10:42:29 +02:00
Niels Lyngsø 1fcce288da changed action into buttons for keyboard focus 2019-04-10 10:42:21 +02:00
Niels Lyngsø 5fbd455fd8 align description with title 2019-04-10 10:41:58 +02:00
Shannon be7f42c454 Don't show the recycle bin in tree pickers/dialogs 2019-04-10 09:52:06 +10:00
Shannon Deminick ff707e8768 Merge pull request #4960 from kjac/v8-fix-tree-dialog-remove-recycle-bin
V8: Don't show the recycle bin in tree pickers/dialogs
2019-04-10 09:50:42 +10:00
Ronald Barendse d2e04614c6 Added UDI support for GetById and fixed bug not using specified preview mode 2019-04-09 23:21:40 +02:00
Stephan e540a4ac23 IsVisible moves from publishde content to element 2019-04-09 21:24:55 +02:00
Stephan ed4de5b000 Merge pull request #5041 from kjac/v8-feature-element-isvisible
V8: Add IsVisible extension on IPublishedElement
2019-04-09 21:20:37 +02:00
Niels Lyngsø 699c34263e bigger area for add-property + only hover-state if you can edit property 2019-04-09 16:42:24 +02:00
Rasmus John Pedersen c96cd09dba Add RTE media url -> localLink migration 2019-04-09 15:35:42 +02:00
Rasmus John Pedersen a96bca5fab Remove isMedia workaround 2019-04-09 15:35:41 +02:00
Rasmus John Pedersen 8e5d33b15e Resolve media urls when parsing localLink 2019-04-09 15:35:37 +02:00
Rasmus John Pedersen 0a66bbb293 Use localLink for media 2019-04-09 11:59:09 +02:00
Rasmus John Pedersen f246dd7dca Support editing media links 2019-04-09 11:59:09 +02:00
Bjarke Berg b29fd4ada3 Merge pull request #5192 from umbraco/v8/bugfix/5183-mapping-enumerables
Fix mapping of enumerable
2019-04-09 11:51:39 +02:00
Bjarke Berg b1674235e9 Merge pull request #5167 from umbraco/v8/bugfix/checkboxlist-fix
Fixing property editor "checkboxlist" to work in v8
2019-04-09 11:12:13 +02:00
Niels Lyngsø 8441d9017b Merge remote-tracking branch 'origin/v8/dev' into v8/bugfix/checkboxlist-fix 2019-04-09 08:54:02 +02:00
Shannon 7e1ee26dee Fix spelling mistake 2019-04-09 10:34:59 +10:00
Stephan 6c8ded6275 Better mapping of enumerable 2019-04-08 16:41:33 +02:00
Niels Lyngsø 968fc40622 Merge remote-tracking branch 'origin/v8/dev' into v8/bugfix/checkboxlist-fix 2019-04-08 15:22:59 +02:00
Stephan 9eb1415796 Fix mapping of enumerable 2019-04-08 10:05:21 +02:00
Kenn Jacobsen 1aec0e1d9c Fix exception types as per review 2019-04-08 07:24:56 +02:00
Stephan 1c9b449c46 Log more details about boot environment 2019-04-07 16:25:06 +02:00
Kenn Jacobsen 2ee8f9dea2 Use the content type model when creating a "matching template" 2019-04-06 08:00:44 +02:00
Stephan c87a9d6bfa Fix composers ordering 2019-04-05 19:00:34 +02:00
Niels Lyngsø ae853a178d Merge remote-tracking branch 'origin/v8/dev' into v8/bugfix/checkboxlist-fix 2019-04-05 14:02:21 +02:00
Niels Lyngsø a4d8f0cd55 Fixing model sync, much weird code cleaned up 2019-04-05 14:01:28 +02:00
Niels Lyngsø f141025248 Fixing checkbox list to work in v8 2019-04-05 09:43:27 +02:00
Shannon e38095b727 NuCache: fix loading the media cache from local files, was missing media 2019-04-05 10:49:19 +11:00
Shannon b5796ad237 Enable configuration of NuCache BTree block size #5114 2019-04-05 10:44:36 +11:00
Kenn Jacobsen 6e1a40e2ee When creating partial views from templates, also replace (Model.Content) with (Model) - building upon the logic in e2d41106 2019-04-04 19:41:39 +02:00
Poornima Nayar 75bba068a4 Fix the colour of the error message in the domains overlay 2019-04-04 16:39:53 +02:00
Shannon Deminick 2ae639a3ae Merge pull request #5099 from umbraco/v7/feature/5059-alt-preview
Alternate Preview Engine
2019-04-04 23:35:23 +11:00
Niels Lyngsø 30da32ee94 Visually more catching focus highlighting 2019-04-04 14:15:57 +02:00
Shannon de8f01a4b2 Merge branch 'v7/dev' into v7/feature/5059-alt-preview 2019-04-04 23:11:27 +11:00
Stephan f985c437b5 Add content.SetValue overload for posted files 2019-04-04 09:28:34 +02:00
Andrew Deans 63fb8f5933 Fix case of query parameter 2019-04-04 09:12:40 +02:00
Shannon Deminick 10f22f7848 Merge pull request #5118 from kjac/v7-fix-content-info-contenttype-alias
V7: Add content type alias to content "general" info box
2019-04-04 14:02:06 +11:00
Niels Lyngsø bc821db8eb less space for content-node and media-node 2019-04-03 15:11:55 +02:00
Niels Lyngsø 959402d545 removed permissions column 2019-04-03 15:11:36 +02:00
Niels Lyngsø df46593ef3 improved list spacing, better text-overflow & center aligned select-all-checkbox for users list 2019-04-03 15:00:00 +02:00
Niels Lyngsø 1ff67df9df Merge remote-tracking branch 'origin/v8/dev' into temp8-4521-umb-property-editor-css-width 2019-04-03 13:47:30 +02:00
Niels Lyngsø db0a069b02 move highlight css to umb-table-body__link 2019-04-03 12:40:15 +02:00
Niels Lyngsø 4e027f7c83 space correction 2019-04-03 11:19:26 +02:00
Niels Lyngsø d2ff96e7ea show checkmark icon when checked 2019-04-03 11:18:37 +02:00
Niels Lyngsø 17e9487bf0 remove end of none existing anchor element 2019-04-03 11:18:15 +02:00
Niels Lyngsø 7f61a6fe9f ability to open as a new tab 2019-04-03 10:51:01 +02:00
Niels Lyngsø 3d949c9a55 changed user groups to use umb-table 2019-04-03 10:37:31 +02:00
Shannon eb529783c4 Don't allow move in members listview 2019-04-03 16:22:13 +11:00
Shannon a8265db5f0 Reload listview after moving items 2019-04-03 10:45:04 +11:00
Niels Lyngsø 0997fe6732 checkmark column removed 2019-04-02 10:12:21 +02:00
Kenn Jacobsen fb1f2c8af4 Add content type alias to content "general" info box 2019-04-02 08:12:46 +02:00
Stephan e6d75f27de Alt. preview: rename modes 2019-04-01 08:23:48 +02:00
Stephan 9bcd70589c Alt. preview: thread safety 2019-04-01 08:21:01 +02:00
Shannon 7dcf2b1abb infinity editing dim-layer for umb-modelcolumn 2019-04-01 17:05:13 +11:00
Stephan 514452ddb9 Better ServerMessenger configuration 2019-04-01 16:30:37 +11:00
Stephan 0676726bfc Refactor preview 2019-03-28 10:52:19 +01:00
Stephan bb43fc310a Add service-level loading of preview Xml document 2019-03-27 17:11:21 +01:00
Dave de Moel ff9179a15f Changed check to use localeCompare 2019-03-27 10:33:21 +01:00
Stephan 3524ba83a8 Merge branch 'v7/bugfix/5019-change-log-level' into dev-v7 2019-03-27 10:29:30 +01:00
Niels Lyngsø a7941b9678 setting width limit of selected property editors 2019-03-26 10:10:34 +01:00
Niels Lyngsø 31fd8066a4 fixing border color, which needs to be white. 2019-03-26 10:10:13 +01:00
Niels Lyngsø 5899f08d7f removing the default width limitation. 2019-03-26 10:09:43 +01:00
Niels Lyngsø 8a16c749e1 Mixin for limiting the width of a property-editor 2019-03-26 10:09:21 +01:00
Bjarke Berg 011d406301 https://github.com/umbraco/Umbraco-CMS/issues/5019 - Changed log level from error to debug. This will spam the log if we request with invalid parameters 2019-03-25 11:59:41 +01:00
Kenn Jacobsen 8bd9ae062d Merge with dev-v7 2019-03-24 13:37:32 +01:00
Kenn Jacobsen d51daa2a8a Make sure the correct user is registered in the log when emptying the recycle bin 2019-03-24 13:25:55 +01:00
Dan White cc9a7ff942 U4 10147 - Bypass User Security option in pickers (#2441) 2019-03-23 12:51:36 +01:00
Kenn Jacobsen 33a91bb9e9 Add IsVisible extension on IPublishedElement 2019-03-21 15:01:46 +01:00
Kenn Jacobsen 761297a2db Merged with dev-v8 2019-03-20 11:50:35 +01:00
Kenn Jacobsen 0c602567ce Don't show the recycle bin in tree pickers/dialogs 2019-03-12 10:25:51 +01:00
Bjarne Fyrstenborg 28d4f1cc44 Fix issues where table cells collapse when sorting doctypes in Nested Content config 2019-03-03 20:18:41 +01:00
Kenn Jacobsen 4851bb0534 Handle mixed variance when creating content templates from content 2019-02-27 19:13:51 +01:00
Kenn Jacobsen b9d1df0844 Return folder creation to non-active state in media picker 2019-02-24 15:28:04 +01:00
Kenn Jacobsen 32a622a6ea Add missing documentation + a bit of renaming 2019-02-24 15:10:49 +01:00
Kenn Jacobsen 7ca6739cee Clear error before (re)submitting 2019-02-24 15:01:47 +01:00
Kenn Jacobsen 214457fc04 Add translation 2019-02-24 09:50:13 +01:00
Kenn Jacobsen 30d46a6204 Merge branch 'v8-wip-invalid-hostname' into v8-fix-invalid-hostname 2019-02-24 09:40:07 +01:00
Kenn Jacobsen b94b94ea06 Add serverside validation of assigned hostnames 2019-02-24 09:37:22 +01:00
372 changed files with 9612 additions and 6394 deletions
+1
View File
@@ -161,3 +161,4 @@ build/temp/
# eof
/src/Umbraco.Web.UI.Client/TESTS-*.xml
/src/ApiDocs/api/*
+2 -1
View File
@@ -39,6 +39,8 @@
<dependency id="Serilog.Formatting.Compact.Reader" version="[1.0.3,1.999999)" />
<dependency id="Serilog.Settings.AppSettings" version="[2.2.2,2.999999)" />
<dependency id="Serilog.Sinks.File" version="[4.0.0,4.999999)" />
<dependency id="Serilog.Sinks.Map" version="[1.0.0,1.999999)" />
<dependency id="Serilog.Sinks.Async" version="[1.3.0,1.999999)" />
<dependency id="Umbraco.SqlServerCE" version="[4.0.0.1,4.999999)" />
<dependency id="NPoco" version="[3.9.4,3.999999)" />
</group>
@@ -54,6 +56,5 @@
<!-- symbols -->
<file src="$BuildTmp$\bin\Umbraco.Core.pdb" target="lib" />
<file src="$BuildTmp$\..\src\Umbraco.Core\**\*.cs" exclude="$BuildTmp$\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Core" />
</files>
</package>
-2
View File
@@ -59,8 +59,6 @@
<!-- symbols -->
<file src="$BuildTmp$\bin\Umbraco.Web.pdb" target="lib" />
<file src="$BuildTmp$\..\src\Umbraco.Web\**\*.cs" exclude="$BuildTmp$\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Web" />
<file src="$BuildTmp$\bin\Umbraco.Examine.pdb" target="lib" />
<file src="$BuildTmp$\..\src\Umbraco.Examine\**\*.cs" exclude="$BuildTmp$\..\src\**\TemporaryGeneratedFile*.cs" target="src\Umbraco.Examine" />
</files>
</package>
+1
View File
@@ -58,6 +58,7 @@
<!-- config transforms -->
<!-- beware! config transforms not supported by PackageReference -->
<file src="tools\Web.config.install.xdt" target="Content\Web.config.install.xdt" />
<file src="tools\serilog.config.install.xdt" target="Content\config\serilog.config.install.xdt" />
<file src="tools\ClientDependency.config.install.xdt" target="Content\config\ClientDependency.config.install.xdt" />
<file src="tools\umbracoSettings.config.install.xdt" target="Content\config\umbracoSettings.config.install.xdt" />
<file src="tools\Views.Web.config.install.xdt" target="Views\Web.config.install.xdt" /> <!-- FIXME: Content\ !! and then... transform?! -->
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">>
<appSettings>
<add key="serilog:using:File" value="Umbraco.Core" xdt:Transform="SetAttributes(value)" xdt:Locator="Match(key)"/>
<add key="serilog:write-to:File.shared" xdt:Transform="Remove" xdt:Locator="Match(key)"/>
</appSettings>
</configuration>
+44
View File
@@ -0,0 +1,44 @@
$uenv=build/build.ps1 -get
$src = "$($uenv.SolutionRoot)\src"
$tmp = $uenv.BuildTemp
$out = $uenv.BuildOutput
$DocFxJson = "$src\ApiDocs\docfx.json"
$DocFxSiteOutput = "$tmp\_site\*.*"
################ Do the UI docs
$uenv.CompileBelle()
"Moving to Umbraco.Web.UI.Client folder"
cd .\src\Umbraco.Web.UI.Client
"Generating the docs and waiting before executing the next commands"
& gulp docs | Out-Null
# change baseUrl
$BaseUrl = "https://our.umbraco.com/apidocs/v8/ui/"
$IndexPath = "./docs/api/index.html"
(Get-Content $IndexPath).replace('location.href.replace(rUrl, indexFile)', "`'" + $BaseUrl + "`'") | Set-Content $IndexPath
# zip it
& $uenv.BuildEnv.Zip a -tzip -r "$out\ui-docs.zip" "$src\Umbraco.Web.UI.Client\docs\api\*.*"
################ Do the c# docs
# Build the solution in debug mode
$SolutionPath = Join-Path -Path $src -ChildPath "umbraco.sln"
#$uenv.CompileUmbraco()
#restore nuget packages
$uenv.RestoreNuGet()
# run DocFx
$DocFx = $uenv.BuildEnv.DocFx
Write-Host "$DocFxJson"
& $DocFx metadata $DocFxJson
& $DocFx build $DocFxJson
# zip it
& $uenv.BuildEnv.Zip a -tzip -r "$out\csharp-docs.zip" $DocFxSiteOutput
+56 -3
View File
@@ -11,6 +11,11 @@
[Alias("loc")]
[switch] $local = $false,
# enable docfx
[Parameter(Mandatory=$false)]
[Alias("doc")]
[switch] $docfx = $false,
# keep the build directories, don't clear them
[Parameter(Mandatory=$false)]
[Alias("c")]
@@ -31,7 +36,7 @@
$ubuild = &"$PSScriptRoot\build-bootstrap.ps1"
if (-not $?) { return }
$ubuild.Boot($PSScriptRoot,
@{ Local = $local; },
@{ Local = $local; WithDocFx = $docfx },
@{ Continue = $continue })
if ($ubuild.OnError()) { return }
@@ -387,13 +392,13 @@
&$this.BuildEnv.NuGet Pack "$nuspecs\UmbracoCms.Core.nuspec" `
-Properties BuildTmp="$($this.BuildTemp)" `
-Version "$($this.Version.Semver.ToString())" `
-Symbols -Verbosity detailed -outputDirectory "$($this.BuildOutput)" > "$($this.BuildTemp)\nupack.cmscore.log"
-Symbols -SymbolPackageFormat snupkg -Verbosity detailed -outputDirectory "$($this.BuildOutput)" > "$($this.BuildTemp)\nupack.cmscore.log"
if (-not $?) { throw "Failed to pack NuGet UmbracoCms.Core." }
&$this.BuildEnv.NuGet Pack "$nuspecs\UmbracoCms.Web.nuspec" `
-Properties BuildTmp="$($this.BuildTemp)" `
-Version "$($this.Version.Semver.ToString())" `
-Symbols -Verbosity detailed -outputDirectory "$($this.BuildOutput)" > "$($this.BuildTemp)\nupack.cmsweb.log"
-Symbols -SymbolPackageFormat snupkg -Verbosity detailed -outputDirectory "$($this.BuildOutput)" > "$($this.BuildTemp)\nupack.cmsweb.log"
if (-not $?) { throw "Failed to pack NuGet UmbracoCms.Web." }
&$this.BuildEnv.NuGet Pack "$nuspecs\UmbracoCms.nuspec" `
@@ -424,6 +429,53 @@
Write-Host "Prepare Azure Gallery"
$this.CopyFile("$($this.SolutionRoot)\build\Azure\azuregalleryrelease.ps1", $this.BuildOutput)
})
$ubuild.DefineMethod("PrepareCSharpDocs",
{
Write-Host "Prepare C# Documentation"
$src = "$($this.SolutionRoot)\src"
$tmp = $this.BuildTemp
$out = $this.BuildOutput
$DocFxJson = Join-Path -Path $src "\ApiDocs\docfx.json"
$DocFxSiteOutput = Join-Path -Path $tmp "\_site\*.*"
#restore nuget packages
$this.RestoreNuGet()
# run DocFx
$DocFx = $this.BuildEnv.DocFx
& $DocFx metadata $DocFxJson
& $DocFx build $DocFxJson
# zip it
& $this.BuildEnv.Zip a -tzip -r "$out\csharp-docs.zip" $DocFxSiteOutput
})
$ubuild.DefineMethod("PrepareAngularDocs",
{
Write-Host "Prepare Angular Documentation"
$src = "$($this.SolutionRoot)\src"
$out = $this.BuildOutput
$this.CompileBelle()
"Moving to Umbraco.Web.UI.Client folder"
cd .\src\Umbraco.Web.UI.Client
"Generating the docs and waiting before executing the next commands"
& gulp docs | Out-Null
# change baseUrl
$BaseUrl = "https://our.umbraco.com/apidocs/v8/ui/"
$IndexPath = "./docs/api/index.html"
(Get-Content $IndexPath).replace('location.href.replace(rUrl, indexFile)', "`'" + $BaseUrl + "`'") | Set-Content $IndexPath
# zip it
& $this.BuildEnv.Zip a -tzip -r "$out\ui-docs.zip" "$src\Umbraco.Web.UI.Client\docs\api\*.*"
})
$ubuild.DefineMethod("Build",
{
@@ -456,6 +508,7 @@
if ($this.OnError()) { return }
$this.PostPackageHook()
if ($this.OnError()) { return }
Write-Host "Done"
})
+10 -24
View File
@@ -2,21 +2,20 @@
"metadata": [
{
"src": [
{
{
"src": "../",
"files": [
"Umbraco.Core/Umbraco.Core.csproj",
"Umbraco.Web/Umbraco.Web.csproj"
],
"exclude": [
"**/obj/**",
"**/bin/**",
"_site/**"
],
"cwd": "../src"
"**/bin/**"
]
}
],
"dest": "../apidocs/api",
"filter": "../apidocs/docfx.filter.yml"
"dest": "api",
"filter": "docfx.filter.yml"
}
],
"build": {
@@ -35,19 +34,7 @@
"*.md"
],
"exclude": [
"obj/**",
"_site/**"
]
}
],
"resource": [
{
"files": [
"images/**"
],
"exclude": [
"obj/**",
"_site/**"
"obj/**"
]
}
],
@@ -57,8 +44,7 @@
"**.md"
],
"exclude": [
"obj/**",
"_site/**"
"obj/**"
]
}
],
@@ -67,9 +53,9 @@
"_enableSearch": true,
"_disableContribution": false
},
"dest": "_site",
"dest": "../../build.tmp/_site",
"template": [
"default", "umbracotemplate"
]
}
}
}
+95 -38
View File
@@ -70,7 +70,23 @@ namespace Umbraco.Core.Composing
}
}
private IEnumerable<Type> PrepareComposerTypes()
internal IEnumerable<Type> PrepareComposerTypes()
{
var requirements = GetRequirements();
// only for debugging, this is verbose
//_logger.Debug<Composers>(GetComposersReport(requirements));
var sortedComposerTypes = SortComposers(requirements);
// bit verbose but should help for troubleshooting
//var text = "Ordered Composers: " + Environment.NewLine + string.Join(Environment.NewLine, sortedComposerTypes) + Environment.NewLine;
_logger.Debug<Composers>("Ordered Composers: {SortedComposerTypes}", sortedComposerTypes);
return sortedComposerTypes;
}
internal Dictionary<Type, List<Type>> GetRequirements(bool throwOnMissing = true)
{
// create a list, remove those that cannot be enabled due to runtime level
var composerTypeList = _composerTypes
@@ -89,25 +105,69 @@ namespace Umbraco.Core.Composing
// enable or disable composers
EnableDisableComposers(composerTypeList);
// sort the composers according to their dependencies
var requirements = new Dictionary<Type, List<Type>>();
foreach (var type in composerTypeList) requirements[type] = null;
foreach (var type in composerTypeList)
void GatherInterfaces<TAttribute>(Type type, Func<TAttribute, Type> getTypeInAttribute, HashSet<Type> iset, List<Type> set2)
where TAttribute : Attribute
{
GatherRequirementsFromRequireAttribute(type, composerTypeList, requirements);
GatherRequirementsFromRequiredByAttribute(type, composerTypeList, requirements);
foreach (var attribute in type.GetCustomAttributes<TAttribute>())
{
var typeInAttribute = getTypeInAttribute(attribute);
if (typeInAttribute != null && // if the attribute references a type ...
typeInAttribute.IsInterface && // ... which is an interface ...
typeof(IComposer).IsAssignableFrom(typeInAttribute) && // ... which implements IComposer ...
!iset.Contains(typeInAttribute)) // ... which is not already in the list
{
// add it to the new list
iset.Add(typeInAttribute);
set2.Add(typeInAttribute);
// add all its interfaces implementing IComposer
foreach (var i in typeInAttribute.GetInterfaces().Where(x => typeof(IComposer).IsAssignableFrom(x)))
{
iset.Add(i);
set2.Add(i);
}
}
}
}
// only for debugging, this is verbose
//_logger.Debug<Composers>(GetComposersReport(requirements));
// gather interfaces too
var interfaces = new HashSet<Type>(composerTypeList.SelectMany(x => x.GetInterfaces().Where(y => typeof(IComposer).IsAssignableFrom(y))));
composerTypeList.AddRange(interfaces);
var list1 = composerTypeList;
while (list1.Count > 0)
{
var list2 = new List<Type>();
foreach (var t in list1)
{
GatherInterfaces<ComposeAfterAttribute>(t, a => a.RequiredType, interfaces, list2);
GatherInterfaces<ComposeBeforeAttribute>(t, a => a.RequiringType, interfaces, list2);
}
composerTypeList.AddRange(list2);
list1 = list2;
}
// sort the composers according to their dependencies
var requirements = new Dictionary<Type, List<Type>>();
foreach (var type in composerTypeList)
requirements[type] = null;
foreach (var type in composerTypeList)
{
GatherRequirementsFromAfterAttribute(type, composerTypeList, requirements, throwOnMissing);
GatherRequirementsFromBeforeAttribute(type, composerTypeList, requirements);
}
return requirements;
}
internal IEnumerable<Type> SortComposers(Dictionary<Type, List<Type>> requirements)
{
// sort composers
var graph = new TopoGraph<Type, KeyValuePair<Type, List<Type>>>(kvp => kvp.Key, kvp => kvp.Value);
graph.AddItems(requirements);
List<Type> sortedComposerTypes;
try
{
sortedComposerTypes = graph.GetSortedItems().Select(x => x.Key).ToList();
sortedComposerTypes = graph.GetSortedItems().Select(x => x.Key).Where(x => !x.IsInterface).ToList();
}
catch (Exception e)
{
@@ -117,40 +177,37 @@ namespace Umbraco.Core.Composing
throw;
}
// bit verbose but should help for troubleshooting
//var text = "Ordered Composers: " + Environment.NewLine + string.Join(Environment.NewLine, sortedComposerTypes) + Environment.NewLine;
_logger.Debug<Composers>("Ordered Composers: {SortedComposerTypes}", sortedComposerTypes);
return sortedComposerTypes;
}
private static string GetComposersReport(Dictionary<Type, List<Type>> requirements)
internal static string GetComposersReport(Dictionary<Type, List<Type>> requirements)
{
var text = new StringBuilder();
text.AppendLine("Composers & Dependencies:");
text.AppendLine(" < compose before");
text.AppendLine(" > compose after");
text.AppendLine(" : implements");
text.AppendLine(" = depends");
text.AppendLine();
bool HasReq(IEnumerable<Type> types, Type type)
=> types.Any(x => type.IsAssignableFrom(x) && !x.IsInterface);
foreach (var kvp in requirements)
{
var type = kvp.Key;
text.AppendLine(type.FullName);
foreach (var attribute in type.GetCustomAttributes<ComposeAfterAttribute>())
text.AppendLine(" -> " + attribute.RequiredType + (attribute.Weak.HasValue
? (attribute.Weak.Value ? " (weak)" : (" (strong" + (requirements.ContainsKey(attribute.RequiredType) ? ", missing" : "") + ")"))
: ""));
foreach (var attribute in type.GetCustomAttributes<ComposeBeforeAttribute>())
text.AppendLine(" -< " + attribute.RequiringType);
foreach (var i in type.GetInterfaces())
{
text.AppendLine(" : " + i.FullName);
foreach (var attribute in i.GetCustomAttributes<ComposeAfterAttribute>())
text.AppendLine(" -> " + attribute.RequiredType + (attribute.Weak.HasValue
? (attribute.Weak.Value ? " (weak)" : (" (strong" + (requirements.ContainsKey(attribute.RequiredType) ? ", missing" : "") + ")"))
: ""));
foreach (var attribute in i.GetCustomAttributes<ComposeBeforeAttribute>())
text.AppendLine(" -< " + attribute.RequiringType);
var weak = !(attribute.RequiredType.IsInterface ? attribute.Weak == false : attribute.Weak != true);
text.AppendLine(" > " + attribute.RequiredType +
(weak ? " (weak" : " (strong") + (HasReq(requirements.Keys, attribute.RequiredType) ? ", found" : ", missing") + ")");
}
foreach (var attribute in type.GetCustomAttributes<ComposeBeforeAttribute>())
text.AppendLine(" < " + attribute.RequiringType);
foreach (var i in type.GetInterfaces())
text.AppendLine(" : " + i.FullName);
if (kvp.Value != null)
foreach (var t in kvp.Value)
text.AppendLine(" = " + t);
@@ -221,16 +278,16 @@ namespace Umbraco.Core.Composing
types.Remove(kvp.Key);
}
private static void GatherRequirementsFromRequireAttribute(Type type, ICollection<Type> types, IDictionary<Type, List<Type>> requirements)
private static void GatherRequirementsFromAfterAttribute(Type type, ICollection<Type> types, IDictionary<Type, List<Type>> requirements, bool throwOnMissing = true)
{
// get 'require' attributes
// these attributes are *not* inherited because we want to "custom-inherit" for interfaces only
var requireAttributes = type
var afterAttributes = type
.GetInterfaces().SelectMany(x => x.GetCustomAttributes<ComposeAfterAttribute>()) // those marking interfaces
.Concat(type.GetCustomAttributes<ComposeAfterAttribute>()); // those marking the composer
// what happens in case of conflicting attributes (different strong/weak for same type) is not specified.
foreach (var attr in requireAttributes)
foreach (var attr in afterAttributes)
{
if (attr.RequiredType == type) continue; // ignore self-requirements (+ exclude in implems, below)
@@ -238,13 +295,13 @@ namespace Umbraco.Core.Composing
// unless strong, and then require at least one enabled composer implementing that interface
if (attr.RequiredType.IsInterface)
{
var implems = types.Where(x => x != type && attr.RequiredType.IsAssignableFrom(x)).ToList();
var implems = types.Where(x => x != type && attr.RequiredType.IsAssignableFrom(x) && !x.IsInterface).ToList();
if (implems.Count > 0)
{
if (requirements[type] == null) requirements[type] = new List<Type>();
requirements[type].AddRange(implems);
}
else if (attr.Weak == false) // if explicitly set to !weak, is strong, else is weak
else if (attr.Weak == false && throwOnMissing) // if explicitly set to !weak, is strong, else is weak
throw new Exception($"Broken composer dependency: {type.FullName} -> {attr.RequiredType.FullName}.");
}
// requiring a class = require that the composer is enabled
@@ -256,28 +313,28 @@ namespace Umbraco.Core.Composing
if (requirements[type] == null) requirements[type] = new List<Type>();
requirements[type].Add(attr.RequiredType);
}
else if (attr.Weak != true) // if not explicitly set to weak, is strong
else if (attr.Weak != true && throwOnMissing) // if not explicitly set to weak, is strong
throw new Exception($"Broken composer dependency: {type.FullName} -> {attr.RequiredType.FullName}.");
}
}
}
private static void GatherRequirementsFromRequiredByAttribute(Type type, ICollection<Type> types, IDictionary<Type, List<Type>> requirements)
private static void GatherRequirementsFromBeforeAttribute(Type type, ICollection<Type> types, IDictionary<Type, List<Type>> requirements)
{
// get 'required' attributes
// these attributes are *not* inherited because we want to "custom-inherit" for interfaces only
var requiredAttributes = type
var beforeAttributes = type
.GetInterfaces().SelectMany(x => x.GetCustomAttributes<ComposeBeforeAttribute>()) // those marking interfaces
.Concat(type.GetCustomAttributes<ComposeBeforeAttribute>()); // those marking the composer
foreach (var attr in requiredAttributes)
foreach (var attr in beforeAttributes)
{
if (attr.RequiringType == type) continue; // ignore self-requirements (+ exclude in implems, below)
// required by an interface = by any enabled composer implementing this that interface
if (attr.RequiringType.IsInterface)
{
var implems = types.Where(x => x != type && attr.RequiringType.IsAssignableFrom(x)).ToList();
var implems = types.Where(x => x != type && attr.RequiringType.IsAssignableFrom(x) && !x.IsInterface).ToList();
foreach (var implem in implems)
{
if (requirements[implem] == null) requirements[implem] = new List<Type>();
@@ -6,30 +6,50 @@ namespace Umbraco.Core.Composing
/// <summary>
/// Provides a base class for collections of types.
/// </summary>
public abstract class TypeCollectionBuilderBase<TCollection, TConstraint> : ICollectionBuilder<TCollection, Type>
public abstract class TypeCollectionBuilderBase<TBuilder, TCollection, TConstraint> : ICollectionBuilder<TCollection, Type>
where TBuilder : TypeCollectionBuilderBase<TBuilder, TCollection, TConstraint>
where TCollection : class, IBuilderCollection<Type>
{
private readonly HashSet<Type> _types = new HashSet<Type>();
private Type Validate(Type type, string action)
protected abstract TBuilder This { get; }
private static Type Validate(Type type, string action)
{
if (!typeof(TConstraint).IsAssignableFrom(type))
throw new InvalidOperationException($"Cannot {action} type {type.FullName} as it does not inherit from/implement {typeof(TConstraint).FullName}.");
return type;
}
public void Add(Type type) => _types.Add(Validate(type, "add"));
public void Add<T>() => Add(typeof(T));
public void Add(IEnumerable<Type> types)
public TBuilder Add(Type type)
{
foreach (var type in types) Add(type);
_types.Add(Validate(type, "add"));
return This;
}
public void Remove(Type type) => _types.Remove(Validate(type, "remove"));
public TBuilder Add<T>()
{
Add(typeof(T));
return This;
}
public void Remove<T>() => Remove(typeof(T));
public TBuilder Add(IEnumerable<Type> types)
{
foreach (var type in types) Add(type);
return This;
}
public TBuilder Remove(Type type)
{
_types.Remove(Validate(type, "remove"));
return This;
}
public TBuilder Remove<T>()
{
Remove(typeof(T));
return This;
}
public TCollection CreateCollection(IFactory factory)
{
@@ -315,7 +315,7 @@ namespace Umbraco.Core.Configuration
var hash = hashString.GenerateHash();
var siteTemp = System.IO.Path.Combine(Environment.ExpandEnvironmentVariables("%temp%"), "UmbracoData", hash);
return _localTempPath = System.IO.Path.Combine(siteTemp, "umbraco.config");
return _localTempPath = siteTemp;
//case LocalTempStorage.Default:
//case LocalTempStorage.Unknown:
+13 -1
View File
@@ -10,6 +10,18 @@ namespace Umbraco.Core
///</summary>
public static class EnumerableExtensions
{
internal static bool HasDuplicates<T>(this IEnumerable<T> items, bool includeNull)
{
var hs = new HashSet<T>();
foreach (var item in items)
{
if ((item != null || includeNull) && !hs.Add(item))
return true;
}
return false;
}
/// <summary>
/// Wraps this object instance into an IEnumerable{T} consisting of a single item.
/// </summary>
@@ -100,7 +112,7 @@ namespace Umbraco.Core
}
}
/// <summary>
/// Returns true if all items in the other collection exist in this collection
/// </summary>
@@ -1,7 +1,11 @@
using System;
using System.Text;
using System.Web;
using Serilog;
using Serilog.Configuration;
using Serilog.Core;
using Serilog.Events;
using Serilog.Formatting;
using Serilog.Formatting.Compact;
using Umbraco.Core.Logging.Serilog.Enrichers;
@@ -9,6 +13,7 @@ namespace Umbraco.Core.Logging.Serilog
{
public static class LoggerConfigExtensions
{
private const string AppDomainId = "AppDomainId";
/// <summary>
/// This configures Serilog with some defaults
/// Such as adding ProcessID, Thread, AppDomain etc
@@ -28,14 +33,14 @@ namespace Umbraco.Core.Logging.Serilog
.Enrich.WithProcessId()
.Enrich.WithProcessName()
.Enrich.WithThreadId()
.Enrich.WithProperty("AppDomainId", AppDomain.CurrentDomain.Id)
.Enrich.WithProperty(AppDomainId, AppDomain.CurrentDomain.Id)
.Enrich.WithProperty("AppDomainAppId", HttpRuntime.AppDomainAppId.ReplaceNonAlphanumericChars(string.Empty))
.Enrich.WithProperty("MachineName", Environment.MachineName)
.Enrich.With<Log4NetLevelMapperEnricher>()
.Enrich.With<HttpSessionIdEnricher>()
.Enrich.With<HttpRequestNumberEnricher>()
.Enrich.With<HttpRequestIdEnricher>();
return logConfig;
}
@@ -50,15 +55,51 @@ namespace Umbraco.Core.Logging.Serilog
//Main .txt logfile - in similar format to older Log4Net output
//Ends with ..txt as Date is inserted before file extension substring
logConfig.WriteTo.File($@"{AppDomain.CurrentDomain.BaseDirectory}\App_Data\Logs\UmbracoTraceLog.{Environment.MachineName}..txt",
shared: true,
rollingInterval: RollingInterval.Day,
restrictedToMinimumLevel: minimumLevel,
retainedFileCountLimit: null, //Setting to null means we keep all files - default is 31 days
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss,fff} [P{ProcessId}/D{AppDomainId}/T{ThreadId}] {Log4NetLevel} {SourceContext} - {Message:lj}{NewLine}{Exception}");
shared: true,
rollingInterval: RollingInterval.Day,
restrictedToMinimumLevel: minimumLevel,
retainedFileCountLimit: null, //Setting to null means we keep all files - default is 31 days
outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss,fff} [P{ProcessId}/D{AppDomainId}/T{ThreadId}] {Log4NetLevel} {SourceContext} - {Message:lj}{NewLine}{Exception}");
return logConfig;
}
/// <remarks>
/// Used in config - If renamed or moved to other assembly the config file also has be updated.
/// </remarks>
public static LoggerConfiguration File(this LoggerSinkConfiguration configuration, ITextFormatter formatter,
string path,
LogEventLevel restrictedToMinimumLevel = LogEventLevel.Verbose,
LoggingLevelSwitch levelSwitch = null,
long? fileSizeLimitBytes = 1073741824,
TimeSpan? flushToDiskInterval = null,
RollingInterval rollingInterval = RollingInterval.Infinite,
bool rollOnFileSizeLimit = false,
int? retainedFileCountLimit = 31,
Encoding encoding = null
)
{
return configuration.Async(
asyncConfiguration => asyncConfiguration.Map(AppDomainId, (_,mapConfiguration) =>
mapConfiguration.File(
formatter,
path,
restrictedToMinimumLevel,
fileSizeLimitBytes,
levelSwitch,
buffered:true,
shared:false,
flushToDiskInterval,
rollingInterval,
rollOnFileSizeLimit,
retainedFileCountLimit,
encoding),
sinkMapCountLimit:0)
);
}
/// <summary>
/// Outputs a CLEF format JSON log at /App_Data/Logs/
/// </summary>
@@ -13,7 +13,7 @@ namespace Umbraco.Core.Logging.Serilog
///<summary>
/// Implements <see cref="ILogger"/> on top of Serilog.
///</summary>
public class SerilogLogger : ILogger
public class SerilogLogger : ILogger, IDisposable
{
/// <summary>
/// Initialize a new instance of the <see cref="SerilogLogger"/> class with a configuration file.
@@ -271,5 +271,10 @@ namespace Umbraco.Core.Logging.Serilog
{
LoggerFor(reporting).Verbose(messageTemplate, propertyValues);
}
public void Dispose()
{
Log.CloseAndFlush();
}
}
}
@@ -39,7 +39,7 @@ namespace Umbraco.Core.Logging.Viewer
for (var day = startDate.Date; day.Date <= endDate.Date; day = day.AddDays(1))
{
//Filename ending to search for (As could be multiple)
var filesToFind = $"*{day:yyyyMMdd}.json";
var filesToFind = GetSearchPattern(day);
var filesForCurrentDay = Directory.GetFiles(logDirectory, filesToFind);
@@ -52,6 +52,11 @@ namespace Umbraco.Core.Logging.Viewer
return logSizeAsMegabytes <= FileSizeCap;
}
private string GetSearchPattern(DateTime day)
{
return $"*{day:yyyyMMdd}*.json";
}
protected override IReadOnlyList<LogEvent> GetLogs(DateTimeOffset startDate, DateTimeOffset endDate, ILogFilter filter, int skip, int take)
{
var logs = new List<LogEvent>();
@@ -66,7 +71,7 @@ namespace Umbraco.Core.Logging.Viewer
for (var day = startDate.Date; day.Date <= endDate.Date; day = day.AddDays(1))
{
//Filename ending to search for (As could be multiple)
var filesToFind = $"*{day:yyyyMMdd}.json";
var filesToFind = GetSearchPattern(day);
var filesForCurrentDay = Directory.GetFiles(logDirectory, filesToFind);
+13
View File
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
namespace Umbraco.Core.Mapping
{
@@ -112,6 +113,18 @@ namespace Umbraco.Core.Mapping
}
*/
/// <summary>
/// Maps an enumerable of source objects to a new list of target objects.
/// </summary>
/// <typeparam name="TSourceElement">The type of the source objects.</typeparam>
/// <typeparam name="TTargetElement">The type of the target objects.</typeparam>
/// <param name="source">The source objects.</param>
/// <returns>A list containing the target objects.</returns>
public List<TTargetElement> MapEnumerable<TSourceElement, TTargetElement>(IEnumerable<TSourceElement> source)
{
return source.Select(Map<TSourceElement, TTargetElement>).ToList();
}
#endregion
}
}
+58 -12
View File
@@ -1,5 +1,6 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
@@ -29,11 +30,16 @@ namespace Umbraco.Core.Mapping
/// </remarks>
public class UmbracoMapper
{
private readonly Dictionary<Type, Dictionary<Type, Func<object, MapperContext, object>>> _ctors
= new Dictionary<Type, Dictionary<Type, Func<object, MapperContext, object>>>();
// note
//
// the outer dictionary *can* be modified, see GetCtor and GetMap, hence have to be ConcurrentDictionary
// the inner dictionaries are never modified and therefore can be simple Dictionary
private readonly Dictionary<Type, Dictionary<Type, Action<object, object, MapperContext>>> _maps
= new Dictionary<Type, Dictionary<Type, Action<object, object, MapperContext>>>();
private readonly ConcurrentDictionary<Type, Dictionary<Type, Func<object, MapperContext, object>>> _ctors
= new ConcurrentDictionary<Type, Dictionary<Type, Func<object, MapperContext, object>>>();
private readonly ConcurrentDictionary<Type, Dictionary<Type, Action<object, object, MapperContext>>> _maps
= new ConcurrentDictionary<Type, Dictionary<Type, Action<object, object, MapperContext>>>();
/// <summary>
/// Initializes a new instance of the <see cref="UmbracoMapper"/> class.
@@ -101,16 +107,12 @@ namespace Umbraco.Core.Mapping
private Dictionary<Type, Func<object, MapperContext, object>> DefineCtors(Type sourceType)
{
if (!_ctors.TryGetValue(sourceType, out var sourceCtor))
sourceCtor = _ctors[sourceType] = new Dictionary<Type, Func<object, MapperContext, object>>();
return sourceCtor;
return _ctors.GetOrAdd(sourceType, _ => new Dictionary<Type, Func<object, MapperContext, object>>());
}
private Dictionary<Type, Action<object, object, MapperContext>> DefineMaps(Type sourceType)
{
if (!_maps.TryGetValue(sourceType, out var sourceMap))
sourceMap = _maps[sourceType] = new Dictionary<Type, Action<object, object, MapperContext>>();
return sourceMap;
return _maps.GetOrAdd(sourceType, _ => new Dictionary<Type, Action<object, object, MapperContext>>());
}
#endregion
@@ -229,7 +231,7 @@ namespace Umbraco.Core.Mapping
if (ctor != null && map != null)
{
// register (for next time) and do it now (for this time)
object NCtor(object s, MapperContext c) => MapEnumerable<TTarget>((IEnumerable) s, targetGenericArg, ctor, map, c);
object NCtor(object s, MapperContext c) => MapEnumerableInternal<TTarget>((IEnumerable) s, targetGenericArg, ctor, map, c);
DefineCtors(sourceType)[targetType] = NCtor;
DefineMaps(sourceType)[targetType] = Identity;
return (TTarget) NCtor(source, context);
@@ -241,7 +243,7 @@ namespace Umbraco.Core.Mapping
throw new InvalidOperationException($"Don't know how to map {sourceType.FullName} to {targetType.FullName}.");
}
private TTarget MapEnumerable<TTarget>(IEnumerable source, Type targetGenericArg, Func<object, MapperContext, object> ctor, Action<object, object, MapperContext> map, MapperContext context)
private TTarget MapEnumerableInternal<TTarget>(IEnumerable source, Type targetGenericArg, Func<object, MapperContext, object> ctor, Action<object, object, MapperContext> map, MapperContext context)
{
var targetList = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(targetGenericArg));
@@ -326,6 +328,8 @@ namespace Umbraco.Core.Mapping
if (_ctors.TryGetValue(sourceType, out var sourceCtor) && sourceCtor.TryGetValue(targetType, out var ctor))
return ctor;
// we *may* run this more than once but it does not matter
ctor = null;
foreach (var (stype, sctors) in _ctors)
{
@@ -347,6 +351,8 @@ namespace Umbraco.Core.Mapping
if (_maps.TryGetValue(sourceType, out var sourceMap) && sourceMap.TryGetValue(targetType, out var map))
return map;
// we *may* run this more than once but it does not matter
map = null;
foreach (var (stype, smap) in _maps)
{
@@ -379,6 +385,46 @@ namespace Umbraco.Core.Mapping
throw new Exception("panic");
}
/// <summary>
/// Maps an enumerable of source objects to a new list of target objects.
/// </summary>
/// <typeparam name="TSourceElement">The type of the source objects.</typeparam>
/// <typeparam name="TTargetElement">The type of the target objects.</typeparam>
/// <param name="source">The source objects.</param>
/// <returns>A list containing the target objects.</returns>
public List<TTargetElement> MapEnumerable<TSourceElement, TTargetElement>(IEnumerable<TSourceElement> source)
{
return source.Select(Map<TSourceElement, TTargetElement>).ToList();
}
/// <summary>
/// Maps an enumerable of source objects to a new list of target objects.
/// </summary>
/// <typeparam name="TSourceElement">The type of the source objects.</typeparam>
/// <typeparam name="TTargetElement">The type of the target objects.</typeparam>
/// <param name="source">The source objects.</param>
/// <param name="f">A mapper context preparation method.</param>
/// <returns>A list containing the target objects.</returns>
public List<TTargetElement> MapEnumerable<TSourceElement, TTargetElement>(IEnumerable<TSourceElement> source, Action<MapperContext> f)
{
var context = new MapperContext(this);
f(context);
return source.Select(x => Map<TSourceElement, TTargetElement>(x, context)).ToList();
}
/// <summary>
/// Maps an enumerable of source objects to a new list of target objects.
/// </summary>
/// <typeparam name="TSourceElement">The type of the source objects.</typeparam>
/// <typeparam name="TTargetElement">The type of the target objects.</typeparam>
/// <param name="source">The source objects.</param>
/// <param name="context">A mapper context.</param>
/// <returns>A list containing the target objects.</returns>
public List<TTargetElement> MapEnumerable<TSourceElement, TTargetElement>(IEnumerable<TSourceElement> source, MapperContext context)
{
return source.Select(x => Map<TSourceElement, TTargetElement>(x, context)).ToList();
}
#endregion
}
}
@@ -83,17 +83,25 @@ namespace Umbraco.Core.Migrations.Expressions.Create
}
/// <inheritdoc />
public ICreateConstraintOnTableBuilder PrimaryKey()
public ICreateConstraintOnTableBuilder PrimaryKey() => PrimaryKey(true);
/// <inheritdoc />
public ICreateConstraintOnTableBuilder PrimaryKey(bool clustered)
{
var expression = new CreateConstraintExpression(_context, ConstraintType.PrimaryKey);
expression.Constraint.IsPrimaryKeyClustered = clustered;
return new CreateConstraintBuilder(expression);
}
/// <inheritdoc />
public ICreateConstraintOnTableBuilder PrimaryKey(string primaryKeyName)
public ICreateConstraintOnTableBuilder PrimaryKey(string primaryKeyName) => PrimaryKey(primaryKeyName, true);
/// <inheritdoc />
public ICreateConstraintOnTableBuilder PrimaryKey(string primaryKeyName, bool clustered)
{
var expression = new CreateConstraintExpression(_context, ConstraintType.PrimaryKey);
expression.Constraint.ConstraintName = primaryKeyName;
expression.Constraint.IsPrimaryKeyClustered = clustered;
return new CreateConstraintBuilder(expression);
}
@@ -19,7 +19,7 @@ namespace Umbraco.Core.Migrations.Expressions.Create.Expressions
var constraintType = (Constraint.IsPrimaryKeyConstraint) ? "PRIMARY KEY" : "UNIQUE";
if (Constraint.IsPrimaryKeyConstraint && SqlSyntax.SupportsClustered())
constraintType += " CLUSTERED";
constraintType += Constraint.IsPrimaryKeyClustered ? " CLUSTERED" : " NONCLUSTERED";
if (Constraint.IsNonUniqueConstraint)
constraintType = string.Empty;
@@ -68,6 +68,16 @@ namespace Umbraco.Core.Migrations.Expressions.Create
/// </summary>
ICreateConstraintOnTableBuilder PrimaryKey(string primaryKeyName);
/// <summary>
/// Builds a Create Primary Key expression.
/// </summary>
ICreateConstraintOnTableBuilder PrimaryKey(bool clustered);
/// <summary>
/// Builds a Create Primary Key expression.
/// </summary>
ICreateConstraintOnTableBuilder PrimaryKey(string primaryKeyName, bool clustered);
/// <summary>
/// Builds a Create Unique Constraint expression.
/// </summary>
@@ -226,6 +226,8 @@ namespace Umbraco.Core.Migrations.Install
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 32, UniqueId = 32.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastLockoutDate, Name = Constants.Conventions.Member.LastLockoutDateLabel, SortOrder = 4, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 33, UniqueId = 33.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastLoginDate, Name = Constants.Conventions.Member.LastLoginDateLabel, SortOrder = 5, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 34, UniqueId = 34.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = 11, Alias = Constants.Conventions.Member.LastPasswordChangeDate, Name = Constants.Conventions.Member.LastPasswordChangeDateLabel, SortOrder = 6, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte) ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 35, UniqueId = 35.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = null, Alias = Constants.Conventions.Member.PasswordQuestion, Name = Constants.Conventions.Member.PasswordQuestionLabel, SortOrder = 7, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte)ContentVariation.Nothing });
_database.Insert(Constants.DatabaseSchema.Tables.PropertyType, "id", false, new PropertyTypeDto { Id = 36, UniqueId = 36.ToGuid(), DataTypeId = Constants.DataTypes.LabelDateTime, ContentTypeId = 1044, PropertyTypeGroupId = null, Alias = Constants.Conventions.Member.PasswordAnswer, Name = Constants.Conventions.Member.PasswordAnswerLabel, SortOrder = 8, Mandatory = false, ValidationRegExp = null, Description = null, Variations = (byte)ContentVariation.Nothing });
}
@@ -6,6 +6,7 @@ using Umbraco.Core.Migrations.Upgrade.V_7_12_0;
using Umbraco.Core.Migrations.Upgrade.V_7_14_0;
using Umbraco.Core.Migrations.Upgrade.V_8_0_0;
using Umbraco.Core.Migrations.Upgrade.V_8_0_1;
using Umbraco.Core.Migrations.Upgrade.V_8_1_0;
namespace Umbraco.Core.Migrations.Upgrade
{
@@ -139,6 +140,7 @@ namespace Umbraco.Core.Migrations.Upgrade
To<RenameLabelAndRichTextPropertyEditorAliases>("{E0CBE54D-A84F-4A8F-9B13-900945FD7ED9}");
To<MergeDateAndDateTimePropertyEditor>("{78BAF571-90D0-4D28-8175-EF96316DA789}");
To<ChangeNuCacheJsonFormat>("{80C0A0CB-0DD5-4573-B000-C4B7C313C70D}");
To<ConvertTinyMceAndGridMediaUrlsToLocalLink>("{B69B6E8C-A769-4044-A27E-4A4E18D1645A}");
//FINAL
@@ -79,7 +79,8 @@ HAVING COUNT(v2.id) <> 1").Any())
// transform column versionId from guid to integer (contentVersion.id)
if (ColumnType(PreTables.PropertyData, "versionId") == "uniqueidentifier")
{
Database.Execute($"ALTER TABLE {PreTables.PropertyData} ADD COLUMN versionId2 INT NULL;");
Alter.Table(PreTables.PropertyData).AddColumn("versionId2").AsInt32().Nullable().Do();
// SQLCE does not support UPDATE...FROM
var temp = Database.Fetch<dynamic>($"SELECT id, versionId FROM {PreTables.ContentVersion}");
foreach (var t in temp)
@@ -0,0 +1,89 @@
using System;
using System.Linq;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Umbraco.Core.Migrations.PostMigrations;
using Umbraco.Core.Persistence;
using Umbraco.Core.Persistence.Dtos;
using Umbraco.Core.Services;
namespace Umbraco.Core.Migrations.Upgrade.V_8_1_0
{
public class ConvertTinyMceAndGridMediaUrlsToLocalLink : MigrationBase
{
private readonly IMediaService _mediaService;
public ConvertTinyMceAndGridMediaUrlsToLocalLink(IMigrationContext context, IMediaService mediaService) : base(context)
{
_mediaService = mediaService ?? throw new ArgumentNullException(nameof(mediaService));
}
public override void Migrate()
{
var mediaLinkPattern = new Regex(
@"(<a[^>]*href="")(\/ media[^""\?]*)([^>]*>)",
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace);
var sqlPropertyData = Sql()
.Select<PropertyDataDto>(x => x.Id, x => x.TextValue)
.AndSelect<DataTypeDto>(x => x.EditorAlias)
.From<PropertyDataDto>()
.InnerJoin<PropertyTypeDto>().On<PropertyDataDto, PropertyTypeDto>((left, right) => left.PropertyTypeId == right.Id)
.InnerJoin<DataTypeDto>().On<PropertyTypeDto, DataTypeDto>((left, right) => left.DataTypeId == right.NodeId)
.Where<DataTypeDto>(x =>
x.EditorAlias == Constants.PropertyEditors.Aliases.TinyMce ||
x.EditorAlias == Constants.PropertyEditors.Aliases.Grid);
var properties = Database.Fetch<PropertyDataDto>(sqlPropertyData);
foreach (var property in properties)
{
var value = property.TextValue;
if (string.IsNullOrWhiteSpace(value)) continue;
if (property.PropertyTypeDto.DataTypeDto.EditorAlias == Constants.PropertyEditors.Aliases.Grid)
{
var obj = JsonConvert.DeserializeObject<JObject>(value);
var allControls = obj.SelectTokens("$.sections..rows..areas..controls");
foreach (var control in allControls.SelectMany(c => c))
{
var controlValue = control["value"];
if (controlValue.Type == JTokenType.String)
{
control["value"] = UpdateMediaUrls(mediaLinkPattern, controlValue.Value<string>());
}
}
property.TextValue = JsonConvert.SerializeObject(obj);
}
else
{
property.TextValue = UpdateMediaUrls(mediaLinkPattern, value);
}
Database.Update(property, x => x.TextValue);
}
Context.AddPostMigration<RebuildPublishedSnapshot>();
}
private string UpdateMediaUrls(Regex mediaLinkPattern, string value)
{
return mediaLinkPattern.Replace(value, match =>
{
// match groups:
// - 1 = from the beginning of the a tag until href attribute value begins
// - 2 = the href attribute value excluding the querystring (if present)
// - 3 = anything after group 2 until the a tag is closed
var href = match.Groups[2].Value;
var media = _mediaService.GetMediaByPath(href);
return media == null
? match.Value
: $"{match.Groups[1].Value}/{{localLink:{media.GetUdi()}}}{match.Groups[3].Value}";
});
}
}
}
+19 -3
View File
@@ -95,6 +95,21 @@ namespace Umbraco.Core.Models
protected void PropertyTypesChanged(object sender, NotifyCollectionChangedEventArgs e)
{
//enable this to detect duplicate property aliases. We do want this, however making this change in a
//patch release might be a little dangerous
////detect if there are any duplicate aliases - this cannot be allowed
//if (e.Action == NotifyCollectionChangedAction.Add
// || e.Action == NotifyCollectionChangedAction.Replace)
//{
// var allAliases = _noGroupPropertyTypes.Concat(PropertyGroups.SelectMany(x => x.PropertyTypes)).Select(x => x.Alias);
// if (allAliases.HasDuplicates(false))
// {
// var newAliases = string.Join(", ", e.NewItems.Cast<PropertyType>().Select(x => x.Alias));
// throw new InvalidOperationException($"Other property types already exist with the aliases: {newAliases}");
// }
//}
OnPropertyChanged(nameof(PropertyTypes));
}
@@ -388,15 +403,16 @@ namespace Umbraco.Core.Models
var group = PropertyGroups[propertyGroupName];
if (group == null) return;
// re-assign the group's properties to no group
// first remove the group
PropertyGroups.RemoveItem(propertyGroupName);
// Then re-assign the group's properties to no group
foreach (var property in group.PropertyTypes)
{
property.PropertyGroupId = null;
_noGroupPropertyTypes.Add(property);
}
// actually remove the group
PropertyGroups.RemoveItem(propertyGroupName);
OnPropertyChanged(nameof(PropertyGroups));
}
@@ -15,7 +15,7 @@ namespace Umbraco.Core.Models
public class PropertyCollection : KeyedCollection<string, Property>, INotifyCollectionChanged, IDeepCloneable
{
private readonly object _addLocker = new object();
internal Action OnAdd;
internal Func<Property, bool> AdditionValidator { get; set; }
/// <summary>
@@ -49,10 +49,12 @@ namespace Umbraco.Core.Models
/// </summary>
internal void Reset(IEnumerable<Property> properties)
{
//collection events will be raised in each of these calls
Clear();
//collection events will be raised in each of these calls
foreach (var property in properties)
Add(property);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
/// <summary>
@@ -60,8 +62,9 @@ namespace Umbraco.Core.Models
/// </summary>
protected override void SetItem(int index, Property property)
{
var oldItem = index >= 0 ? this[index] : property;
base.SetItem(index, property);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, property, index));
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, property, oldItem));
}
/// <summary>
@@ -120,10 +123,8 @@ namespace Umbraco.Core.Models
}
}
//collection events will be raised in InsertItem with Add
base.Add(property);
OnAdd?.Invoke();
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, property));
}
}
@@ -19,9 +19,6 @@ namespace Umbraco.Core.Models
{
private readonly ReaderWriterLockSlim _addLocker = new ReaderWriterLockSlim();
// TODO: this doesn't seem to be used anywhere
internal Action OnAdd;
internal PropertyGroupCollection()
{ }
@@ -37,16 +34,19 @@ namespace Umbraco.Core.Models
/// <remarks></remarks>
internal void Reset(IEnumerable<PropertyGroup> groups)
{
//collection events will be raised in each of these calls
Clear();
//collection events will be raised in each of these calls
foreach (var group in groups)
Add(group);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
protected override void SetItem(int index, PropertyGroup item)
{
var oldItem = index >= 0 ? this[index] : item;
base.SetItem(index, item);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index));
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, item, oldItem));
}
protected override void RemoveItem(int index)
@@ -84,6 +84,7 @@ namespace Umbraco.Core.Models
if (keyExists)
throw new Exception($"Naming conflict: Changing the name of PropertyGroup '{item.Name}' would result in duplicates");
//collection events will be raised in SetItem
SetItem(IndexOfKey(item.Id), item);
return;
}
@@ -96,16 +97,14 @@ namespace Umbraco.Core.Models
var exists = Contains(key);
if (exists)
{
//collection events will be raised in SetItem
SetItem(IndexOfKey(key), item);
return;
}
}
}
//collection events will be raised in InsertItem
base.Add(item);
OnAdd?.Invoke();
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
}
finally
{
@@ -19,9 +19,6 @@ namespace Umbraco.Core.Models
[IgnoreDataMember]
private readonly ReaderWriterLockSlim _addLocker = new ReaderWriterLockSlim();
// TODO: This doesn't seem to be used
[IgnoreDataMember]
internal Action OnAdd;
internal PropertyTypeCollection(bool supportsPublishing)
{
@@ -43,36 +40,44 @@ namespace Umbraco.Core.Models
/// <remarks></remarks>
internal void Reset(IEnumerable<PropertyType> properties)
{
//collection events will be raised in each of these calls
Clear();
//collection events will be raised in each of these calls
foreach (var property in properties)
Add(property);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
Add(property);
}
protected override void SetItem(int index, PropertyType item)
{
item.SupportsPublishing = SupportsPublishing;
base.SetItem(index, item);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index));
var oldItem = index >= 0 ? this[index] : item;
base.SetItem(index, item);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, item, oldItem));
item.PropertyChanged += Item_PropertyChanged;
}
protected override void RemoveItem(int index)
{
var removed = this[index];
base.RemoveItem(index);
removed.PropertyChanged -= Item_PropertyChanged;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, removed));
}
protected override void InsertItem(int index, PropertyType item)
{
item.SupportsPublishing = SupportsPublishing;
base.InsertItem(index, item);
base.InsertItem(index, item);
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
item.PropertyChanged += Item_PropertyChanged;
}
protected override void ClearItems()
{
base.ClearItems();
foreach (var item in this)
item.PropertyChanged -= Item_PropertyChanged;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
@@ -91,6 +96,7 @@ namespace Umbraco.Core.Models
var exists = Contains(key);
if (exists)
{
//collection events will be raised in SetItem
SetItem(IndexOfKey(key), item);
return;
}
@@ -103,10 +109,8 @@ namespace Umbraco.Core.Models
item.SortOrder = this.Max(x => x.SortOrder) + 1;
}
//collection events will be raised in InsertItem
base.Add(item);
OnAdd?.Invoke();
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item));
}
finally
{
@@ -115,6 +119,17 @@ namespace Umbraco.Core.Models
}
}
/// <summary>
/// Occurs when a property changes on a PropertyType that exists in this collection
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Item_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
var propType = (PropertyType)sender;
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, propType, propType));
}
/// <summary>
/// Determines whether this collection contains a <see cref="Property"/> whose alias matches the specified PropertyType.
/// </summary>
@@ -18,5 +18,6 @@ namespace Umbraco.Core.Persistence.DatabaseModelDefinitions
public string ConstraintName { get; set; }
public string TableName { get; set; }
public ICollection<string> Columns = new HashSet<string>();
public bool IsPrimaryKeyClustered { get; set; }
}
}
@@ -379,6 +379,20 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
return "variantName";
}
// content type alias is invariant
if(ordering.OrderBy.InvariantEquals("contentTypeAlias"))
{
var joins = Sql()
.InnerJoin<ContentTypeDto>("ctype").On<ContentDto, ContentTypeDto>((content, contentType) => content.ContentTypeId == contentType.NodeId, aliasRight: "ctype");
// see notes in ApplyOrdering: the field MUST be selected + aliased
sql = Sql(InsertBefore(sql, "FROM", ", " + SqlSyntax.GetFieldName<ContentTypeDto>(x => x.Alias, "ctype") + " AS ordering "), sql.Arguments);
sql = InsertJoins(sql, joins);
return "ordering";
}
// previously, we'd accept anything and just sanitize it - not anymore
throw new NotSupportedException($"Ordering by {ordering.OrderBy} not supported.");
}
@@ -240,6 +240,25 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
propertyIx++;
}
contentType.NoGroupPropertyTypes = noGroupPropertyTypes;
// ensure builtin properties
if (contentType is MemberType memberType)
{
// ensure that the group exists (ok if it already exists)
memberType.AddPropertyGroup(Constants.Conventions.Member.StandardPropertiesGroupName);
// ensure that property types exist (ok if they already exist)
foreach (var (alias, propertyType) in builtinProperties)
{
var added = memberType.AddPropertyType(propertyType, Constants.Conventions.Member.StandardPropertiesGroupName);
if (added)
{
var access = new MemberTypePropertyProfileAccess(false, false, false);
memberType.MemberTypePropertyTypes[alias] = access;
}
}
}
}
}
@@ -264,7 +283,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
if (contentType is MemberType memberType)
{
var access = new MemberTypePropertyProfileAccess(dto.ViewOnProfile, dto.CanEdit, dto.IsSensitive);
memberType.MemberTypePropertyTypes.Add(dto.Alias, access);
memberType.MemberTypePropertyTypes[dto.Alias] = access;
}
return new PropertyType(dto.DataTypeDto.EditorAlias, storageType, readonlyStorageType, dto.Alias)
@@ -13,12 +13,15 @@ namespace Umbraco.Core.PropertyEditors
/// </summary>
public class ConfigurationEditor : IConfigurationEditor
{
private IDictionary<string, object> _defaultConfiguration;
/// <summary>
/// Initializes a new instance of the <see cref="ConfigurationEditor"/> class.
/// </summary>
public ConfigurationEditor()
{
Fields = new List<ConfigurationField>();
_defaultConfiguration = new Dictionary<string, object>();
}
/// <summary>
@@ -61,7 +64,10 @@ namespace Umbraco.Core.PropertyEditors
/// <inheritdoc />
[JsonProperty("defaultConfig")]
public virtual IDictionary<string, object> DefaultConfiguration => new Dictionary<string, object>();
public virtual IDictionary<string, object> DefaultConfiguration {
get => _defaultConfiguration;
internal set => _defaultConfiguration = value;
}
/// <inheritdoc />
public virtual object DefaultConfigurationObject => DefaultConfiguration;
@@ -173,7 +173,13 @@ namespace Umbraco.Core.PropertyEditors
/// </summary>
protected virtual IConfigurationEditor CreateConfigurationEditor()
{
return new ConfigurationEditor();
var editor = new ConfigurationEditor();
// pass the default configuration if this is not a property value editor
if((Type & EditorType.PropertyValue) == 0)
{
editor.DefaultConfiguration = _defaultConfiguration;
}
return editor;
}
/// <summary>
@@ -1,8 +1,8 @@
namespace Umbraco.Core.PropertyEditors
{
internal class DropDownFlexibleConfiguration : ValueListConfiguration
public class DropDownFlexibleConfiguration : ValueListConfiguration
{
[ConfigurationField("multiple", "Enable multiple choice", "boolean", Description = "When checked, the dropdown will be a select multiple / combo box style dropdown.")]
public bool Multiple { get; set; }
}
}
}
@@ -9,18 +9,18 @@
public bool EnableRange { get; set; }
[ConfigurationField("initVal1", "Initial value", "number")]
public int InitialValue { get; set; }
public decimal InitialValue { get; set; }
[ConfigurationField("initVal2", "Initial value 2", "number", Description = "Used when range is enabled")]
public int InitialValue2 { get; set; }
public decimal InitialValue2 { get; set; }
[ConfigurationField("minVal", "Minimum value", "number")]
public int MinimumValue { get; set; }
public decimal MinimumValue { get; set; }
[ConfigurationField("maxVal", "Maximum value", "number")]
public int MaximumValue { get; set; }
public decimal MaximumValue { get; set; }
[ConfigurationField("step", "Step increments", "number")]
public int StepIncrements { get; set; }
public decimal StepIncrements { get; set; }
}
}
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using Umbraco.Core.Models;
using Umbraco.Core.Models.Membership;
using Umbraco.Core.Persistence.DatabaseModelDefinitions;
@@ -315,8 +316,16 @@ namespace Umbraco.Core.Services
/// <summary>
/// Empties the recycle bin.
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("Use EmptyRecycleBin with explicit indication of user ID instead")]
OperationResult EmptyRecycleBin();
/// <summary>
/// Empties the Recycle Bin by deleting all <see cref="IContent"/> that resides in the bin
/// </summary>
/// <param name="userId">Optional Id of the User emptying the Recycle Bin</param>
OperationResult EmptyRecycleBin(int userId = Constants.Security.SuperUserId);
/// <summary>
/// Sorts documents.
/// </summary>
@@ -162,8 +162,16 @@ namespace Umbraco.Core.Services
/// <summary>
/// Empties the Recycle Bin by deleting all <see cref="IMedia"/> that resides in the bin
/// </summary>
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("Use EmptyRecycleBin with explicit indication of user ID instead")]
OperationResult EmptyRecycleBin();
/// <summary>
/// Empties the Recycle Bin by deleting all <see cref="IMedia"/> that resides in the bin
/// </summary>
/// <param name="userId">Optional Id of the User emptying the Recycle Bin</param>
OperationResult EmptyRecycleBin(int userId = Constants.Security.SuperUserId);
/// <summary>
/// Deletes all media of specified type. All children of deleted media is moved to Recycle Bin.
/// </summary>
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
using Umbraco.Core.Events;
@@ -1888,9 +1889,8 @@ namespace Umbraco.Core.Services.Implement
content.ParentId = parentId;
// get the level delta (old pos to new pos)
var levelDelta = parent == null
? 1 - content.Level + (parentId == Constants.System.RecycleBinContent ? 1 : 0)
: parent.Level + 1 - content.Level;
// note that recycle bin (id:-20) level is 0!
var levelDelta = 1 - content.Level + (parent?.Level ?? 0);
var paths = new Dictionary<int, string>();
@@ -1939,7 +1939,14 @@ namespace Umbraco.Core.Services.Implement
/// <summary>
/// Empties the Recycle Bin by deleting all <see cref="IContent"/> that resides in the bin
/// </summary>
public OperationResult EmptyRecycleBin()
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("Use EmptyRecycleBin with explicit indication of user ID instead")]
public OperationResult EmptyRecycleBin() => EmptyRecycleBin(Constants.Security.SuperUserId);
/// <summary>
/// Empties the Recycle Bin by deleting all <see cref="IContent"/> that resides in the bin
/// </summary>
public OperationResult EmptyRecycleBin(int userId = Constants.Security.SuperUserId)
{
var nodeObjectType = Constants.ObjectTypes.Document;
var deleted = new List<IContent>();
@@ -1974,7 +1981,7 @@ namespace Umbraco.Core.Services.Implement
recycleBinEventArgs.RecycleBinEmptiedSuccessfully = true; // oh my?!
scope.Events.Dispatch(EmptiedRecycleBin, this, recycleBinEventArgs);
scope.Events.Dispatch(TreeChanged, this, deleted.Select(x => new TreeChange<IContent>(x, TreeChangeTypes.Remove)).ToEventArgs());
Audit(AuditType.Delete, 0, Constants.System.RecycleBinContent, "Recycle bin emptied");
Audit(AuditType.Delete, userId, Constants.System.RecycleBinContent, "Recycle bin emptied");
scope.Complete();
}
@@ -2878,25 +2885,16 @@ namespace Umbraco.Core.Services.Implement
{
foreach (var property in blueprint.Properties)
{
if (property.PropertyType.VariesByCulture())
{
content.SetValue(property.Alias, property.GetValue(culture), culture);
}
else
{
content.SetValue(property.Alias, property.GetValue());
}
var propertyCulture = property.PropertyType.VariesByCulture() ? culture : null;
content.SetValue(property.Alias, property.GetValue(propertyCulture), propertyCulture);
}
content.Name = blueprint.Name;
if (!string.IsNullOrEmpty(culture))
{
content.SetCultureInfo(culture, blueprint.GetCultureName(culture), now);
}
}
return content;
}
@@ -1034,10 +1034,12 @@ namespace Umbraco.Core.Services.Implement
//strip the @inherits if it's there
snippetContent = StripPartialViewHeader(snippetContent);
//Update Model.Content. to be Model. when used as PartialView
//Update Model.Content to be Model when used as PartialView
if (partialViewType == PartialViewType.PartialView)
{
snippetContent = snippetContent.Replace("Model.Content.", "Model.");
snippetContent = snippetContent
.Replace("Model.Content.", "Model.")
.Replace("(Model.Content)", "(Model)");
}
var content = $"{partialViewHeader}{Environment.NewLine}{snippetContent}";
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO;
using System.Linq;
@@ -289,7 +290,7 @@ namespace Umbraco.Core.Services.Implement
scope.Events.Dispatch(Saved, this, saveEventArgs);
scope.Events.Dispatch(TreeChanged, this, new TreeChange<IMedia>(media, TreeChangeTypes.RefreshNode).ToEventArgs());
}
if (withIdentity == false)
return;
@@ -716,7 +717,7 @@ namespace Umbraco.Core.Services.Implement
#endregion
#region Delete
/// <summary>
/// Permanently deletes an <see cref="IMedia"/> object
/// </summary>
@@ -975,9 +976,8 @@ namespace Umbraco.Core.Services.Implement
media.ParentId = parentId;
// get the level delta (old pos to new pos)
var levelDelta = parent == null
? 1 - media.Level + (parentId == Constants.System.RecycleBinMedia ? 1 : 0)
: parent.Level + 1 - media.Level;
// note that recycle bin (id:-20) level is 0!
var levelDelta = 1 - media.Level + (parent?.Level ?? 0);
var paths = new Dictionary<int, string>();
@@ -1024,7 +1024,15 @@ namespace Umbraco.Core.Services.Implement
/// <summary>
/// Empties the Recycle Bin by deleting all <see cref="IMedia"/> that resides in the bin
/// </summary>
public OperationResult EmptyRecycleBin()
[EditorBrowsable(EditorBrowsableState.Never)]
[Obsolete("Use EmptyRecycleBin with explicit indication of user ID instead")]
public OperationResult EmptyRecycleBin() => EmptyRecycleBin(Constants.Security.SuperUserId);
/// <summary>
/// Empties the Recycle Bin by deleting all <see cref="IMedia"/> that resides in the bin
/// </summary>
/// <param name="userId">Optional Id of the User emptying the Recycle Bin</param>
public OperationResult EmptyRecycleBin(int userId = Constants.Security.SuperUserId)
{
var nodeObjectType = Constants.ObjectTypes.Media;
var deleted = new List<IMedia>();
@@ -1063,7 +1071,7 @@ namespace Umbraco.Core.Services.Implement
args.CanCancel = false;
scope.Events.Dispatch(EmptiedRecycleBin, this, args);
scope.Events.Dispatch(TreeChanged, this, deleted.Select(x => new TreeChange<IMedia>(x, TreeChangeTypes.Remove)).ToEventArgs());
Audit(AuditType.Delete, 0, Constants.System.RecycleBinMedia, "Empty Media recycle bin");
Audit(AuditType.Delete, userId, Constants.System.RecycleBinMedia, "Empty Media recycle bin");
scope.Complete();
}
+7
View File
@@ -55,6 +55,12 @@
</ItemGroup>
<ItemGroup>
<!-- note: NuGet deals with transitive references now -->
<PackageReference Include="Serilog.Sinks.Async">
<Version>1.3.0</Version>
</PackageReference>
<PackageReference Include="Serilog.Sinks.Map">
<Version>1.0.0</Version>
</PackageReference>
<PackageReference Include="Umbraco.Code">
<Version>1.0.5</Version>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
@@ -219,6 +225,7 @@
<Compile Include="Mapping\MapDefinitionCollectionBuilder.cs" />
<Compile Include="Mapping\IMapDefinition.cs" />
<Compile Include="Mapping\UmbracoMapper.cs" />
<Compile Include="Migrations\Upgrade\V_8_1_0\ConvertTinyMceAndGridMediaUrlsToLocalLink.cs" />
<Compile Include="Models\CultureImpact.cs" />
<Compile Include="Models\PublishedContent\ILivePublishedModelFactory.cs" />
<Compile Include="Persistence\Dtos\PropertyTypeCommonDto.cs" />
@@ -159,6 +159,7 @@ namespace Umbraco.Tests.Cache
TestObjects.GetUmbracoSettings(),
TestObjects.GetGlobalSettings(),
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
Mock.Of<IUserService>());
// just assert it does not throw
@@ -81,6 +81,7 @@ namespace Umbraco.Tests.Cache.PublishedCache
new WebSecurity(_httpContextFactory.HttpContext, Current.Services.UserService, globalSettings),
umbracoSettings,
Enumerable.Empty<IUrlProvider>(),
Enumerable.Empty<IMediaUrlProvider>(),
globalSettings,
new TestVariationContextAccessor());
@@ -4,6 +4,7 @@ using System.Linq;
using Moq;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Cache;
using Umbraco.Core.Compose;
using Umbraco.Core.Composing;
using Umbraco.Core.IO;
@@ -299,11 +300,19 @@ namespace Umbraco.Tests.Components
composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
Composed.Clear();
Assert.Throws<Exception>(() => composers.Compose());
Console.WriteLine("throws:");
composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
var requirements = composers.GetRequirements(false);
Console.WriteLine(Composers.GetComposersReport(requirements));
types = new[] { typeof(Composer2) };
composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
Composed.Clear();
Assert.Throws<Exception>(() => composers.Compose());
Console.WriteLine("throws:");
composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
requirements = composers.GetRequirements(false);
Console.WriteLine(Composers.GetComposersReport(requirements));
types = new[] { typeof(Composer12) };
composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
@@ -349,6 +358,25 @@ namespace Umbraco.Tests.Components
Assert.AreEqual(typeof(Composer27), Composed[1]);
}
[Test]
public void AllComposers()
{
var typeLoader = new TypeLoader(AppCaches.Disabled.RuntimeCache, IOHelper.MapPath("~/App_Data/TEMP"), Mock.Of<IProfilingLogger>());
var register = MockRegister();
var composition = new Composition(register, typeLoader, Mock.Of<IProfilingLogger>(), MockRuntimeState(RuntimeLevel.Run));
var types = typeLoader.GetTypes<IComposer>().Where(x => x.FullName.StartsWith("Umbraco.Core.") || x.FullName.StartsWith("Umbraco.Web"));
var composers = new Composers(composition, types, Mock.Of<IProfilingLogger>());
var requirements = composers.GetRequirements();
var report = Composers.GetComposersReport(requirements);
Console.WriteLine(report);
var composerTypes = composers.SortComposers(requirements);
foreach (var type in composerTypes)
Console.WriteLine(type);
}
#region Compothings
public class TestComposerBase : IComposer
@@ -27,10 +27,7 @@ namespace Umbraco.Tests.Composing
public void Initialize()
{
// this ensures it's reset
_typeLoader = new TypeLoader(NoAppCache.Instance, IOHelper.MapPath("~/App_Data/TEMP"), new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>()));
foreach (var file in Directory.GetFiles(IOHelper.MapPath(SystemDirectories.TempData.EnsureEndsWith('/') + "TypesCache")))
File.Delete(file);
_typeLoader = new TypeLoader(NoAppCache.Instance, IOHelper.MapPath("~/App_Data/TEMP"), new ProfilingLogger(Mock.Of<ILogger>(), Mock.Of<IProfiler>()), false);
// for testing, we'll specify which assemblies are scanned for the PluginTypeResolver
// TODO: Should probably update this so it only searches this assembly and add custom types to be found
@@ -381,6 +381,9 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache
}
}
public override IPublishedContent GetById(bool preview, Udi nodeId)
=> throw new NotSupportedException();
public override bool HasById(bool preview, int contentId)
{
return GetXml(preview).CreateNavigator().MoveToId(contentId.ToString(CultureInfo.InvariantCulture));
@@ -97,6 +97,9 @@ namespace Umbraco.Tests.LegacyXmlPublishedCache
throw new NotImplementedException();
}
public override IPublishedContent GetById(bool preview, Udi nodeId)
=> throw new NotSupportedException();
public override bool HasById(bool preview, int contentId)
{
return GetUmbracoMedia(contentId) != null;
+125 -11
View File
@@ -1,7 +1,11 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using NUnit.Framework;
using Umbraco.Core.Mapping;
using Umbraco.Core.Models;
using Umbraco.Web.Models.ContentEditing;
namespace Umbraco.Tests.Mapping
{
@@ -11,11 +15,11 @@ namespace Umbraco.Tests.Mapping
[Test]
public void SimpleMap()
{
var profiles = new MapDefinitionCollection(new IMapDefinition[]
var definitions = new MapDefinitionCollection(new IMapDefinition[]
{
new Profile1(),
new MapperDefinition1(),
});
var mapper = new UmbracoMapper(profiles);
var mapper = new UmbracoMapper(definitions);
var thing1 = new Thing1 { Value = "value" };
var thing2 = mapper.Map<Thing1, Thing2>(thing1);
@@ -36,11 +40,11 @@ namespace Umbraco.Tests.Mapping
[Test]
public void EnumerableMap()
{
var profiles = new MapDefinitionCollection(new IMapDefinition[]
var definitions = new MapDefinitionCollection(new IMapDefinition[]
{
new Profile1(),
new MapperDefinition1(),
});
var mapper = new UmbracoMapper(profiles);
var mapper = new UmbracoMapper(definitions);
var thing1A = new Thing1 { Value = "valueA" };
var thing1B = new Thing1 { Value = "valueB" };
@@ -58,16 +62,23 @@ namespace Umbraco.Tests.Mapping
Assert.AreEqual(2, thing2.Count);
Assert.AreEqual("valueA", thing2[0].Value);
Assert.AreEqual("valueB", thing2[1].Value);
thing2 = mapper.MapEnumerable<Thing1, Thing2>(thing1).ToList();
Assert.IsNotNull(thing2);
Assert.AreEqual(2, thing2.Count);
Assert.AreEqual("valueA", thing2[0].Value);
Assert.AreEqual("valueB", thing2[1].Value);
}
[Test]
public void InheritedMap()
{
var profiles = new MapDefinitionCollection(new IMapDefinition[]
var definitions = new MapDefinitionCollection(new IMapDefinition[]
{
new Profile1(),
new MapperDefinition1(),
});
var mapper = new UmbracoMapper(profiles);
var mapper = new UmbracoMapper(definitions);
var thing3 = new Thing3 { Value = "value" };
var thing2 = mapper.Map<Thing3, Thing2>(thing3);
@@ -85,6 +96,82 @@ namespace Umbraco.Tests.Mapping
Assert.AreEqual("value", thing2.Value);
}
[Test]
public void CollectionsMap()
{
var definitions = new MapDefinitionCollection(new IMapDefinition[]
{
new MapperDefinition2(),
});
var mapper = new UmbracoMapper(definitions);
// can map a PropertyCollection
var source = new PropertyCollection();
var target = mapper.Map<IEnumerable<ContentPropertyDto>>(source);
}
[Test]
[Explicit]
public void ConcurrentMap()
{
var definitions = new MapDefinitionCollection(new IMapDefinition[]
{
new MapperDefinition1(),
new MapperDefinition3(),
});
var mapper = new UmbracoMapper(definitions);
// the mapper currently has a map from Thing1 to Thing2
// because Thing3 inherits from Thing1, it will map a Thing3 instance,
// and register a new map from Thing3 to Thing2,
// thus modifying its internal dictionaries
// if timing is good, and mapper does have non-concurrent dictionaries, it fails
// practically, to reproduce, one needs to add a 1s sleep in the mapper's loop
// hence, this test is explicit
var thing3 = new Thing3 { Value = "value" };
var thing4 = new Thing4();
Exception caught = null;
void ThreadLoop()
{
// keep failing at mapping - and looping through the maps
for (var i = 0; i < 10; i++)
{
try
{
mapper.Map<Thing2>(thing4);
}
catch (Exception e)
{
caught = e;
Console.WriteLine($"{e.GetType().Name} {e.Message}");
}
}
Console.WriteLine("done");
}
var thread = new Thread(ThreadLoop);
thread.Start();
Thread.Sleep(1000);
try
{
Console.WriteLine($"{DateTime.Now:O} mapping");
var thing2 = mapper.Map<Thing2>(thing3);
Console.WriteLine($"{DateTime.Now:O} mapped");
Assert.IsNotNull(thing2);
Assert.AreEqual("value", thing2.Value);
}
finally
{
thread.Join();
}
}
private class Thing1
{
public string Value { get; set; }
@@ -98,7 +185,10 @@ namespace Umbraco.Tests.Mapping
public string Value { get; set; }
}
private class Profile1 : IMapDefinition
private class Thing4
{ }
private class MapperDefinition1 : IMapDefinition
{
public void DefineMaps(UmbracoMapper mapper)
{
@@ -110,5 +200,29 @@ namespace Umbraco.Tests.Mapping
target.Value = source.Value;
}
}
private class MapperDefinition2 : IMapDefinition
{
public void DefineMaps(UmbracoMapper mapper)
{
mapper.Define<Property, ContentPropertyDto>((source, context) => new ContentPropertyDto(), Map);
}
private static void Map(Property source, ContentPropertyDto target, MapperContext context)
{ }
}
private class MapperDefinition3 : IMapDefinition
{
public void DefineMaps(UmbracoMapper mapper)
{
// just some random things so that the mapper contains things
mapper.Define<int, object>();
mapper.Define<string, object>();
mapper.Define<double, object>();
mapper.Define<UmbracoMapper, object>();
mapper.Define<Property, object>();
}
}
}
}
+43 -9
View File
@@ -15,13 +15,47 @@ namespace Umbraco.Tests.Models
[TestFixture]
public class ContentTypeTests : UmbracoTestBase
{
[Test]
[Ignore("Ignoring this test until we actually enforce this, see comments in ContentTypeBase.PropertyTypesChanged")]
public void Cannot_Add_Duplicate_Property_Aliases()
{
var contentType = MockedContentTypes.CreateBasicContentType();
contentType.PropertyGroups.Add(new PropertyGroup(new PropertyTypeCollection(false, new[]
{
new PropertyType("testPropertyEditor", ValueStorageType.Nvarchar){ Alias = "myPropertyType" }
})));
Assert.Throws<InvalidOperationException>(() =>
contentType.PropertyTypeCollection.Add(
new PropertyType("testPropertyEditor", ValueStorageType.Nvarchar) { Alias = "myPropertyType" }));
}
[Test]
[Ignore("Ignoring this test until we actually enforce this, see comments in ContentTypeBase.PropertyTypesChanged")]
public void Cannot_Update_Duplicate_Property_Aliases()
{
var contentType = MockedContentTypes.CreateBasicContentType();
contentType.PropertyGroups.Add(new PropertyGroup(new PropertyTypeCollection(false, new[]
{
new PropertyType("testPropertyEditor", ValueStorageType.Nvarchar){ Alias = "myPropertyType" }
})));
contentType.PropertyTypeCollection.Add(new PropertyType("testPropertyEditor", ValueStorageType.Nvarchar) { Alias = "myPropertyType2" });
var toUpdate = contentType.PropertyTypeCollection["myPropertyType2"];
Assert.Throws<InvalidOperationException>(() => toUpdate.Alias = "myPropertyType");
}
[Test]
public void Can_Deep_Clone_Content_Type_Sort()
{
var contentType = new ContentTypeSort(new Lazy<int>(() => 3), 4, "test");
var clone = (ContentTypeSort) contentType.DeepClone();
var clone = (ContentTypeSort)contentType.DeepClone();
Assert.AreNotSame(clone, contentType);
Assert.AreEqual(clone, contentType);
Assert.AreEqual(clone.Id.Value, contentType.Id.Value);
@@ -54,7 +88,7 @@ namespace Umbraco.Tests.Models
contentType.Id = 10;
contentType.CreateDate = DateTime.Now;
contentType.CreatorId = 22;
contentType.SetDefaultTemplate(new Template((string) "Test Template", (string) "testTemplate")
contentType.SetDefaultTemplate(new Template((string)"Test Template", (string)"testTemplate")
{
Id = 88
});
@@ -117,12 +151,12 @@ namespace Umbraco.Tests.Models
{
group.Id = ++i;
}
contentType.AllowedTemplates = new[] { new Template((string) "Name", (string) "name") { Id = 200 }, new Template((string) "Name2", (string) "name2") { Id = 201 } };
contentType.AllowedTemplates = new[] { new Template((string)"Name", (string)"name") { Id = 200 }, new Template((string)"Name2", (string)"name2") { Id = 201 } };
contentType.AllowedContentTypes = new[] { new ContentTypeSort(new Lazy<int>(() => 888), 8, "sub"), new ContentTypeSort(new Lazy<int>(() => 889), 9, "sub2") };
contentType.Id = 10;
contentType.CreateDate = DateTime.Now;
contentType.CreatorId = 22;
contentType.SetDefaultTemplate(new Template((string) "Test Template", (string) "testTemplate")
contentType.SetDefaultTemplate(new Template((string)"Test Template", (string)"testTemplate")
{
Id = 88
});
@@ -167,12 +201,12 @@ namespace Umbraco.Tests.Models
{
group.Id = ++i;
}
contentType.AllowedTemplates = new[] { new Template((string) "Name", (string) "name") { Id = 200 }, new Template((string) "Name2", (string) "name2") { Id = 201 } };
contentType.AllowedContentTypes = new[] {new ContentTypeSort(new Lazy<int>(() => 888), 8, "sub"), new ContentTypeSort(new Lazy<int>(() => 889), 9, "sub2")};
contentType.AllowedTemplates = new[] { new Template((string)"Name", (string)"name") { Id = 200 }, new Template((string)"Name2", (string)"name2") { Id = 201 } };
contentType.AllowedContentTypes = new[] { new ContentTypeSort(new Lazy<int>(() => 888), 8, "sub"), new ContentTypeSort(new Lazy<int>(() => 889), 9, "sub2") };
contentType.Id = 10;
contentType.CreateDate = DateTime.Now;
contentType.CreatorId = 22;
contentType.SetDefaultTemplate(new Template((string) "Test Template", (string) "testTemplate")
contentType.SetDefaultTemplate(new Template((string)"Test Template", (string)"testTemplate")
{
Id = 88
});
@@ -264,12 +298,12 @@ namespace Umbraco.Tests.Models
{
propertyType.Id = ++i;
}
contentType.AllowedTemplates = new[] { new Template((string) "Name", (string) "name") { Id = 200 }, new Template((string) "Name2", (string) "name2") { Id = 201 } };
contentType.AllowedTemplates = new[] { new Template((string)"Name", (string)"name") { Id = 200 }, new Template((string)"Name2", (string)"name2") { Id = 201 } };
contentType.AllowedContentTypes = new[] { new ContentTypeSort(new Lazy<int>(() => 888), 8, "sub"), new ContentTypeSort(new Lazy<int>(() => 889), 9, "sub2") };
contentType.Id = 10;
contentType.CreateDate = DateTime.Now;
contentType.CreatorId = 22;
contentType.SetDefaultTemplate(new Template((string) "Test Template", (string) "testTemplate")
contentType.SetDefaultTemplate(new Template((string)"Test Template", (string)"testTemplate")
{
Id = 88
});
@@ -171,7 +171,6 @@ namespace Umbraco.Tests.Persistence.Repositories
}
}
//NOTE: This tests for left join logic (rev 7b14e8eacc65f82d4f184ef46c23340c09569052)
[Test]
public void Can_Get_All_Members_When_No_Properties_Assigned()
@@ -200,7 +199,6 @@ namespace Umbraco.Tests.Persistence.Repositories
}
}
[Test]
public void Can_Get_Member_Type_By_Id()
{
@@ -233,22 +231,114 @@ namespace Umbraco.Tests.Persistence.Repositories
}
}
// See: https://github.com/umbraco/Umbraco-CMS/issues/4963#issuecomment-483516698
[Test]
public void Bug_Changing_Built_In_Member_Type_Property_Type_Aliases_Results_In_Exception()
{
var stubs = Constants.Conventions.Member.GetStandardPropertyTypeStubs();
var provider = TestObjects.GetScopeProvider(Logger);
using (provider.CreateScope())
{
var repository = CreateRepository(provider);
IMemberType memberType = MockedContentTypes.CreateSimpleMemberType("mtype");
// created without the stub properties
Assert.AreEqual(1, memberType.PropertyGroups.Count);
Assert.AreEqual(3, memberType.PropertyTypes.Count());
// saving *new* member type adds the stub properties
repository.Save(memberType);
// saving has added (and saved) the stub properties
Assert.AreEqual(2, memberType.PropertyGroups.Count);
Assert.AreEqual(3 + stubs.Count, memberType.PropertyTypes.Count());
foreach (var stub in stubs)
{
var prop = memberType.PropertyTypes.First(x => x.Alias == stub.Key);
prop.Alias = prop.Alias + "__0000";
}
// saving *existing* member type does *not* ensure stub properties
repository.Save(memberType);
// therefore, nothing has changed
Assert.AreEqual(2, memberType.PropertyGroups.Count);
Assert.AreEqual(3 + stubs.Count, memberType.PropertyTypes.Count());
// fetching ensures that the stub properties are there
memberType = repository.Get("mtype");
Assert.IsNotNull(memberType);
Assert.AreEqual(2, memberType.PropertyGroups.Count);
Assert.AreEqual(3 + stubs.Count * 2, memberType.PropertyTypes.Count());
}
}
[Test]
public void Built_In_Member_Type_Properties_Are_Automatically_Added_When_Creating()
{
var stubs = Constants.Conventions.Member.GetStandardPropertyTypeStubs();
var provider = TestObjects.GetScopeProvider(Logger);
using (var scope = provider.CreateScope())
using (provider.CreateScope())
{
var repository = CreateRepository(provider);
IMemberType memberType = MockedContentTypes.CreateSimpleMemberType();
// created without the stub properties
Assert.AreEqual(1, memberType.PropertyGroups.Count);
Assert.AreEqual(3, memberType.PropertyTypes.Count());
// saving *new* member type adds the stub properties
repository.Save(memberType);
// saving has added (and saved) the stub properties
Assert.AreEqual(2, memberType.PropertyGroups.Count);
Assert.AreEqual(3 + stubs.Count, memberType.PropertyTypes.Count());
// getting with stub properties
memberType = repository.Get(memberType.Id);
Assert.That(memberType.PropertyTypes.Count(), Is.EqualTo(3 + Constants.Conventions.Member.GetStandardPropertyTypeStubs().Count));
Assert.That(memberType.PropertyGroups.Count(), Is.EqualTo(2));
Assert.AreEqual(2, memberType.PropertyGroups.Count);
Assert.AreEqual(3 + stubs.Count, memberType.PropertyTypes.Count());
}
}
[Test]
public void Built_In_Member_Type_Properties_Missing_Are_Automatically_Added_When_Creating()
{
var stubs = Constants.Conventions.Member.GetStandardPropertyTypeStubs();
var provider = TestObjects.GetScopeProvider(Logger);
using (provider.CreateScope())
{
var repository = CreateRepository(provider);
IMemberType memberType = MockedContentTypes.CreateSimpleMemberType();
// created without the stub properties
Assert.AreEqual(1, memberType.PropertyGroups.Count);
Assert.AreEqual(3, memberType.PropertyTypes.Count());
// add one stub property, others are still missing
memberType.AddPropertyType(stubs.First().Value, Constants.Conventions.Member.StandardPropertiesGroupName);
// saving *new* member type adds the (missing) stub properties
repository.Save(memberType);
// saving has added (and saved) the (missing) stub properties
Assert.AreEqual(2, memberType.PropertyGroups.Count);
Assert.AreEqual(3 + stubs.Count, memberType.PropertyTypes.Count());
// getting with stub properties
memberType = repository.Get(memberType.Id);
Assert.AreEqual(2, memberType.PropertyGroups.Count);
Assert.AreEqual(3 + stubs.Count, memberType.PropertyTypes.Count());
}
}
@@ -71,6 +71,7 @@ namespace Umbraco.Tests.PublishedContent
new WebSecurity(httpContext, Current.Services.UserService, globalSettings),
TestObjects.GetUmbracoSettings(),
Enumerable.Empty<IUrlProvider>(),
Enumerable.Empty<IMediaUrlProvider>(),
globalSettings,
new TestVariationContextAccessor());
@@ -92,6 +92,9 @@ namespace Umbraco.Tests.PublishedContent
throw new NotImplementedException();
}
public override IPublishedContent GetById(bool preview, Udi nodeId)
=> throw new NotSupportedException();
public override bool HasById(bool preview, int contentId)
{
return _content.ContainsKey(contentId);
@@ -0,0 +1,152 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Moq;
using Newtonsoft.Json;
using NUnit.Framework;
using Umbraco.Core;
using Umbraco.Core.Models;
using Umbraco.Core.Models.PublishedContent;
using Umbraco.Core.PropertyEditors;
using Umbraco.Core.PropertyEditors.ValueConverters;
using Umbraco.Tests.PublishedContent;
using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.TestHelpers.Stubs;
using Umbraco.Tests.Testing;
using Umbraco.Web.Routing;
namespace Umbraco.Tests.Routing
{
[TestFixture]
[UmbracoTest(Database = UmbracoTestOptions.Database.NewSchemaPerFixture)]
public class MediaUrlProviderTests : BaseWebTest
{
private DefaultMediaUrlProvider _mediaUrlProvider;
public override void SetUp()
{
base.SetUp();
_mediaUrlProvider = new DefaultMediaUrlProvider();
}
public override void TearDown()
{
base.TearDown();
_mediaUrlProvider = null;
}
[Test]
public void Get_Media_Url_Resolves_Url_From_Upload_Property_Editor()
{
const string expected = "/media/rfeiw584/test.jpg";
var umbracoContext = GetUmbracoContext("/", mediaUrlProviders: new[] { _mediaUrlProvider });
var publishedContent = CreatePublishedContent(Constants.PropertyEditors.Aliases.UploadField, expected, null);
var resolvedUrl = umbracoContext.UrlProvider.GetMediaUrl(publishedContent, "umbracoFile", UrlProviderMode.Auto, null, null);
Assert.AreEqual(expected, resolvedUrl);
}
[Test]
public void Get_Media_Url_Resolves_Url_From_Image_Cropper_Property_Editor()
{
const string expected = "/media/rfeiw584/test.jpg";
var configuration = new ImageCropperConfiguration();
var imageCropperValue = JsonConvert.SerializeObject(new ImageCropperValue
{
Src = expected
});
var umbracoContext = GetUmbracoContext("/", mediaUrlProviders: new[] { _mediaUrlProvider });
var publishedContent = CreatePublishedContent(Constants.PropertyEditors.Aliases.ImageCropper, imageCropperValue, configuration);
var resolvedUrl = umbracoContext.UrlProvider.GetMediaUrl(publishedContent, "umbracoFile", UrlProviderMode.Auto, null, null);
Assert.AreEqual(expected, resolvedUrl);
}
[Test]
public void Get_Media_Url_Can_Resolve_Absolute_Url()
{
const string mediaUrl = "/media/rfeiw584/test.jpg";
var expected = $"http://localhost{mediaUrl}";
var umbracoContext = GetUmbracoContext("http://localhost", mediaUrlProviders: new[] { _mediaUrlProvider });
var publishedContent = CreatePublishedContent(Constants.PropertyEditors.Aliases.UploadField, mediaUrl, null);
var resolvedUrl = umbracoContext.UrlProvider.GetMediaUrl(publishedContent, "umbracoFile", UrlProviderMode.Absolute, null, null);
Assert.AreEqual(expected, resolvedUrl);
}
[Test]
public void Get_Media_Url_Returns_Empty_String_When_PropertyType_Is_Not_Supported()
{
var umbracoContext = GetUmbracoContext("/", mediaUrlProviders: new[] { _mediaUrlProvider });
var publishedContent = CreatePublishedContent(Constants.PropertyEditors.Aliases.Boolean, "0", null);
var resolvedUrl = umbracoContext.UrlProvider.GetMediaUrl(publishedContent, "test", UrlProviderMode.Absolute, null, null);
Assert.AreEqual(string.Empty, resolvedUrl);
}
[Test]
public void Get_Media_Url_Can_Resolve_Variant_Property_Url()
{
var umbracoContext = GetUmbracoContext("http://localhost", mediaUrlProviders: new[] { _mediaUrlProvider });
var umbracoFilePropertyType = CreatePropertyType(Constants.PropertyEditors.Aliases.UploadField, null, ContentVariation.Culture);
const string enMediaUrl = "/media/rfeiw584/en.jpg";
const string daMediaUrl = "/media/uf8ewud2/da.jpg";
var property = new SolidPublishedPropertyWithLanguageVariants
{
Alias = "umbracoFile",
PropertyType = umbracoFilePropertyType,
};
property.SetValue("en", enMediaUrl, true);
property.SetValue("da", daMediaUrl);
var contentType = new PublishedContentType(666, "alias", PublishedItemType.Content, Enumerable.Empty<string>(), new [] { umbracoFilePropertyType }, ContentVariation.Culture);
var publishedContent = new SolidPublishedContent(contentType) {Properties = new[] {property}};
var resolvedUrl = umbracoContext.UrlProvider.GetMediaUrl(publishedContent, "umbracoFile", UrlProviderMode.Auto, "da", null);
Assert.AreEqual(daMediaUrl, resolvedUrl);
}
private static TestPublishedContent CreatePublishedContent(string propertyEditorAlias, object propertyValue, object dataTypeConfiguration)
{
var umbracoFilePropertyType = CreatePropertyType(propertyEditorAlias, dataTypeConfiguration, ContentVariation.Nothing);
var contentType = new PublishedContentType(666, "alias", PublishedItemType.Content, Enumerable.Empty<string>(),
new[] {umbracoFilePropertyType}, ContentVariation.Nothing);
return new TestPublishedContent(contentType, 1234, Guid.NewGuid(),
new Dictionary<string, object> {{"umbracoFile", propertyValue } }, false);
}
private static PublishedPropertyType CreatePropertyType(string propertyEditorAlias, object dataTypeConfiguration, ContentVariation variation)
{
var uploadDataType = new PublishedDataType(1234, propertyEditorAlias, new Lazy<object>(() => dataTypeConfiguration));
var propertyValueConverters = new PropertyValueConverterCollection(new IPropertyValueConverter[]
{
new UploadPropertyConverter(),
new ImageCropperValueConverter(),
});
var publishedModelFactory = Mock.Of<IPublishedModelFactory>();
var publishedContentTypeFactory = new Mock<IPublishedContentTypeFactory>();
publishedContentTypeFactory.Setup(x => x.GetDataType(It.IsAny<int>()))
.Returns(uploadDataType);
return new PublishedPropertyType("umbracoFile", 42, true, variation, propertyValueConverters, publishedModelFactory, publishedContentTypeFactory.Object);
}
}
}
+11 -4
View File
@@ -29,6 +29,7 @@ using Umbraco.Tests.TestHelpers;
using Umbraco.Tests.Testing.Objects.Accessors;
using Umbraco.Web;
using Umbraco.Web.Cache;
using Umbraco.Web.Macros;
using Umbraco.Web.PublishedCache;
using Umbraco.Web.Routing;
using Umbraco.Web.Runtime;
@@ -81,7 +82,7 @@ namespace Umbraco.Tests.Runtimes
var composerTypes = typeLoader.GetTypes<IComposer>() // all of them
.Where(x => !x.FullName.StartsWith("Umbraco.Tests.")) // exclude test components
.Where(x => x != typeof(WebInitialComposer)); // exclude web runtime
.Where(x => x != typeof(WebInitialComposer) && x != typeof(WebFinalComposer)); // exclude web runtime
var composers = new Composers(composition, composerTypes, profilingLogger);
composers.Compose();
@@ -101,6 +102,8 @@ namespace Umbraco.Tests.Runtimes
composition.RegisterUnique<IDistributedCacheBinder, DistributedCacheBinder>();
composition.RegisterUnique<IExamineManager>(f => ExamineManager.Instance);
composition.RegisterUnique<IUmbracoContextFactory, UmbracoContextFactory>();
composition.RegisterUnique<IMacroRenderer, MacroRenderer>();
composition.RegisterUnique<MediaUrlProviderCollection>(_ => new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()));
// initialize some components only/individually
composition.WithCollectionBuilder<ComponentCollectionBuilder>()
@@ -124,14 +127,15 @@ namespace Umbraco.Tests.Runtimes
if (true || runtimeState.Level == RuntimeLevel.Install)
{
var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var file = Path.Combine(path, "Umbraco.sdf");
var file = databaseFactory.Configured ? Path.Combine(path, "UmbracoNPocoTests.sdf") : Path.Combine(path, "Umbraco.sdf");
if (File.Exists(file))
File.Delete(file);
// create the database file
// databaseBuilder.ConfigureEmbeddedDatabaseConnection() can do it too,
// but then it wants to write the connection string to web.config = bad
using (var engine = new SqlCeEngine("Data Source=|DataDirectory|\\Umbraco.sdf;Flush Interval=1;"))
var connectionString = databaseFactory.Configured ? databaseFactory.ConnectionString : "Data Source=|DataDirectory|\\Umbraco.sdf;Flush Interval=1;";
using (var engine = new SqlCeEngine(connectionString))
{
engine.CreateDatabase();
}
@@ -140,7 +144,8 @@ namespace Umbraco.Tests.Runtimes
//databaseFactory.Configure(DatabaseBuilder.EmbeddedDatabaseConnectionString, Constants.DbProviderNames.SqlCe);
//databaseBuilder.CreateDatabaseSchemaAndData();
databaseFactory.Configure(DatabaseBuilder.EmbeddedDatabaseConnectionString, Constants.DbProviderNames.SqlCe);
if (!databaseFactory.Configured)
databaseFactory.Configure(DatabaseBuilder.EmbeddedDatabaseConnectionString, Constants.DbProviderNames.SqlCe);
var scopeProvider = factory.GetInstance<IScopeProvider>();
using (var scope = scopeProvider.CreateScope())
@@ -154,6 +159,8 @@ namespace Umbraco.Tests.Runtimes
// done installing
runtimeState.Level = RuntimeLevel.Run;
components.Initialize();
// instantiate to register events
// should be done by Initialize?
// should we invoke Initialize?
@@ -118,6 +118,7 @@ namespace Umbraco.Tests.Scoping
new WebSecurity(httpContext, Current.Services.UserService, globalSettings),
umbracoSettings ?? SettingsForTests.GetDefaultUmbracoSettings(),
urlProviders ?? Enumerable.Empty<IUrlProvider>(),
Enumerable.Empty<IMediaUrlProvider>(),
globalSettings,
new TestVariationContextAccessor());
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Web;
using Microsoft.Owin;
using Moq;
@@ -33,7 +34,7 @@ namespace Umbraco.Tests.Security
Mock.Of<HttpContextBase>(),
Mock.Of<IPublishedSnapshotService>(),
new WebSecurity(Mock.Of<HttpContextBase>(), Current.Services.UserService, globalSettings),
TestObjects.GetUmbracoSettings(), new List<IUrlProvider>(),globalSettings,
TestObjects.GetUmbracoSettings(), new List<IUrlProvider>(), Enumerable.Empty<IMediaUrlProvider>(), globalSettings,
new TestVariationContextAccessor());
var runtime = Mock.Of<IRuntimeState>(x => x.Level == RuntimeLevel.Install);
@@ -53,7 +54,7 @@ namespace Umbraco.Tests.Security
Mock.Of<HttpContextBase>(),
Mock.Of<IPublishedSnapshotService>(),
new WebSecurity(Mock.Of<HttpContextBase>(), Current.Services.UserService, globalSettings),
TestObjects.GetUmbracoSettings(), new List<IUrlProvider>(), globalSettings,
TestObjects.GetUmbracoSettings(), new List<IUrlProvider>(), Enumerable.Empty<IMediaUrlProvider>(), globalSettings,
new TestVariationContextAccessor());
var runtime = Mock.Of<IRuntimeState>(x => x.Level == RuntimeLevel.Run);
@@ -139,6 +139,7 @@ namespace Umbraco.Tests.TestHelpers.ControllerTesting
webSecurity.Object,
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == Mock.Of<IWebRoutingSection>(routingSection => routingSection.UrlProviderMode == "Auto")),
Enumerable.Empty<IUrlProvider>(),
Enumerable.Empty<IMediaUrlProvider>(),
globalSettings,
new TestVariationContextAccessor());
@@ -122,6 +122,7 @@ namespace Umbraco.Tests.TestHelpers
var umbracoSettings = GetUmbracoSettings();
var globalSettings = GetGlobalSettings();
var urlProviders = new UrlProviderCollection(Enumerable.Empty<IUrlProvider>());
var mediaUrlProviders = new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>());
if (accessor == null) accessor = new TestUmbracoContextAccessor();
@@ -133,6 +134,7 @@ namespace Umbraco.Tests.TestHelpers
umbracoSettings,
globalSettings,
urlProviders,
mediaUrlProviders,
Mock.Of<IUserService>());
return umbracoContextFactory.EnsureUmbracoContext(httpContext).UmbracoContext;
@@ -353,7 +353,7 @@ namespace Umbraco.Tests.TestHelpers
}
}
protected UmbracoContext GetUmbracoContext(string url, int templateId = 1234, RouteData routeData = null, bool setSingleton = false, IUmbracoSettingsSection umbracoSettings = null, IEnumerable<IUrlProvider> urlProviders = null, IGlobalSettings globalSettings = null, IPublishedSnapshotService snapshotService = null)
protected UmbracoContext GetUmbracoContext(string url, int templateId = 1234, RouteData routeData = null, bool setSingleton = false, IUmbracoSettingsSection umbracoSettings = null, IEnumerable<IUrlProvider> urlProviders = null, IEnumerable<IMediaUrlProvider> mediaUrlProviders = null, IGlobalSettings globalSettings = null, IPublishedSnapshotService snapshotService = null)
{
// ensure we have a PublishedCachesService
var service = snapshotService ?? PublishedSnapshotService as PublishedSnapshotService;
@@ -380,6 +380,7 @@ namespace Umbraco.Tests.TestHelpers
Factory.GetInstance<IGlobalSettings>()),
umbracoSettings ?? Factory.GetInstance<IUmbracoSettingsSection>(),
urlProviders ?? Enumerable.Empty<IUrlProvider>(),
mediaUrlProviders ?? Enumerable.Empty<IMediaUrlProvider>(),
globalSettings ?? Factory.GetInstance<IGlobalSettings>(),
new TestVariationContextAccessor());
@@ -80,7 +80,7 @@ namespace Umbraco.Tests.Testing.TestingTests
.Returns(UrlInfo.Url("/hello/world/1234"));
var urlProvider = urlProviderMock.Object;
var theUrlProvider = new UrlProvider(umbracoContext, new [] { urlProvider }, umbracoContext.VariationContextAccessor);
var theUrlProvider = new UrlProvider(umbracoContext, new [] { urlProvider }, Enumerable.Empty<IMediaUrlProvider>(), umbracoContext.VariationContextAccessor);
var contentType = new PublishedContentType(666, "alias", PublishedItemType.Content, Enumerable.Empty<string>(), Enumerable.Empty<PublishedPropertyType>(), ContentVariation.Nothing);
var publishedContent = Mock.Of<IPublishedContent>();
+1
View File
@@ -143,6 +143,7 @@
<Compile Include="PublishedContent\PublishedContentSnapshotTestBase.cs" />
<Compile Include="PublishedContent\SolidPublishedSnapshot.cs" />
<Compile Include="PublishedContent\NuCacheTests.cs" />
<Compile Include="Routing\MediaUrlProviderTests.cs" />
<Compile Include="Runtimes\StandaloneTests.cs" />
<Compile Include="Routing\GetContentUrlsTests.cs" />
<Compile Include="Services\AmbiguousEventTests.cs" />
@@ -72,6 +72,7 @@ namespace Umbraco.Tests.Web.Mvc
TestObjects.GetUmbracoSettings(),
globalSettings,
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
@@ -101,6 +102,7 @@ namespace Umbraco.Tests.Web.Mvc
TestObjects.GetUmbracoSettings(),
globalSettings,
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
@@ -130,6 +132,7 @@ namespace Umbraco.Tests.Web.Mvc
TestObjects.GetUmbracoSettings(),
globalSettings,
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
@@ -159,6 +162,7 @@ namespace Umbraco.Tests.Web.Mvc
TestObjects.GetUmbracoSettings(),
globalSettings,
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
@@ -47,6 +47,7 @@ namespace Umbraco.Tests.Web.Mvc
TestObjects.GetUmbracoSettings(),
globalSettings,
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
@@ -74,6 +75,7 @@ namespace Umbraco.Tests.Web.Mvc
TestObjects.GetUmbracoSettings(),
globalSettings,
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
@@ -104,6 +106,7 @@ namespace Umbraco.Tests.Web.Mvc
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == Mock.Of<IWebRoutingSection>(routingSection => routingSection.UrlProviderMode == "Auto")),
globalSettings,
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
@@ -141,6 +144,7 @@ namespace Umbraco.Tests.Web.Mvc
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == webRoutingSettings),
globalSettings,
new UrlProviderCollection(Enumerable.Empty<IUrlProvider>()),
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
Mock.Of<IUserService>());
var umbracoContextReference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>());
@@ -440,6 +440,7 @@ namespace Umbraco.Tests.Web.Mvc
new WebSecurity(http, Current.Services.UserService, globalSettings),
TestObjects.GetUmbracoSettings(),
Enumerable.Empty<IUrlProvider>(),
Enumerable.Empty<IMediaUrlProvider>(),
globalSettings,
new TestVariationContextAccessor());
@@ -61,10 +61,12 @@ namespace Umbraco.Tests.Web
[TestCase("", "")]
[TestCase("hello href=\"{localLink:1234}\" world ", "hello href=\"/my-test-url\" world ")]
[TestCase("hello href=\"{localLink:umb://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"/my-test-url\" world ")]
[TestCase("hello href=\"{localLink:umb://document-type/9931BDE0AAC34BABB838909A7B47570E}\" world ", "hello href=\"/my-test-url\" world ")]
[TestCase("hello href=\"{localLink:umb://document/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"/my-test-url\" world ")]
[TestCase("hello href=\"{localLink:umb://document/9931BDE0AAC34BABB838909A7B47570E}\" world ", "hello href=\"/my-test-url\" world ")]
[TestCase("hello href=\"{localLink:umb://media/9931BDE0AAC34BABB838909A7B47570E}\" world ", "hello href=\"/media/1001/my-image.jpg\" world ")]
//this one has an invalid char so won't match
[TestCase("hello href=\"{localLink:umb^://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"{localLink:umb^://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ")]
[TestCase("hello href=\"{localLink:umb^://document/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"{localLink:umb^://document/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ")]
[TestCase("hello href=\"{localLink:umb://document-type/9931BDE0-AAC3-4BAB-B838-909A7B47570E}\" world ", "hello href=\"#\" world ")]
public void ParseLocalLinks(string input, string result)
{
var serviceCtxMock = new TestObjects(null).GetServiceContextMock();
@@ -77,7 +79,7 @@ namespace Umbraco.Tests.Web
// return Attempt.Succeed(1234);
// });
//setup a mock url provider which we'll use fo rtesting
//setup a mock url provider which we'll use for testing
var testUrlProvider = new Mock<IUrlProvider>();
testUrlProvider
.Setup(x => x.GetUrl(It.IsAny<UmbracoContext>(), It.IsAny<IPublishedContent>(), It.IsAny<UrlProviderMode>(), It.IsAny<string>(), It.IsAny<Uri>()))
@@ -96,6 +98,10 @@ namespace Umbraco.Tests.Web
Mock.Get(snapshot).Setup(x => x.Content).Returns(contentCache);
var snapshotService = Mock.Of<IPublishedSnapshotService>();
Mock.Get(snapshotService).Setup(x => x.CreatePublishedSnapshot(It.IsAny<string>())).Returns(snapshot);
var media = Mock.Of<IPublishedContent>();
Mock.Get(media).Setup(x => x.Url).Returns("/media/1001/my-image.jpg");
var mediaCache = Mock.Of<IPublishedMediaCache>();
Mock.Get(mediaCache).Setup(x => x.GetById(It.IsAny<Guid>())).Returns(media);
var umbracoContextFactory = new UmbracoContextFactory(
Umbraco.Web.Composing.Current.UmbracoContextAccessor,
@@ -105,11 +111,12 @@ namespace Umbraco.Tests.Web
Mock.Of<IUmbracoSettingsSection>(section => section.WebRouting == Mock.Of<IWebRoutingSection>(routingSection => routingSection.UrlProviderMode == "Auto")),
globalSettings,
new UrlProviderCollection(new[] { testUrlProvider.Object }),
new MediaUrlProviderCollection(Enumerable.Empty<IMediaUrlProvider>()),
Mock.Of<IUserService>());
using (var reference = umbracoContextFactory.EnsureUmbracoContext(Mock.Of<HttpContextBase>()))
{
var output = TemplateUtilities.ParseInternalLinks(input, reference.UmbracoContext.UrlProvider);
var output = TemplateUtilities.ParseInternalLinks(input, reference.UmbracoContext.UrlProvider, mediaCache);
Assert.AreEqual(result, output);
}
@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
@@ -31,6 +32,7 @@ namespace Umbraco.Tests.Web
new WebSecurity(Mock.Of<HttpContextBase>(), Current.Services.UserService, TestObjects.GetGlobalSettings()),
TestObjects.GetUmbracoSettings(),
new List<IUrlProvider>(),
Enumerable.Empty<IMediaUrlProvider>(),
TestObjects.GetGlobalSettings(),
new TestVariationContextAccessor());
var r1 = new RouteData();
@@ -49,6 +51,7 @@ namespace Umbraco.Tests.Web
new WebSecurity(Mock.Of<HttpContextBase>(), Current.Services.UserService, TestObjects.GetGlobalSettings()),
TestObjects.GetUmbracoSettings(),
new List<IUrlProvider>(),
Enumerable.Empty<IMediaUrlProvider>(),
TestObjects.GetGlobalSettings(),
new TestVariationContextAccessor());
@@ -77,6 +80,7 @@ namespace Umbraco.Tests.Web
new WebSecurity(Mock.Of<HttpContextBase>(), Current.Services.UserService, TestObjects.GetGlobalSettings()),
TestObjects.GetUmbracoSettings(),
new List<IUrlProvider>(),
Enumerable.Empty<IMediaUrlProvider>(),
TestObjects.GetGlobalSettings(),
new TestVariationContextAccessor());
+9 -2
View File
@@ -1,3 +1,10 @@
{
"presets": ["@babel/preset-env"]
}
"presets": [
[
"@babel/preset-env",
{
"targets": "last 2 version, not dead, > 0.5%, not ie 11"
}
]
]
}
@@ -6,46 +6,6 @@
This documentation relates to the angular, js, css and less APIs for developing back office components
##Running the site with mocked data
This won't require any database or setup, as everything is running through node. All you have to do is install
node and grunt on either windows or OSX and the entire setup is ready for you.
###Install node.js
We need node to run tests and automated less compiling and other automated tasks. go to http://nodejs.org. Node.js is a powerfull javascript engine, which allows us to run all our tests and tasks written in javascript locally.
*note:* On windows you might need to restart explorer.exe to register node.
###Install dependencies
Next we need to install all the required packages. This is done with the package tool, included with node.js, open /Umbraco.Belle.Client in cmd.exe or osx terminal and run the command:
npm install
this will fetch all needed packages to your local machine.
###Install grunt globally
Grunt is a task runner for node.js, and we use it for all automated tasks in the build process. For convenience we need to install it globally on your machine, so it can be used directly in cmd.exe or the terminal.
So run the command:
npm install grunt-cli -g
*note:* On windows you might need to restart explorer.exe to register the grunt cmd.
*note:* On OSX you might need to run:
sudo npm install grunt-cli -g
Now that you have node and grunt installed, you can open `/Umbraco.Web.UI.Client` in either `cmd.exe` or terminal and run:
grunt dev
This will build the site, merge less files, run tests and create the /Build folder, and finally open the site in your
browser.
##Getting started
The current app is built, following conventions from angularJs and bootstrap. To get started with the applicaton you will need to atleast know the basics of these frameworks
@@ -7,6 +7,7 @@ var babel = require("gulp-babel");
var sort = require('gulp-sort');
var concat = require('gulp-concat');
var wrap = require("gulp-wrap-js");
var embedTemplates = require('gulp-angular-embed-templates');
module.exports = function(files, out) {
@@ -22,6 +23,7 @@ module.exports = function(files, out) {
// sort files in stream by path or any custom sort comparator
task = task.pipe(babel())
.pipe(sort())
.pipe(embedTemplates({ basePath: "./src/" }))
.pipe(concat(out))
.pipe(wrap('(function(){\n%= body %\n})();'))
.pipe(gulp.dest(config.root + config.targets.js));
@@ -29,4 +31,4 @@ module.exports = function(files, out) {
return task;
};
};
+323 -46
View File
@@ -1122,6 +1122,12 @@
"integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=",
"dev": true
},
"argh": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/argh/-/argh-0.1.4.tgz",
"integrity": "sha1-PrTWEpc/xrbcbvM49W91nyrFw6Y=",
"dev": true
},
"argparse": {
"version": "1.0.10",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
@@ -1216,7 +1222,7 @@
"arraybuffer.slice": {
"version": "0.0.7",
"resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz",
"integrity": "sha1-O7xCdd1YTMGxCAm4nU6LY6aednU=",
"integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==",
"dev": true
},
"asap": {
@@ -1253,6 +1259,15 @@
"integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==",
"dev": true
},
"async": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz",
"integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==",
"dev": true,
"requires": {
"lodash": "^4.17.11"
}
},
"async-each": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz",
@@ -1269,7 +1284,7 @@
"async-limiter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz",
"integrity": "sha1-ePrtjD0HSrgfIrTphdeehzj3IPg=",
"integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==",
"dev": true
},
"asynckit": {
@@ -1520,7 +1535,7 @@
},
"bl": {
"version": "1.2.2",
"resolved": "http://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
"resolved": "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz",
"integrity": "sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA==",
"dev": true,
"requires": {
@@ -1536,7 +1551,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@@ -1551,7 +1566,7 @@
},
"string_decoder": {
"version": "1.1.1",
"resolved": "http://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"requires": {
@@ -1725,7 +1740,7 @@
"buffer-alloc": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz",
"integrity": "sha1-iQ3ZDZI6hz4I4Q5f1RpX5bfM4Ow=",
"integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==",
"dev": true,
"requires": {
"buffer-alloc-unsafe": "^1.1.0",
@@ -1735,7 +1750,7 @@
"buffer-alloc-unsafe": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz",
"integrity": "sha1-vX3CauKXLQ7aJTvgYdupkjScGfA=",
"integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==",
"dev": true
},
"buffer-crc32": {
@@ -1920,9 +1935,9 @@
}
},
"caniuse-lite": {
"version": "1.0.30000913",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000913.tgz",
"integrity": "sha512-PP7Ypc35XY1mNduHqweGNOp0qfNUCmaQauGOYDByvirlFjrzRyY72pBRx7jnBidOB8zclg00DAzsy2H475BouQ==",
"version": "1.0.30000967",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000967.tgz",
"integrity": "sha512-rUBIbap+VJfxTzrM4akJ00lkvVb5/n5v3EGXfWzSH5zT8aJmGzjA8HWhJ4U6kCpzxozUSnB+yvAYDRPY6mRpgQ==",
"dev": true
},
"canonical-path": {
@@ -2111,6 +2126,20 @@
}
}
},
"cli-color": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/cli-color/-/cli-color-1.4.0.tgz",
"integrity": "sha512-xu6RvQqqrWEo6MPR1eixqGPywhYBHRs653F9jfXB2Hx4jdM/3WxiNE1vppRmxtMIfl16SFYTpYlrnqH/HsK/2w==",
"dev": true,
"requires": {
"ansi-regex": "^2.1.1",
"d": "1",
"es5-ext": "^0.10.46",
"es6-iterator": "^2.0.3",
"memoizee": "^0.4.14",
"timers-ext": "^0.1.5"
}
},
"cli-cursor": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz",
@@ -2287,12 +2316,40 @@
"integrity": "sha1-k4NDeaHMmgxh+C9S8NBDIiUb1aI=",
"dev": true
},
"colornames": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz",
"integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y=",
"dev": true
},
"colors": {
"version": "1.1.2",
"resolved": "http://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
"integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=",
"dev": true
},
"colorspace": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.1.tgz",
"integrity": "sha512-pI3btWyiuz7Ken0BWh9Elzsmv2bM9AhA7psXib4anUXy/orfZ/E0MbQwhSOG/9L8hLlalqrU0UhOuqxW1YjmVw==",
"dev": true,
"requires": {
"color": "3.0.x",
"text-hex": "1.0.x"
},
"dependencies": {
"color": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz",
"integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==",
"dev": true,
"requires": {
"color-convert": "^1.9.1",
"color-string": "^1.5.2"
}
}
}
},
"combine-lists": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/combine-lists/-/combine-lists-1.0.1.tgz",
@@ -2459,7 +2516,7 @@
"content-type": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
"integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=",
"integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
"dev": true
},
"continuable-cache": {
@@ -3417,6 +3474,17 @@
"integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=",
"dev": true
},
"diagnostics": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz",
"integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==",
"dev": true,
"requires": {
"colorspace": "1.1.x",
"enabled": "1.0.x",
"kuler": "1.0.x"
}
},
"diff": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
@@ -3467,6 +3535,15 @@
"integrity": "sha512-SQVCLFS2E7G5CRCMdn6K9bIhRj1bS6QBWZfF0TUPh4V/BbqrQ619IdSS3/izn0FZ+9l+uODzaZjb08fjOfablA==",
"dev": true
},
"domhandler": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
"integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
"dev": true,
"requires": {
"domelementtype": "1"
}
},
"domutils": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
@@ -3921,6 +3998,21 @@
"integrity": "sha512-EV5FZ68Hu+n9fHVhOc9AcG3Lvf+E1YqR36ulJUpwaQTkf4LwdvBqmGIazaIrt4kt6J8Gw3Kv7r9F+PQjAkjWeA==",
"dev": true
},
"emits": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/emits/-/emits-3.0.0.tgz",
"integrity": "sha1-MnUrupXhcHshlWI4Srm7ix/WL3A=",
"dev": true
},
"enabled": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz",
"integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=",
"dev": true,
"requires": {
"env-variable": "0.0.x"
}
},
"encodeurl": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
@@ -3953,7 +4045,7 @@
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"dev": true,
"requires": {
"ms": "2.0.0"
@@ -3969,7 +4061,7 @@
},
"engine.io-client": {
"version": "3.2.1",
"resolved": "http://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz",
"resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz",
"integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==",
"dev": true,
"requires": {
@@ -3989,7 +4081,7 @@
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"dev": true,
"requires": {
"ms": "2.0.0"
@@ -4028,6 +4120,12 @@
"integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
"dev": true
},
"env-variable": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.5.tgz",
"integrity": "sha512-zoB603vQReOFvTg5xMl9I1P2PnHsHQQKTEowsKKD7nseUfJq6UWzK+4YtlWUO1nhiQUxe6XMkk+JleSZD1NZFA==",
"dev": true
},
"errno": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz",
@@ -4119,6 +4217,18 @@
"es5-ext": "~0.10.14"
}
},
"es6-weak-map": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz",
"integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=",
"dev": true,
"requires": {
"d": "1",
"es5-ext": "^0.10.14",
"es6-iterator": "^2.0.1",
"es6-symbol": "^3.1.1"
}
},
"escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
@@ -4338,6 +4448,16 @@
"integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
"dev": true
},
"event-emitter": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
"integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=",
"dev": true,
"requires": {
"d": "1",
"es5-ext": "~0.10.14"
}
},
"event-stream": {
"version": "3.3.5",
"resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.5.tgz",
@@ -4356,13 +4476,13 @@
"eventemitter3": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.0.tgz",
"integrity": "sha1-CQtNbNvWRe0Qv3UNS1QHlC17oWM=",
"integrity": "sha512-ivIvhpq/Y0uSjcHDcOIccjmYjGLcP09MFGE7ysAwkAvkXfpZlC985pH2/ui64DKazbTW/4kN3yqozUxlXzI6cA==",
"dev": true
},
"exec-buffer": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/exec-buffer/-/exec-buffer-3.2.0.tgz",
"integrity": "sha1-sWhtvZBMfPmC5lLB9aebHlVzCCs=",
"integrity": "sha512-wsiD+2Tp6BWHoVv3B+5Dcx6E7u5zky+hUwOHjuH2hKSLR3dvRmX8fk8UD8uqQixHs4Wk6eDmiegVrMPjKj7wpA==",
"dev": true,
"optional": true,
"requires": {
@@ -5124,7 +5244,7 @@
"fs-constants": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
"integrity": "sha1-a+Dem+mYzhavivwkSXue6bfM2a0=",
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==",
"dev": true
},
"fs-extra": {
@@ -5189,7 +5309,8 @@
"ansi-regex": {
"version": "2.1.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"aproba": {
"version": "1.2.0",
@@ -5210,12 +5331,14 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@@ -5230,17 +5353,20 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
@@ -5357,7 +5483,8 @@
"inherits": {
"version": "2.0.3",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"ini": {
"version": "1.3.5",
@@ -5369,6 +5496,7 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@@ -5383,6 +5511,7 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@@ -5390,12 +5519,14 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"minipass": {
"version": "2.2.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.1",
"yallist": "^3.0.0"
@@ -5414,6 +5545,7 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@@ -5494,7 +5626,8 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
@@ -5506,6 +5639,7 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@@ -5591,7 +5725,8 @@
"safe-buffer": {
"version": "5.1.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"safer-buffer": {
"version": "2.1.2",
@@ -5627,6 +5762,7 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@@ -5646,6 +5782,7 @@
"version": "3.0.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@@ -5689,12 +5826,14 @@
"wrappy": {
"version": "1.0.2",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"yallist": {
"version": "3.0.2",
"bundled": true,
"dev": true
"dev": true,
"optional": true
}
}
},
@@ -6185,6 +6324,27 @@
}
}
},
"gulp-angular-embed-templates": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/gulp-angular-embed-templates/-/gulp-angular-embed-templates-2.3.0.tgz",
"integrity": "sha1-wBDv3VlN7pRRMoNFN9eSOt6EDXk=",
"dev": true,
"requires": {
"gulp-util": "^3.0.6",
"htmlparser2": "~3.9.1",
"minimize": "^2.0.0",
"object-assign": "4.1.0",
"through2": "^2.0.1"
},
"dependencies": {
"object-assign": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.0.tgz",
"integrity": "sha1-ejs9DpgGPUP0wD8uiubNUahog6A=",
"dev": true
}
}
},
"gulp-babel": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/gulp-babel/-/gulp-babel-8.0.0.tgz",
@@ -7415,7 +7575,7 @@
"has-binary2": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz",
"integrity": "sha1-d3asYn8+p3JQz8My2rfd9eT10R0=",
"integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==",
"dev": true,
"requires": {
"isarray": "2.0.1"
@@ -7537,6 +7697,58 @@
"integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==",
"dev": true
},
"htmlparser2": {
"version": "3.9.2",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz",
"integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=",
"dev": true,
"requires": {
"domelementtype": "^1.3.0",
"domhandler": "^2.3.0",
"domutils": "^1.5.1",
"entities": "^1.1.1",
"inherits": "^2.0.1",
"readable-stream": "^2.0.2"
},
"dependencies": {
"domelementtype": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
"integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
"dev": true
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
"dev": true
},
"readable-stream": {
"version": "2.3.6",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"requires": {
"safe-buffer": "~5.1.0"
}
}
}
},
"http-errors": {
"version": "1.6.3",
"resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
@@ -7566,7 +7778,7 @@
"http-proxy": {
"version": "1.17.0",
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz",
"integrity": "sha1-etOElGWPhGBeL220Q230EPTlvpo=",
"integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==",
"dev": true,
"requires": {
"eventemitter3": "^3.0.0",
@@ -8306,9 +8518,9 @@
}
},
"jquery": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz",
"integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg=="
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.4.0.tgz",
"integrity": "sha512-ggRCXln9zEqv6OqAGXFEcshF5dSBvCkzj6Gm2gzuR5fWawaX8t7cxKVkkygKODrDAzKdoYw3l/e3pm3vlT4IbQ=="
},
"jquery-ui-dist": {
"version": "1.12.1",
@@ -8560,6 +8772,15 @@
}
}
},
"kuler": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz",
"integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==",
"dev": true,
"requires": {
"colornames": "^1.1.1"
}
},
"lazy-cache": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
@@ -9114,7 +9335,7 @@
"lowercase-keys": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
"integrity": "sha1-b54wtHCE2XGnyCD/FabFFnt0wm8=",
"integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==",
"dev": true
},
"lpad-align": {
@@ -9136,10 +9357,19 @@
"integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=",
"dev": true
},
"lru-queue": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz",
"integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=",
"dev": true,
"requires": {
"es5-ext": "~0.10.2"
}
},
"make-dir": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
"integrity": "sha1-ecEDO4BRW9bSTsmTPoYMp17ifww=",
"integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
"dev": true,
"requires": {
"pify": "^3.0.0"
@@ -9225,6 +9455,22 @@
"integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
"dev": true
},
"memoizee": {
"version": "0.4.14",
"resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.14.tgz",
"integrity": "sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg==",
"dev": true,
"requires": {
"d": "1",
"es5-ext": "^0.10.45",
"es6-weak-map": "^2.0.2",
"event-emitter": "^0.3.5",
"is-promise": "^2.1",
"lru-queue": "0.1",
"next-tick": "1",
"timers-ext": "^0.1.5"
}
},
"meow": {
"version": "3.7.0",
"resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
@@ -9355,6 +9601,21 @@
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
"dev": true
},
"minimize": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/minimize/-/minimize-2.2.0.tgz",
"integrity": "sha512-IxR2XMbw9pXCxApkdD9BTcH2U4XlXhbeySUrv71rmMS9XDA8BVXEsIuFu24LtwCfBgfbL7Fuh8/ZzkO5DaTLlQ==",
"dev": true,
"requires": {
"argh": "^0.1.4",
"async": "^2.1.5",
"cli-color": "^1.2.0",
"diagnostics": "^1.1.0",
"emits": "^3.0.0",
"htmlparser2": "^3.9.2",
"uuid": "^3.0.0"
}
},
"mixin-deep": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz",
@@ -12474,7 +12735,7 @@
"dependencies": {
"minimist": {
"version": "0.0.10",
"resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
"integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=",
"dev": true
},
@@ -13355,7 +13616,7 @@
"qjobs": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz",
"integrity": "sha1-xF6cYYAL0IfviNfiVkI73Unl0HE=",
"integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==",
"dev": true
},
"qs": {
@@ -14514,7 +14775,7 @@
},
"socket.io-parser": {
"version": "3.2.0",
"resolved": "http://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz",
"resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz",
"integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==",
"dev": true,
"requires": {
@@ -14526,7 +14787,7 @@
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"dev": true,
"requires": {
"ms": "2.0.0"
@@ -14659,7 +14920,7 @@
},
"chalk": {
"version": "1.1.3",
"resolved": "http://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
"optional": true,
@@ -15067,7 +15328,7 @@
"strip-outer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz",
"integrity": "sha1-sv0qv2YEudHmATBXGV34Nrip1jE=",
"integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==",
"dev": true,
"requires": {
"escape-string-regexp": "^1.0.2"
@@ -15227,7 +15488,7 @@
},
"readable-stream": {
"version": "2.3.6",
"resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
"dev": true,
"requires": {
@@ -15269,6 +15530,12 @@
"uuid": "^3.0.1"
}
},
"text-hex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
"integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==",
"dev": true
},
"text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
@@ -15369,6 +15636,16 @@
"integrity": "sha1-lYYL/MXHbCd/j4Mm/Q9bLiDrohc=",
"dev": true
},
"timers-ext": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz",
"integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==",
"dev": true,
"requires": {
"es5-ext": "~0.10.46",
"next-tick": "1"
}
},
"timsort": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz",
@@ -15454,7 +15731,7 @@
"to-buffer": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz",
"integrity": "sha1-STvUj2LXxD/N7TE6A9ytsuEhOoA=",
"integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==",
"dev": true
},
"to-fast-properties": {
@@ -15583,7 +15860,7 @@
"type-is": {
"version": "1.6.16",
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz",
"integrity": "sha1-+JzjQVQcZysl7nrjxz3uOyvlAZQ=",
"integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==",
"dev": true,
"requires": {
"media-typer": "0.3.0",
@@ -15625,7 +15902,7 @@
"ultron": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz",
"integrity": "sha1-n+FTahCmZKZSZqHjzPhf02MCvJw=",
"integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==",
"dev": true
},
"unc-path-regex": {
@@ -16228,7 +16505,7 @@
"ws": {
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz",
"integrity": "sha1-8c+E/i1ekB686U767OeF8YeiKPI=",
"integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==",
"dev": true,
"requires": {
"async-limiter": "~1.0.0",
+4 -2
View File
@@ -29,7 +29,7 @@
"diff": "3.5.0",
"flatpickr": "4.5.2",
"font-awesome": "4.7.0",
"jquery": "3.3.1",
"jquery": "^3.4.0",
"jquery-ui-dist": "1.12.1",
"jquery-ui-touch-punch": "0.2.3",
"lazyload-js": "1.0.0",
@@ -50,6 +50,7 @@
"cssnano": "4.1.7",
"fs": "0.0.2",
"gulp": "^3.9.1",
"gulp-angular-embed-templates": "^2.3.0",
"gulp-babel": "8.0.0",
"gulp-clean-css": "4.0.0",
"gulp-cli": "^2.0.1",
@@ -76,6 +77,7 @@
"lodash": "4.17.11",
"marked": "^0.5.2",
"merge-stream": "1.0.1",
"run-sequence": "2.2.1"
"run-sequence": "2.2.1",
"caniuse-lite": "^1.0.30000966"
}
}
@@ -1,7 +1,7 @@
(function () {
"use strict";
function AppHeaderDirective(eventsService, appState, userService) {
function AppHeaderDirective(eventsService, appState, userService, focusService) {
function link(scope, el, attr, ctrl) {
@@ -54,7 +54,9 @@
}
});
}));
scope.rememberFocus = focusService.rememberFocus;
scope.searchClick = function() {
var showSearch = appState.getSearchState("show");
appState.setSearchState("show", !showSearch);
@@ -101,4 +103,4 @@
angular.module("umbraco.directives").directive("umbAppHeader", AppHeaderDirective);
})();
})();
@@ -16,7 +16,6 @@
function UmbLoginController($scope, $location, currentUserResource, formHelper, mediaHelper, umbRequestHelper, Upload, localizationService, userService, externalLoginInfo, resetPasswordCodeInfo, $timeout, authResource, $q) {
const vm = this;
let twoFactorloginDialog = null;
vm.invitedUser = null;
@@ -69,7 +68,9 @@
).then(function (data) {
vm.labels.usernameLabel = data[0];
vm.labels.usernamePlaceholder = data[1];
})
});
vm.twoFactor = {};
function onInit() {
@@ -126,6 +127,7 @@
function togglePassword() {
var elem = $("form[name='vm.loginForm'] input[name='password']");
elem.attr("type", (elem.attr("type") === "text" ? "password" : "text"));
elem.focus();
$(".password-text.show, .password-text.hide").toggle();
}
@@ -186,15 +188,18 @@
vm.view = "set-password";
}
function loginSubmit(login, password) {
function loginSubmit() {
// make sure that we are returning to the login view.
vm.view = "login";
// TODO: Do validation properly like in the invite password update
//if the login and password are not empty we need to automatically
// validate them - this is because if there are validation errors on the server
// then the user has to change both username & password to resubmit which isn't ideal,
// so if they're not empty, we'll just make sure to set them to valid.
if (login && password && login.length > 0 && password.length > 0) {
if (vm.login && vm.password && vm.login.length > 0 && vm.password.length > 0) {
vm.loginForm.username.$setValidity('auth', true);
vm.loginForm.password.$setValidity('auth', true);
}
@@ -205,7 +210,7 @@
vm.loginStates.submitButton = "busy";
userService.authenticate(login, password)
userService.authenticate(vm.login, vm.password)
.then(function (data) {
vm.loginStates.submitButton = "success";
userService._retryRequestQueue(true);
@@ -218,7 +223,7 @@
//is Two Factor required?
if (reason.status === 402) {
vm.errorMsg = "Additional authentication required";
show2FALoginDialog(reason.data.twoFactorView, submit);
show2FALoginDialog(reason.data.twoFactorView);
}
else {
vm.loginStates.submitButton = "error";
@@ -402,8 +407,12 @@
});
}
function show2FALoginDialog(view, callback) {
// TODO: show 2FA window
function show2FALoginDialog(viewPath) {
vm.twoFactor.submitCallback = function submitCallback() {
vm.onLogin();
}
vm.twoFactor.view = viewPath;
vm.view = "2fa-login";
}
function resetInputValidation() {
@@ -13,7 +13,7 @@
}
};
function umbSearchController($timeout, backdropService, searchService) {
function umbSearchController($timeout, backdropService, searchService, focusService) {
var vm = this;
@@ -25,6 +25,9 @@
vm.handleKeyUp = handleKeyUp;
vm.closeSearch = closeSearch;
vm.focusSearch = focusSearch;
//we need to capture the focus before this element is initialized.
vm.focusBeforeOpening = focusService.getLastKnownFocus();
function onInit() {
vm.searchQuery = "";
@@ -70,6 +73,10 @@
* @param {object} event
*/
function handleKeyUp(event) {
event.stopPropagation();
event.preventDefault();
// esc
if(event.keyCode === 27) {
closeSearch();
@@ -80,6 +87,9 @@
* Used to proxy a callback
*/
function closeSearch() {
if(vm.focusBeforeOpening) {
vm.focusBeforeOpening.focus();
}
if(vm.onClose) {
vm.onClose();
}
@@ -115,4 +125,4 @@
angular.module('umbraco.directives').component('umbSearch', umbSearch);
})();
})();
@@ -117,6 +117,8 @@ Use this directive to render an umbraco button. The directive can be used to gen
vm.innerState = "init";
vm.buttonLabel = vm.label;
// is this a primary button style (i.e. anything but an 'info' button)?
vm.isPrimaryButtonStyle = vm.buttonStyle && vm.buttonStyle !== 'info';
if (vm.buttonStyle) {
@@ -0,0 +1,105 @@
/**
@ngdoc directive
@name umbraco.directives.directive:umbToggleGroup
@restrict E
@scope
@description
Use this directive to render a group of toggle buttons.
<h3>Markup example</h3>
<pre>
<div ng-controller="My.Controller as vm">
<umb-toggle-group
items="vm.items"
on-click="vm.toggle(item)">
</umb-toggle-group>
</div>
</pre>
<h3>Controller example</h3>
<pre>
(function () {
"use strict";
function Controller() {
var vm = this;
vm.toggle = toggle;
function toggle(item) {
if(item.checked) {
// do something if item is checked
}
else {
// do something else if item is unchecked
}
}
function init() {
vm.items = [{
name: "Item 1",
description: "Item 1 description",
checked: false,
disabled: false
}, {
name: "Item 2",
description: "Item 2 description",
checked: true,
disabled: true
}];
}
init();
}
angular.module("umbraco").controller("My.Controller", Controller);
})();
</pre>
@param {Array} items The items to list in the toggle group
@param {callback} onClick The function which should be called when the toggle is clicked for one of the items.
**/
(function () {
'use strict';
function ToggleGroupDirective() {
function link(scope, el, attr, ctrl) {
scope.change = function(item) {
if (item.disabled) {
return;
}
item.checked = !item.checked;
if(scope.onClick) {
scope.onClick({'item': item});
}
};
}
var directive = {
restrict: 'E',
replace: true,
templateUrl: 'views/components/buttons/umb-toggle-group.html',
scope: {
items: "=",
onClick: "&"
},
link: link
};
return directive;
}
angular.module('umbraco.directives').directive('umbToggleGroup', ToggleGroupDirective);
})();
@@ -55,9 +55,9 @@
}
}
// if we still dont have a app, lets show the first one:
if (isAppPresent === false) {
if (isAppPresent === false && content.apps.length) {
content.apps[0].active = true;
$scope.appChanged(content.apps[0]);
}
@@ -198,9 +198,11 @@
return a.alias === "umbContent";
});
//The view model for the content app is simply the index of the variant being edited
var variantIndex = vm.content.variants.indexOf(variant);
contentApp.viewModel = variantIndex;
if (contentApp) {
//The view model for the content app is simply the index of the variant being edited
var variantIndex = vm.content.variants.indexOf(variant);
contentApp.viewModel = variantIndex;
}
// make sure the same app it set to active in the new variant
if(activeAppAlias) {
@@ -47,6 +47,9 @@ The sub header is sticky and will follow along down the page when scrolling.
transclude: true,
restrict: 'E',
replace: true,
scope: {
"appearance": "@?"
},
templateUrl: 'views/components/editor/subheader/umb-editor-sub-header.html'
};
@@ -4,7 +4,7 @@
**/
angular.module("umbraco.directives")
.directive('hotkey', function($window, keyboardService, $log) {
.directive('hotkey', function($window, keyboardService, $log, focusService) {
return function(scope, el, attrs) {
@@ -28,7 +28,9 @@ angular.module("umbraco.directives")
}
keyboardService.bind(keyCombo, function() {
focusService.rememberFocus();
var element = $(el);
var activeElementType = document.activeElement.tagName;
var clickableElements = ["A", "BUTTON"];
@@ -6,7 +6,7 @@
**/
angular.module("umbraco.directives")
.directive('umbImageCrop',
function ($timeout, localizationService, cropperHelper, $log) {
function ($timeout, cropperHelper) {
return {
restrict: 'E',
replace: true,
@@ -21,6 +21,9 @@ angular.module("umbraco.directives")
},
link: function(scope, element, attrs) {
let sliderRef = null;
scope.width = 400;
scope.height = 320;
@@ -30,12 +33,56 @@ angular.module("umbraco.directives")
viewport:{},
margin: 20,
scale: {
min: 0.3,
min: 0,
max: 3,
current: 1
}
};
};
scope.sliderOptions = {
"start": scope.dimensions.scale.current,
"step": 0.001,
"tooltips": [false],
"format": {
to: function (value) {
return parseFloat(parseFloat(value).toFixed(3)); //Math.round(value);
},
from: function (value) {
return parseFloat(parseFloat(value).toFixed(3)); //Math.round(value);
}
},
"range": {
"min": scope.dimensions.scale.min,
"max": scope.dimensions.scale.max
}
};
scope.setup = function (slider) {
sliderRef = slider;
// Set slider handle position
sliderRef.noUiSlider.set(scope.dimensions.scale.current);
// Update slider range min/max
sliderRef.noUiSlider.updateOptions({
"range": {
"min": scope.dimensions.scale.min,
"max": scope.dimensions.scale.max
}
});
};
scope.slide = function (values) {
if (values) {
scope.dimensions.scale.current = parseFloat(values);
}
};
scope.change = function (values) {
if (values) {
scope.dimensions.scale.current = parseFloat(values);
}
};
//live rendering of viewport and image styles
scope.style = function () {
@@ -63,7 +110,6 @@ angular.module("umbraco.directives")
constraints.top.min = scope.dimensions.margin + scope.dimensions.cropper.height - scope.dimensions.image.height;
};
var setDimensions = function(originalImage){
originalImage.width("auto");
originalImage.height("auto");
@@ -131,13 +177,11 @@ angular.module("umbraco.directives")
scope.dimensions.scale.current = scope.dimensions.image.ratio;
//min max based on original width/height
// Update min and max based on original width/height
scope.dimensions.scale.min = ratioCalculation.ratio;
scope.dimensions.scale.max = 2;
scope.dimensions.scale.max = 2;
};
var validatePosition = function(left, top){
if(left > constraints.left.max)
{
@@ -191,8 +235,6 @@ angular.module("umbraco.directives")
}
});
var init = function(image){
scope.loaded = false;
@@ -219,10 +261,10 @@ angular.module("umbraco.directives")
};
/// WATCHERS ////
// Watchers
scope.$watchCollection('[width, height]', function(newValues, oldValues){
//we have to reinit the whole thing if
//one of the external params changes
// We have to reinit the whole thing if
// one of the external params changes
if(newValues !== oldValues){
setDimensions($image);
setConstraints();
@@ -230,29 +272,18 @@ angular.module("umbraco.directives")
});
var throttledResizing = _.throttle(function(){
resizeImageToScale(scope.dimensions.scale.current);
resizeImageToScale(scope.dimensions.scale.current);
calculateCropBox();
}, 15);
//happens when we change the scale
scope.$watch("dimensions.scale.current", function(){
if(scope.loaded){
// Happens when we change the scale
scope.$watch("dimensions.scale.current", function (newValue, oldValue) {
if (scope.loaded) {
throttledResizing();
}
});
//ie hack
if(window.navigator.userAgent.indexOf("MSIE ") >= 0){
var ranger = element.find("input");
ranger.on("change",function(){
scope.$apply(function(){
scope.dimensions.scale.current = ranger.val();
});
});
}
//// INIT /////
// Init
$image.on("load", function(){
$timeout(function(){
init($image);
@@ -295,7 +295,8 @@ Opens an overlay to show a custom YSOD. </br>
scope.closeOverLay();
});
}
event.stopPropagation();
event.preventDefault();
}
@@ -511,6 +512,7 @@ Opens an overlay to show a custom YSOD. </br>
model: "=",
view: "=",
position: "@",
size: "=?",
parentScope: "=?"
},
link: link
@@ -41,6 +41,7 @@
vm.removeTag = removeTag;
vm.showPrompt = showPrompt;
vm.hidePrompt = hidePrompt;
vm.onKeyUpOnTag = onKeyUpOnTag;
vm.htmlId = "t" + String.CreateGuid();
vm.isLoading = true;
@@ -272,6 +273,12 @@
vm.promptIsVisible = "-1";
}
function onKeyUpOnTag(tag, $event) {
if ($event.keyCode === 8 || $event.keyCode === 46) {
removeTag(tag);
}
}
// helper method to remove current tags
function removeCurrentTagsFromSuggestions(suggestions) {
return $.grep(suggestions, function (suggestion) {
@@ -12,6 +12,7 @@ function treeSearchBox(localizationService, searchService, $q) {
searchFromName: "@",
showSearch: "@",
section: "@",
ignoreUserStartNodes: "@",
hideSearchCallback: "=",
searchCallback: "="
},
@@ -34,6 +35,7 @@ function treeSearchBox(localizationService, searchService, $q) {
scope.showSearch = "false";
}
//used to cancel any request in progress if another one needs to take it's place
var canceler = null;
@@ -60,6 +62,11 @@ function treeSearchBox(localizationService, searchService, $q) {
searchArgs["searchFrom"] = scope.searchFromId;
}
//append ignoreUserStartNodes value if there is one
if (scope.ignoreUserStartNodes) {
searchArgs["ignoreUserStartNodes"] = scope.ignoreUserStartNodes;
}
searcher(searchArgs).then(function (data) {
scope.searchCallback(data);
//set back to null so it can be re-created
@@ -60,6 +60,7 @@ function confirmDirective() {
link: function (scope, element, attr, ctrl) {
scope.showCancel = false;
scope.showConfirm = false;
scope.confirmButtonState = "init";
if (scope.onConfirm) {
scope.showConfirm = true;
@@ -68,6 +69,15 @@ function confirmDirective() {
if (scope.onCancel) {
scope.showCancel = true;
}
scope.confirm = function () {
if (!scope.onConfirm) {
return;
}
scope.confirmButtonState = "busy";
scope.onConfirm();
}
}
};
}
@@ -3,7 +3,7 @@
function () {
var link = function ($scope) {
// Clone the model because some property editors
// do weird things like updating and config values
// so we want to ensure we start from a fresh every
@@ -12,10 +12,10 @@
$scope.nodeContext = $scope.model;
// Find the selected tab
var selectedTab = $scope.model.tabs[0];
var selectedTab = $scope.model.variants[0].tabs[0];
if ($scope.tabAlias) {
angular.forEach($scope.model.tabs, function (tab) {
angular.forEach($scope.model.variants[0].tabs, function (tab) {
if (tab.alias.toLowerCase() === $scope.tabAlias.toLowerCase()) {
selectedTab = tab;
return;
@@ -31,9 +31,9 @@
// Tell inner controls we are submitting
$scope.$broadcast("formSubmitting", { scope: $scope });
// Sync the values back
angular.forEach($scope.ngModel.tabs, function (tab) {
angular.forEach($scope.ngModel.variants[0].tabs, function (tab) {
if (tab.alias.toLowerCase() === selectedTab.alias.toLowerCase()) {
var localPropsMap = selectedTab.properties.reduce(function (map, obj) {
@@ -94,4 +94,4 @@
// },
// link: link
// }
//});
//});
@@ -91,6 +91,10 @@ Use this directive to generate a pagination.
function link(scope, el, attr, ctrl) {
function activate() {
// page number is sometimes a string - let's make sure it's an int before we do anything with it
if (scope.pageNumber) {
scope.pageNumber = parseInt(scope.pageNumber);
}
scope.pagination = [];
@@ -1,36 +0,0 @@
(function () {
'use strict';
function PermissionDirective() {
function link(scope, el, attr, ctrl) {
scope.change = function() {
scope.selected = !scope.selected;
if(scope.onChange) {
scope.onChange({'selected': scope.selected});
}
};
}
var directive = {
restrict: 'E',
replace: true,
templateUrl: 'views/components/users/umb-permission.html',
scope: {
name: "=",
description: "=?",
selected: "=",
onChange: "&"
},
link: link
};
return directive;
}
angular.module('umbraco.directives').directive('umbPermission', PermissionDirective);
})();
@@ -0,0 +1,31 @@
/**
* @ngdoc filter
* @name umbraco.filters.filter:truncate
* @namespace truncateFilter
*
* param {any} wordwise if true, the string will be cut after last fully displayed word.
* param {any} max max length of the outputtet string
* param {any} tail option tail, defaults to: ' ...'
*
* @description
* Limits the length of a string, if a cut happens only the string will be appended with three dots to indicate that more is available.
*/
angular.module("umbraco.filters").filter('truncate',
function () {
return function (value, wordwise, max, tail) {
if (!value) return '';
max = parseInt(max, 10);
if (!max) return value;
if (value.length <= max) return value;
value = value.substr(0, max);
if (wordwise) {
var lastspace = value.lastIndexOf(' ');
if (lastspace != -1) {
value = value.substr(0, lastspace);
}
}
return value + (tail || (wordwise ? ' …' : '…'));
};
}
);
@@ -59,20 +59,27 @@
}
//A 401 means that the user is not logged in
if (rejection.status === 401 && !rejection.config.url.endsWith("umbraco/backoffice/UmbracoApi/Authentication/GetCurrentUser")) {
if (rejection.status === 401) {
//avoid an infinite loop
var umbRequestHelper = $injector.get('umbRequestHelper');
var getCurrentUserPath = umbRequestHelper.getApiUrl("authenticationApiBaseUrl", "GetCurrentUser");
if (!rejection.config.url.endsWith(getCurrentUserPath)) {
var userService = $injector.get('userService'); // see above
var userService = $injector.get('userService'); // see above
//Associate the user name with the retry to ensure we retry for the right user
return userService.getCurrentUser()
.then(function (user) {
var userName = user ? user.name : null;
//The request bounced because it was not authorized - add a new request to the retry queue
return requestRetryQueue.pushRetryFn('unauthorized-server', userName, function retryRequest() {
// We must use $injector to get the $http service to prevent circular dependency
return $injector.get('$http')(rejection.config);
//Associate the user name with the retry to ensure we retry for the right user
return userService.getCurrentUser()
.then(function(user) {
var userName = user ? user.name : null;
//The request bounced because it was not authorized - add a new request to the retry queue
return requestRetryQueue.pushRetryFn('unauthorized-server',
userName,
function retryRequest() {
// We must use $injector to get the $http service to prevent circular dependency
return $injector.get('$http')(rejection.config);
});
});
});
}
}
else if (rejection.status === 404) {
@@ -215,14 +215,6 @@ angular.module('umbraco.mocks').
"placeholders_nameentity": "Name the %0%...",
"placeholders_search": "Type to search...",
"placeholders_filter": "Type to filter...",
"editcontenttype_allowedchildnodetypes": "Allowed child nodetypes",
"editcontenttype_create": "Create",
"editcontenttype_deletetab": "Delete tab",
"editcontenttype_description": "Description",
"editcontenttype_newtab": "New tab",
"editcontenttype_tab": "Tab",
"editcontenttype_thumbnail": "Thumbnail",
"editcontenttype_iscontainercontenttype": "Use as container content type",
"editdatatype_addPrevalue": "Add prevalue",
"editdatatype_dataBaseDatatype": "Database datatype",
"editdatatype_guid": "Property editor GUID",
@@ -365,17 +365,28 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) {
* </pre>
*
* @param {Int} id id of content item to return
* @param {Int} culture optional culture to retrieve the item in
* @param {Bool} options.ignoreUserStartNodes set to true to allow a user to choose nodes that they normally don't have access to
* @returns {Promise} resourcePromise object containing the content item.
*
*/
getById: function (id) {
getById: function (id, options) {
var defaults = {
ignoreUserStartNodes: false
};
if (options === undefined) {
options = {};
}
//overwrite the defaults if there are any specified
angular.extend(defaults, options);
//now copy back to the options we will use
options = defaults;
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"contentApiBaseUrl",
"GetById",
{ id: id })),
[{ id: id }, { ignoreUserStartNodes: options.ignoreUserStartNodes }])),
'Failed to retrieve data for content id ' + id)
.then(function (result) {
return $q.when(umbDataFormatter.formatContentGetData(result));
@@ -344,6 +344,12 @@ function contentTypeResource($q, $http, umbRequestHelper, umbDataFormatter, loca
$http.post(umbRequestHelper.getApiUrl("contentTypeApiBaseUrl", "Import", { file: file })),
"Failed to import document type " + file
);
},
createDefaultTemplate: function (id) {
return umbRequestHelper.resourcePromise(
$http.post(umbRequestHelper.getApiUrl("contentTypeApiBaseUrl", "PostCreateDefaultTemplate", { id: id })),
'Failed to create default template for content type with id ' + id);
}
};
}
@@ -284,15 +284,31 @@ function entityResource($q, $http, umbRequestHelper) {
* @returns {Promise} resourcePromise object containing the entity.
*
*/
getAncestors: function (id, type, culture) {
getAncestors: function (id, type, culture, options) {
var defaults = {
ignoreUserStartNodes: false
};
if (options === undefined) {
options = {};
}
//overwrite the defaults if there are any specified
angular.extend(defaults, options);
//now copy back to the options we will use
options = defaults;
if (culture === undefined) culture = "";
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"entityApiBaseUrl",
"GetAncestors",
[{ id: id }, { type: type }, { culture: culture }])),
'Failed to retrieve ancestor data for id ' + id);
[
{ id: id },
{ type: type },
{ culture: culture },
{ ignoreUserStartNodes: options.ignoreUserStartNodes }
])),
'Failed to retrieve ancestor data for id ' + id);
},
/**
@@ -424,7 +440,8 @@ function entityResource($q, $http, umbRequestHelper) {
pageNumber: 1,
filter: '',
orderDirection: "Ascending",
orderBy: "SortOrder"
orderBy: "SortOrder",
ignoreUserStartNodes: false
};
if (options === undefined) {
options = {};
@@ -453,7 +470,8 @@ function entityResource($q, $http, umbRequestHelper) {
pageSize: options.pageSize,
orderBy: options.orderBy,
orderDirection: options.orderDirection,
filter: encodeURIComponent(options.filter)
filter: encodeURIComponent(options.filter),
ignoreUserStartNodes: options.ignoreUserStartNodes
}
)),
'Failed to retrieve child data for id ' + parentId);
@@ -481,12 +499,19 @@ function entityResource($q, $http, umbRequestHelper) {
* @returns {Promise} resourcePromise object containing the entity array.
*
*/
search: function (query, type, searchFrom, canceler) {
search: function (query, type, options, canceler) {
var args = [{ query: query }, { type: type }];
if (searchFrom) {
args.push({ searchFrom: searchFrom });
if(options !== undefined) {
if (options.searchFrom) {
args.push({ searchFrom: options.searchFrom });
}
if (options.ignoreUserStartNodes) {
args.push({ ignoreUserStartNodes: options.ignoreUserStartNodes });
}
}
var httpConfig = {};
if (canceler) {
@@ -53,7 +53,7 @@ function logResource($q, $http, umbRequestHelper) {
*
* @param {Object} options options object
* @param {Int} options.id the id of the entity
* @param {Int} options.pageSize if paging data, number of nodes per page, default = 10, set to 0 to disable paging
* @param {Int} options.pageSize if paging data, number of nodes per page, default = 10
* @param {Int} options.pageNumber if paging data, current page index, default = 1
* @param {String} options.orderDirection can be `Ascending` or `Descending` - Default: `Descending`
* @param {Date} options.sinceDate if provided this will only get log entries going back to this date
@@ -122,7 +122,7 @@ function logResource($q, $http, umbRequestHelper) {
* </pre>
*
* @param {Object} options options object
* @param {Int} options.pageSize if paging data, number of nodes per page, default = 10, set to 0 to disable paging
* @param {Int} options.pageSize if paging data, number of nodes per page, default = 10
* @param {Int} options.pageNumber if paging data, current page index, default = 1
* @param {String} options.orderDirection can be `Ascending` or `Descending` - Default: `Descending`
* @param {Date} options.sinceDate if provided this will only get log entries going back to this date
@@ -329,7 +329,8 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
filter: '',
orderDirection: "Ascending",
orderBy: "SortOrder",
orderBySystemField: true
orderBySystemField: true,
ignoreUserStartNodes: false
};
if (options === undefined) {
options = {};
@@ -367,6 +368,7 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) {
"GetChildren",
[
{ id: parentId },
{ ignoreUserStartNodes: options.ignoreUserStartNodes },
{ pageNumber: options.pageNumber },
{ pageSize: options.pageSize },
{ orderBy: options.orderBy },
@@ -0,0 +1,203 @@
/**
* @ngdoc service
* @name umbraco.services.clipboardService
*
* @requires notificationsService
* @requires eventsService
*
* @description
* Service to handle clipboard in general across the application. Responsible for handling the data both storing and retrive.
* The service has a set way for defining a data-set by a entryType and alias, which later will be used to retrive the posible entries for a paste scenario.
*
*/
function clipboardService(notificationsService, eventsService, localStorageService) {
var STORAGE_KEY = "umbClipboardService";
var retriveStorage = function() {
if (localStorageService.isSupported === false) {
return null;
}
var dataJSON;
var dataString = localStorageService.get(STORAGE_KEY);
if (dataString != null) {
dataJSON = JSON.parse(dataString);
}
if(dataJSON == null) {
dataJSON = new Object();
}
if(dataJSON.entries === undefined) {
dataJSON.entries = [];
}
return dataJSON;
}
var saveStorage = function(storage) {
var storageString = JSON.stringify(storage);
try {
var storageJSON = JSON.parse(storageString);
localStorageService.set(STORAGE_KEY, storageString);
eventsService.emit("clipboardService.storageUpdate");
return true;
} catch(e) {
return false;
}
return false;
}
var service = {};
/**
* @ngdoc method
* @name umbraco.services.clipboardService#copy
* @methodOf umbraco.services.clipboardService
*
* @param {string} type A string defining the type of data to storing, example: 'elementType', 'contentNode'
* @param {string} alias A string defining the alias of the data to store, example: 'product'
* @param {object} data A object containing the properties to be saved.
*
* @description
* Saves a single JS-object with a type and alias to the clipboard.
*/
service.copy = function(type, alias, data) {
var storage = retriveStorage();
var shallowCloneData = Object.assign({}, data);// Notice only a shallow copy, since we dont need to deep copy. (that will happen when storing the data)
delete shallowCloneData.key;
delete shallowCloneData.$$hashKey;
var key = data.key || data.$$hashKey || console.error("missing unique key for this content");
// remove previous copies of this entry:
storage.entries = storage.entries.filter(
(entry) => {
return entry.unique !== key;
}
);
var entry = {unique:key, type:type, alias:alias, data:shallowCloneData};
storage.entries.push(entry);
if (saveStorage(storage) === true) {
notificationsService.success("Clipboard", "Copied to clipboard.");
} else {
notificationsService.success("Clipboard", "Couldnt copy this data to clipboard.");
}
};
/**
* @ngdoc method
* @name umbraco.services.supportsCopy#supported
* @methodOf umbraco.services.clipboardService
*
* @description
* Determins wether the current browser is able to performe its actions.
*/
service.isSupported = function() {
return localStorageService.isSupported;
};
/**
* @ngdoc method
* @name umbraco.services.supportsCopy#hasEntriesOfType
* @methodOf umbraco.services.clipboardService
*
* @param {string} type A string defining the type of data test for.
* @param {string} aliases A array of strings providing the alias of the data you want to test for.
*
* @description
* Determines whether the current clipboard has entries that match a given type and one of the aliases.
*/
service.hasEntriesOfType = function(type, aliases) {
if(service.retriveEntriesOfType(type, aliases).length > 0) {
return true;
}
return false;
};
/**
* @ngdoc method
* @name umbraco.services.supportsCopy#retriveEntriesOfType
* @methodOf umbraco.services.clipboardService
*
* @param {string} type A string defining the type of data to recive.
* @param {string} aliases A array of strings providing the alias of the data you want to recive.
*
* @description
* Returns an array of entries matching the given type and one of the provided aliases.
*/
service.retriveEntriesOfType = function(type, aliases) {
var storage = retriveStorage();
// Find entries that are fulfilling the criteria for this nodeType and nodeTypesAliases.
var filteretEntries = storage.entries.filter(
(entry) => {
return (entry.type === type && aliases.filter(alias => alias === entry.alias).length > 0);
}
);
return filteretEntries;
};
/**
* @ngdoc method
* @name umbraco.services.supportsCopy#retriveEntriesOfType
* @methodOf umbraco.services.clipboardService
*
* @param {string} type A string defining the type of data to recive.
* @param {string} aliases A array of strings providing the alias of the data you want to recive.
*
* @description
* Returns an array of data of entries matching the given type and one of the provided aliases.
*/
service.retriveDataOfType = function(type, aliases) {
return service.retriveEntriesOfType(type, aliases).map((x) => x.data);
};
/**
* @ngdoc method
* @name umbraco.services.supportsCopy#retriveEntriesOfType
* @methodOf umbraco.services.clipboardService
*
* @param {string} type A string defining the type of data to remove.
* @param {string} aliases A array of strings providing the alias of the data you want to remove.
*
* @description
* Removes entries matching the given type and one of the provided aliases.
*/
service.clearEntriesOfType = function(type, aliases) {
var storage = retriveStorage();
// Find entries that are NOT fulfilling the criteria for this nodeType and nodeTypesAliases.
var filteretEntries = storage.entries.filter(
(entry) => {
return !(entry.type === type && aliases.filter(alias => alias === entry.alias).length > 0);
}
);
storage.entries = filteretEntries;
saveStorage(storage);
};
return service;
}
@@ -112,6 +112,7 @@ When building a custom infinite editor view you can use the same components as a
type="button"
button-style="link"
label-key="general_close"
shortcut="esc"
action="vm.close()">
</umb-button>
<umb-button
@@ -163,9 +164,22 @@ When building a custom infinite editor view you can use the same components as a
"use strict";
function editorService(eventsService, keyboardService, $timeout) {
let editorsKeyboardShorcuts = [];
var editors = [];
var isEnabled = true;
// events for backdrop
eventsService.on("appState.backdrop", function (name, args) {
if (args.show === true) {
blur();
} else {
focus();
}
});
/**
* @ngdoc method
@@ -190,7 +204,43 @@ When building a custom infinite editor view you can use the same components as a
function getNumberOfEditors() {
return editors.length;
};
/**
* @ngdoc method
* @name umbraco.services.editorService#blur
* @methodOf umbraco.services.editorService
*
* @description
* Method to tell editors that they are begin blurred.
*/
function blur() {
/* keyboard shortcuts will be overwritten by the new infinite editor
so we need to store the shortcuts for the current editor so they can be rebound
when the infinite editor closes
*/
unbindKeyboardShortcuts();
isEnabled = false;
}
/**
* @ngdoc method
* @name umbraco.services.editorService#blur
* @methodOf umbraco.services.editorService
*
* @description
* Method to tell editors that they are gaining focus again.
*/
function focus() {
if(isEnabled === false) {
/* keyboard shortcuts will be overwritten by the new infinite editor
so we need to store the shortcuts for the current editor so they can be rebound
when the infinite editor closes
*/
rebindKeyboardShortcuts();
isEnabled = true;
}
}
/**
* @ngdoc method
* @name umbraco.services.editorService#open
@@ -201,7 +251,7 @@ When building a custom infinite editor view you can use the same components as a
*
* @param {Object} editor rendering options
* @param {String} editor.view Path to view
* @param {String} editor.size Sets the size of the editor ("Small"). If nothing is set it will use full width.
* @param {String} editor.size Sets the size of the editor ("small"). If nothing is set it will use full width.
*/
function open(editor) {
@@ -465,6 +515,8 @@ When building a custom infinite editor view you can use the same components as a
* @description
* Opens an icon picker in infinite editing, the submit callback returns the selected icon
* @param {Object} editor rendering options
* @param {String} editor.icon The CSS class representing the icon - eg. "icon-autofill".
* @param {String} editor.color The CSS class representing the color - eg. "color-red".
* @param {Callback} editor.submit Submits the editor
* @param {Callback} editor.close Closes the editor
* @returns {Object} editor object
@@ -0,0 +1,78 @@
/**
@ngdoc service
* @name umbraco.services.focusService
*
* @description
* <b>Added in Umbraco 8.1</b>. Application-wide service for focus related stuff.
*
*/
(function () {
"use strict";
function focusService() {
var currentFocus = null;
var lastKnownFocus = null;
function focusInApp(e) {
currentFocus = e.target;
}
document.addEventListener('focusin', focusInApp);
var service = {
/**
* @ngdoc function
* @name umbraco.services.focusService#getLastKnownFocus
* @methodOf umbraco.services.focusService
* @function
*
* @description
* Gives the element that was set to be remembered, the directive using this should store the value of this to make sure that its not changed white using that directive.
* This variable is avaiable for directives that are not able to figure out the focused element on init, and there this service will help remembering it untill the directive is initialized.
*
*/
getLastKnownFocus: function() {
return lastKnownFocus;
},
/**
* @ngdoc function
* @name umbraco.services.focusService#rememberFocus
* @methodOf umbraco.services.focusService
* @function
*
* @description
* Call this before a new focus is begin set, to be able to return to the focus before a given scenario.
*
*/
rememberFocus: function() {
lastKnownFocus = currentFocus;
},
/**
* @ngdoc function
* @name umbraco.services.focusService#setLastKnownFocus
* @methodOf umbraco.services.focusService
* @function
*
* @description
* Overwrite the element remembered as the last known element in focus.
*
*/
setLastKnownFocus: function(element) {
lastKnownFocus = element;
}
};
return service;
}
angular.module("umbraco.services").factory("focusService", focusService);
})();
@@ -45,7 +45,7 @@
(function () {
'use strict';
function listViewHelper(localStorageService) {
function listViewHelper($location, localStorageService, urlHelper) {
var firstSelectedIndex = 0;
var localStorageKey = "umblistViewLayout";
@@ -559,6 +559,32 @@
}
/**
* @ngdoc method
* @name umbraco.services.listViewHelper#editItem
* @methodOf umbraco.services.listViewHelper
*
* @description
* Method for opening an item in a list view for editing.
*
* @param {Object} item The item to edit
*/
function editItem(item) {
if (!item.editPath) {
return;
}
var parts = item.editPath.split("?");
var path = parts[0];
var params = parts[1]
? urlHelper.getQueryStringParams("?" + parts[1])
: {};
$location.path(path);
for (var p in params) {
$location.search(p, params[p]);
}
}
function isMatchingLayout(id, layout) {
// legacy format uses "nodeId", be sure to look for both
return layout.id === id || layout.nodeId === id;
@@ -579,7 +605,8 @@
isSelectedAll: isSelectedAll,
setSortingDirection: setSortingDirection,
setSorting: setSorting,
getButtonPermissions: getButtonPermissions
getButtonPermissions: getButtonPermissions,
editItem: editItem
};

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