Compare commits

..

124 Commits
4 ... 5.1.4

Author SHA1 Message Date
Guy Sartorelli
9202ce9a68
FIX Ensure react-select field menus are always on top (#2910) 2023-12-19 17:30:14 +13:00
Guy Sartorelli
ab2cfa0b1d
Merge pull request #2909 from creative-commoners/pulls/5.1/docblock
MNT Update @methods on class docblocks
2023-12-15 12:45:22 +13:00
Steve Boyd
fb5925b325 MNT Update @methods on class docblocks 2023-12-15 11:58:32 +13:00
Guy Sartorelli
8ca2ade623
Merge pull request #2908 from creative-commoners/pulls/5.1/fixtest
MNT Fix unit test
2023-12-06 15:00:12 +13:00
Steve Boyd
7027d654d2 MNT Fix unit test 2023-12-06 11:58:34 +13:00
Guy Sartorelli
04a0c928b3
Merge branch '4' into 5.1 2023-11-28 10:11:06 +13:00
github-actions
2ccbbc2e9c Merge branch '4' into 5.1 2023-11-11 13:24:05 +00:00
Guy Sartorelli
665b208d89
Merge pull request #2904 from creative-commoners/pulls/5.1/limit-100
FIX Limit Member map to 100
2023-11-09 09:49:27 +13:00
Steve Boyd
dd2bd61387 FIX Limit Member map to 100 2023-11-08 11:55:30 +13:00
Guy Sartorelli
eed9a79c19
Merge pull request #2898 from creative-commoners/pulls/5.1/remove-todo
MNT Remove TODO comments
2023-10-20 13:13:52 +13:00
Sabina Talipova
c1eaaaabfa MNT Remove TODO comments 2023-10-19 16:22:38 +13:00
github-actions
58a2d58173 Merge branch '5.0' into 5.1 2023-09-23 13:23:32 +00:00
github-actions
7427f615de Merge branch '4' into 5.0 2023-09-23 13:23:31 +00:00
github-actions
1e7bba1dd3 Merge branch '5.0' into 5.1 2023-09-17 23:33:00 +00:00
Maxime Rainville
34581be27d
Merge pull request #2886 from creative-commoners/pulls/5.1/fix-regression-ui-button
FIX Regression issue UI URLSegment buttons
2023-09-18 11:28:24 +12:00
Guy Sartorelli
6259ca30ad
Merge branch '4' into 5.0
# Conflicts:
#	client/dist/js/TinyMCE_sslink-anchor.js
#	client/dist/js/TinyMCE_sslink-internal.js
#	composer.json
#	tests/behat/features/insert-a-link.feature
#	tests/behat/features/insert-anchor-link.feature
2023-09-18 11:10:29 +12:00
Sabina Talipova
061517ac45 FIX Regression issue UI URLSegment buttons 2023-09-14 15:50:58 +12:00
Guy Sartorelli
4a92f5eb64
FIX Allow wrapping an image in a link (#2884) 2023-09-11 12:33:00 +12:00
Steve Boyd
332898f3ed Merge branch '5.0' into 5.1 2023-09-05 15:19:54 +12:00
Steve Boyd
7e42058206 Merge branch '4' into 5.0 2023-09-05 15:19:35 +12:00
github-actions[bot]
2799ef3b39
DEP Update JS dependencies (#2878)
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com>
2023-08-31 11:58:54 +12:00
Guy Sartorelli
280eec2e17
Merge branch '5.0' into 5 2023-08-30 11:29:51 +12:00
Guy Sartorelli
d11915cffd
Merge pull request #2876 from creative-commoners/pulls/5.0/module-standardiser-1693278538
MNT Run module-standardiser
2023-08-29 17:08:18 +12:00
Steve Boyd
57c5dcbebb MNT Run module-standardiser 2023-08-29 15:08:58 +12:00
github-actions
6b3acefc47 Merge branch '5.0' into 5 2023-08-26 13:23:34 +00:00
github-actions
b8e30925e8 Merge branch '4' into 5.0 2023-08-26 13:23:33 +00:00
github-actions
0b3bbcd372 Merge branch '5.0' into 5 2023-08-19 13:23:56 +00:00
github-actions
461cab09a0 Merge branch '4' into 5.0 2023-08-19 13:23:55 +00:00
Guy Sartorelli
6decb06909
ENH Update translations (#2873) 2023-08-17 18:15:22 +12:00
Guy Sartorelli
391f836153
Merge pull request #2871 from creative-commoners/pulls/5/module-standardiser-1691549983
MNT Run module-standardiser
2023-08-15 12:09:05 +12:00
Steve Boyd
d865d508c9 MNT Run module-standardiser 2023-08-14 15:43:59 +12:00
Guy Sartorelli
78452fc1a8
Merge pull request #2870 from lekoala/patch-2
drop duplicated call
2023-08-02 17:05:32 +12:00
Thomas Portelange
c455a8288f
drop duplicated call
already called due to init being called in the extension by leftandmain
2023-07-28 08:25:46 +02:00
Sabina Talipova
c831b1be6b
DEP Update eslint module (#2868) 2023-07-12 11:04:39 +12:00
Sabina Talipova
643801a01b
MNT ESLint issues (#2865) 2023-07-10 09:49:33 +12:00
Guy Sartorelli
e91b7c7f8e
Merge pull request #2862 from andrewandante/FEAT_add_cms_interface_for_user_inherited_permission
FEAT update SiteTree permissions in CMS
2023-07-07 10:08:46 +12:00
Andrew Paxley
14eb767c9c ENH update SiteTree permissions in CMS 2023-07-06 17:59:36 +12:00
Steve Boyd
06d39c2cc9 Merge branch '5.0' into 5 2023-06-16 11:41:37 +12:00
Steve Boyd
b44ceb95ed Merge branch '4' into 5.0 2023-06-16 11:40:00 +12:00
Guy Sartorelli
2ea9d85ee8
Merge pull request #2860 from creative-commoners/pulls/5/tx-1686703283
ENH Update translations
2023-06-14 15:25:26 +12:00
Steve Boyd
cdd6e54fce ENH Update translations 2023-06-14 12:41:23 +12:00
Sabina Talipova
39fe63db8a
FIX Duplicate page keeps original pages canView and canEdit permission (#2859) 2023-06-12 13:29:18 +12:00
Steve Boyd
b42ef6273d Merge branch '5.0' into 5 2023-05-31 14:41:09 +12:00
Steve Boyd
1f2bf0a8a7 Merge branch '4' into 5.0 2023-05-31 14:40:54 +12:00
Steve Boyd
c7db5e25a9 Merge branch '5.0' into 5 2023-05-31 11:26:56 +12:00
Steve Boyd
984cf404f4 Merge branch '4' into 5.0 2023-05-31 11:26:36 +12:00
Steve Boyd
989bb7944a Merge branch '4.13' into 4 2023-05-31 11:24:51 +12:00
Steve Boyd
40f7a79c09 Merge branch '5.0' into 5 2023-05-04 13:26:23 +12:00
Guy Sartorelli
81e7e1a01b
Merge pull request #2849 from creative-commoners/pulls/5.0/react-testing-library
MNT Use React Testing Library
2023-05-01 17:48:45 +12:00
Steve Boyd
28ecbdc845 MNT Use React Testing Library 2023-04-28 10:48:47 +12:00
Guy Sartorelli
ca837d6ccd
Merge branch '4' into 5.0 2023-04-27 14:44:59 +12:00
Sabina Talipova
6675f50f81
Merge pull request #2850 from creative-commoners/pulls/5.0/cms5-readme
DOC Update README.md for CMS 5
2023-04-21 15:29:11 +12:00
Guy Sartorelli
cfc48fad0a
DOC Update README.md for CMS 5 2023-04-19 17:38:49 +12:00
Maxime Rainville
0b50824e46
Merge pull request #2847 from creative-commoners/pulls/5.0/devjs
MNT Update dev JS
2023-04-03 15:32:17 +12:00
Steve Boyd
b1efcc217d MNT Update dev JS 2023-04-03 14:30:30 +12:00
Steve Boyd
2afad17237 Merge branch '5.0' into 5 2023-03-30 13:29:02 +13:00
Steve Boyd
f2d745afec Merge branch '4' into 5.0 2023-03-30 13:28:53 +13:00
Steve Boyd
0c712284a9 Merge branch '5.0' into 5 2023-03-08 12:22:46 +13:00
Steve Boyd
f705df4b0c Merge branch '4' into 5.0 2023-03-08 12:22:34 +13:00
Steve Boyd
76ba5ed33b Merge branch '5.0' into 5 2023-03-02 16:22:42 +13:00
Steve Boyd
7fe9a04112 Merge branch '4' into 5.0 2023-03-02 16:22:11 +13:00
Guy Sartorelli
3f1dbe4d3f
Merge pull request #2836 from creative-commoners/pulls/5.0/fix-broken-builds
FIX Replace Diff class with HtmlDiff
2023-02-14 18:55:21 +13:00
Guy Sartorelli
abf00ede95
MNT Get JS tests passing again (#2834) 2023-02-13 15:20:56 +13:00
Sabina Talipova
93f57d2300 FIX Replace Diff class with HtmlDiff 2023-02-09 10:32:25 +13:00
Steve Boyd
222972c687 Merge branch '4' into 5 2023-02-02 16:34:19 +13:00
Guy Sartorelli
b02beba7ba
Resolve a couple of behat issues (#2830)
* FIX Correctly add message to reactstrap-confirm

* MNT Fix behat tests
2023-01-30 10:32:26 +13:00
Maxime Rainville
081eea42c5
Merge pull request #2824 from creative-commoners/pulls/5/remove-legacy-upgrader
MNT Remove legacy upgrader config
2023-01-23 10:36:04 +13:00
Steve Boyd
30685c9227 MNT Remove legacy upgrader config 2023-01-20 17:13:11 +13:00
Guy Sartorelli
37af732dbf
Merge pull request #2771 from xini/fix-5-remove-trailing-slash-from-sitetree-links
SS5: Remove trailing slash from SiteTree links if no action present
2023-01-20 15:46:39 +13:00
Florian Thoma
18cb6d499d
API Normalise trailing slashes in links 2023-01-20 15:08:37 +13:00
Maxime Rainville
2b0374e692
Merge pull request #2823 from creative-commoners/pulls/5/broken-builds
MNT Broken builds
2023-01-20 14:53:28 +13:00
Steve Boyd
f362d8b129 MNT Broken builds 2023-01-19 16:54:57 +13:00
Guy Sartorelli
9bb6f700b4
Merge pull request #2820 from creative-commoners/pulls/5/remove-translatable
ENH Remove unused Translatable code
2023-01-19 09:05:03 +13:00
Maxime Rainville
69fabe9a34
Merge pull request #2818 from creative-commoners/pulls/5/remove-legacy-tasks
API Remove legacy tasks
2023-01-18 14:22:01 +13:00
Steve Boyd
b57d557bc7 ENH Remove unused Translatable code 2023-01-18 14:07:39 +13:00
Maxime Rainville
97fdff4bb2
API Remove deprecated CMSMain::$subitem_class config (#2821) 2023-01-18 11:06:45 +13:00
Maxime Rainville
50cefa6d14 Merge branch '4' into 5 2023-01-17 22:35:51 +13:00
Steve Boyd
1bd578fc96 API Remove legacy tasks 2023-01-17 12:31:51 +13:00
Guy Sartorelli
61d729285f
Merge pull request #2814 from creative-commoners/pulls/5/lint
MNT Add yarn lint back in
2023-01-13 15:40:31 +13:00
Steve Boyd
a44547915d MNT Add yarn lint back in 2023-01-13 15:17:54 +13:00
Maxime Rainville
e7d9d1b36e
Merge pull request #2813 from creative-commoners/pulls/5/fix-behat2
Fix anchor select field component
2023-01-11 17:53:01 +13:00
Maxime Rainville
3c7459208e
Merge pull request #2811 from creative-commoners/pulls/5/fix-behat
MNT Fix behat test for inserting WYSIWYG links
2023-01-11 17:17:31 +13:00
Guy Sartorelli
ef4122da04
ENH Use the EmotionCssCacheProvider component
This ensures we can override the react-select CSS if we need to.
2023-01-11 16:06:36 +13:00
Guy Sartorelli
b9115f3f6d
Fix anchor select field component
This should have been done when we upgraded react-select. My bad.
2023-01-10 12:34:13 +13:00
Guy Sartorelli
dd79cf5a23
MNT Fix behat test for inserting WYSIWYG links
The selectors for TreeDropdownField's markup changed when we updated
react-select.
2023-01-09 13:01:49 +13:00
Guy Sartorelli
cba1acb88e
Merge pull request #2809 from creative-commoners/pulls/5/remove-silverstripe-version-file
MNT Remove silverstripe_version file
2022-12-20 12:11:47 +13:00
Guy Sartorelli
bd42008584
MNT Remove silverstripe_version file
This file hasn't been updated since 2012 and was only referenced in the now-removed `SilverStripe\Dev\SapphireInfo` class.
2022-12-20 11:35:45 +13:00
Guy Sartorelli
5e843d2619
DEP Upgrade build stack (#2795)
* DEP Upgrade webpack config and various deps

* DEP Update code to work with upgraded libraries

* MNT run yarn build
2022-12-19 10:21:10 +13:00
Guy Sartorelli
ddbe4ea4ce
DEP Upgrade build stack (#2795)
* DEP Upgrade webpack config and various deps

* DEP Update code to work with upgraded libraries

* MNT run yarn build
2022-12-19 10:20:52 +13:00
Guy Sartorelli
145f063c33
Merge branch '4' into 5 2022-12-14 15:22:01 +13:00
Guy Sartorelli
03bac4b72d
Merge pull request #2806 from creative-commoners/pulls/5/absolute-link
FIX Cast absoluteUrl() argument to string
2022-12-13 16:27:07 +13:00
Steve Boyd
605daf5026 FIX Cast absoluteUrl() argument to string 2022-12-09 10:02:43 +13:00
Sabina Talipova
0e5428b78b
API Remove deprecated code (#2800) 2022-12-08 10:44:36 +13:00
Guy Sartorelli
8b1433b263
Merge pull request #2804 from creative-commoners/pulls/5/sortraw
FIX Use orderBy() instead of sort()
2022-12-07 14:53:18 +13:00
Steve Boyd
3186e0e129 FIX Use orderBy() instead of sort() 2022-12-05 17:46:44 +13:00
Guy Sartorelli
911a71d6f6
Merge branch '4' into '5' 2022-11-21 18:07:57 +13:00
Guy Sartorelli
003f9ba750
Revert "Merge branch '4' into 5"
This reverts commit 2d10a624b3, reversing
changes made to af1a482d20.
2022-11-21 17:11:42 +13:00
Sabina Talipova
2d10a624b3 Merge branch '4' into 5 2022-11-21 16:59:42 +13:00
Guy Sartorelli
af1a482d20
FIX Loosen config order to allow "after: '*'" in framework (#2793) 2022-10-19 15:15:48 +13:00
Guy Sartorelli
8320023526
Merge pull request #2788 from creative-commoners/pulls/5/action-signature
API Strongly-type action method signatures
2022-10-19 10:08:22 +13:00
Steve Boyd
6e19ae737f API Strongly-type action method signatures 2022-10-18 18:21:09 +13:00
Guy Sartorelli
9b64c7de24
Merge branch '4' into 5 2022-10-13 11:18:14 +13:00
Sabina Talipova
ea9ce63438
Merge pull request #2779 from creative-commoners/pulls/5/previewable-via-extension
ENH Records can be made previewable via an extension
2022-10-07 13:34:19 +13:00
Guy Sartorelli
6ff98c4201
ENH Records can be made previewable via an extension 2022-10-06 15:51:30 +13:00
Sabina Talipova
e5cea70b54
Merge pull request #2761 from creative-commoners/pulls/5/migrate-preview-bits
API Migrate SilverStripeNagivator classes
2022-10-06 13:46:38 +13:00
Guy Sartorelli
d7857ebbe0
API Migrate SilverStripeNagivator classes
These classes are useful with `silverstripe/admin` and
`silverstripe/versioned` without needing `silverstripe/cms`.
2022-10-05 14:24:11 +13:00
Sabina Talipova
390f078551
Merge pull request #2781 from creative-commoners/pulls/5/tinymce6
FIX Fix link plugins to support tinymce6
2022-10-03 12:10:14 +13:00
Guy Sartorelli
bedd64554f
FIX Use correct tinymce selection logic 2022-09-30 18:26:13 +13:00
Guy Sartorelli
7368df8757
FIX Fix link plugins to support tinymce6 2022-09-30 15:27:38 +13:00
Guy Sartorelli
d56682509c
Merge branch '4' into 5 2022-09-02 11:01:22 +12:00
Steve Boyd
aa4ba82f38
Merge pull request #2769 from creative-commoners/pulls/5/rescue-master-remove-history-viewer
API Rescue Master Branch PR: Remove deprecated CMSPageHistoryViewer
2022-09-01 14:50:58 +12:00
Guy Sartorelli
f2c4423d0c
Merge branch '4' into 5 2022-08-31 13:56:26 +12:00
Florian Thoma
1711c0c88e
API Move updateRelativeLink hook after concatination (#2770)
* move updateRelativeLink hook after concatination to make it actually updatable

* keep existing parameters the same

* revert to link parameter be first

* update updateRelativeLink method signature in SiteTreeExtension

* don't pass old parameters by reference
2022-08-31 12:33:05 +12:00
Guy Sartorelli
adcea213a2
ENH Remove css for CMSPageHistoryController. 2022-08-30 11:14:51 +12:00
Steve Boyd
f9a19e7429
Merge pull request #2768 from creative-commoners/pulls/5/rescue-master-canberoot-check
Rescue Master Branch PR: FIX Don't offer to restore to root if can_be_root is false
2022-08-29 18:07:56 +12:00
Guy Sartorelli
803b4add7b
FIX Resolve CI failure 2022-08-25 16:18:07 +12:00
Aaron Carlino
cda7857e12
API: Remove deprecated CMSPageHistoryViewer 2022-08-25 16:18:01 +12:00
Mike Cochrane
b46876b8a8
FIX Don't offer to restore to root if can_be_root is false 2022-08-25 14:18:50 +12:00
Steve Boyd
c130b55ecb
Merge pull request #2766 from creative-commoners/pulls/5/rescue-master-sitetree-not-page
Rescue Master Branch PR: MNT Use SiteTree instead of Page in tests
2022-08-25 11:47:14 +12:00
Mike Cochrane
2219899c10
MNT Use SiteTree instead of Page in tests 2022-08-25 10:17:41 +12:00
Guy Sartorelli
859ff00184
Merge pull request #2763 from creative-commoners/pulls/5/other-deps
DEP Update dependencies for CMS 5
2022-08-10 11:14:52 +12:00
Steve Boyd
7381de15e8 DEP Update dependencies for CMS 5 2022-08-09 17:24:39 +12:00
Guy Sartorelli
e580527111
Merge pull request #2759 from creative-commoners/pulls/5/major-deps
DEP Update core dependencies for CMS 5
2022-08-09 09:41:32 +12:00
Steve Boyd
72f8e5f71d DEP Update core dependencies for CMS 5 2022-08-04 17:36:54 +12:00
221 changed files with 8291 additions and 13488 deletions

View File

@ -1,10 +1,10 @@
name: Keepalive name: Keepalive
on: on:
workflow_dispatch: # At 6:30 PM UTC, on day 15 of the month
# The 4th of every month at 10:50am UTC
schedule: schedule:
- cron: '50 10 4 * *' - cron: '30 18 15 * *'
workflow_dispatch:
jobs: jobs:
keepalive: keepalive:

17
.github/workflows/merge-up.yml vendored Normal file
View File

@ -0,0 +1,17 @@
name: Merge-up
on:
# At 1:20 PM UTC, only on Saturday
schedule:
- cron: '20 13 * * 6'
workflow_dispatch:
jobs:
merge-up:
name: Merge-up
# Only run cron on the silverstripe account
if: (github.event_name == 'schedule' && github.repository_owner == 'silverstripe') || (github.event_name != 'schedule')
runs-on: ubuntu-latest
steps:
- name: Merge-up
uses: silverstripe/gha-merge-up@v1

View File

@ -4,7 +4,7 @@ on:
workflow_dispatch: workflow_dispatch:
# Run on a schedule of once per quarter # Run on a schedule of once per quarter
schedule: schedule:
- cron: '0 0 1 */3 *' - cron: '30 18 1 */3 *'
jobs: jobs:
update-js: update-js:

2
.nvmrc
View File

@ -1 +1 @@
10 18

View File

@ -1,161 +0,0 @@
mappings:
CMSBatchAction_Publish: SilverStripe\CMS\BatchActions\CMSBatchAction_Publish
CMSBatchAction_Unpublish: SilverStripe\CMS\BatchActions\CMSBatchAction_Unpublish
CMSBatchAction_Archive: SilverStripe\CMS\BatchActions\CMSBatchAction_Archive
CMSBatchAction_Restore: SilverStripe\CMS\BatchActions\CMSBatchAction_Restore
CMSMain: SilverStripe\CMS\Controllers\CMSMain
CMSPageAddController: SilverStripe\CMS\Controllers\CMSPageAddController
CMSPageEditController: SilverStripe\CMS\Controllers\CMSPageEditController
CMSPageHistoryController: SilverStripe\CMS\Controllers\CMSPageHistoryController
CMSPagesController: SilverStripe\CMS\Controllers\CMSPagesController
CMSPageSettingsController: SilverStripe\CMS\Controllers\CMSPageSettingsController
CMSSiteTreeFilter: SilverStripe\CMS\Controllers\CMSSiteTreeFilter
CMSSiteTreeFilter_PublishedPages: SilverStripe\CMS\Controllers\CMSSiteTreeFilter_PublishedPages
CMSSiteTreeFilter_DeletedPages: SilverStripe\CMS\Controllers\CMSSiteTreeFilter_DeletedPages
CMSSiteTreeFilter_ChangedPages: SilverStripe\CMS\Controllers\CMSSiteTreeFilter_ChangedPages
CMSSiteTreeFilter_StatusRemovedFromDraftPages: SilverStripe\CMS\Controllers\CMSSiteTreeFilter_StatusRemovedFromDraftPages
CMSSiteTreeFilter_StatusDraftPages: SilverStripe\CMS\Controllers\CMSSiteTreeFilter_StatusDraftPages
CMSSiteTreeFilter_StatusDeletedPages: SilverStripe\CMS\Controllers\CMSSiteTreeFilter_StatusDeletedPages
CMSSiteTreeFilter_Search: SilverStripe\CMS\Controllers\CMSSiteTreeFilter_Search
ContentController: SilverStripe\CMS\Controllers\ContentController
ErrorPageControllerExtension: SilverStripe\ErrorPage\ErrorPageControllerExtension
ErrorPageFileExtension: SilverStripe\ErrorPage\ErrorPageFileExtension
LeftAndMainPageIconsExtension: SilverStripe\CMS\Controllers\LeftAndMainPageIconsExtension
ModelAsController: SilverStripe\CMS\Controllers\ModelAsController
OldPageRedirector: SilverStripe\CMS\Controllers\OldPageRedirector
RootURLController: SilverStripe\CMS\Controllers\RootURLController
SilverStripeNavigator: SilverStripe\CMS\Controllers\SilverStripeNavigator
SilverStripeNavigatorItem: SilverStripe\CMS\Controllers\SilverStripeNavigatorItem
SilverStripeNavigatorItem_CMSLink: SilverStripe\CMS\Controllers\SilverStripeNavigatorItem_CMSLink
SilverStripeNavigatorItem_StageLink: SilverStripe\CMS\Controllers\SilverStripeNavigatorItem_StageLink
SilverStripeNavigatorItem_LiveLink: SilverStripe\CMS\Controllers\SilverStripeNavigatorItem_LiveLink
SilverStripeNavigatorItem_ArchiveLink: SilverStripe\CMS\Controllers\SilverStripeNavigatorItem_ArchiveLink
SiteTreeURLSegmentField: SilverStripe\CMS\Forms\SiteTreeURLSegmentField
SiteTreeURLSegmentField_Readonly: SilverStripe\CMS\Forms\SiteTreeURLSegmentField_Readonly
CurrentPageIdentifier: SilverStripe\CMS\Model\CurrentPageIdentifier
ErrorPage: SilverStripe\ErrorPage\ErrorPage
ErrorPage_Controller: SilverStripe\ErrorPage\ErrorPageController
RedirectorPage: SilverStripe\CMS\Model\RedirectorPage
RedirectorPage_Controller: SilverStripe\CMS\Model\RedirectorPageController
SiteTree: SilverStripe\CMS\Model\SiteTree
SiteTreeExtension: SilverStripe\CMS\Model\SiteTreeExtension
SiteTreeFileExtension: SilverStripe\CMS\Model\SiteTreeFileExtension
SiteTreeFolderExtension: SilverStripe\CMS\Model\SiteTreeFolderExtension
SiteTreeLinkTracking: SilverStripe\CMS\Model\SiteTreeLinkTracking
SiteTreeLinkTracking_Parser: SilverStripe\CMS\Model\SiteTreeLinkTracking_Parser
VirtualPage: SilverStripe\CMS\Model\VirtualPage
BrokenFilesReport: SilverStripe\CMS\Reports\BrokenFilesReport
SideReport_BrokenFiles: SilverStripe\CMS\Reports\BrokenFilesReport
BrokenLinksReport: SilverStripe\CMS\Reports\BrokenLinksReport
SideReport_BrokenLinks: SilverStripe\CMS\Reports\BrokenLinksReport
BrokenRedirectorPagesReport: SilverStripe\CMS\Reports\BrokenRedirectorPagesReport
SideReport_BrokenRedirectorPages: SilverStripe\CMS\Reports\BrokenRedirectorPagesReport
BrokenVirtualPagesReport: SilverStripe\CMS\Reports\BrokenVirtualPagesReport
SideReport_BrokenVirtualPages: SilverStripe\CMS\Reports\BrokenVirtualPagesReport
EmptyPagesReport: SilverStripe\CMS\Reports\EmptyPagesReport
SideReport_EmptyPages: SilverStripe\CMS\Reports\EmptyPagesReport
RecentlyEditedReport: SilverStripe\CMS\Reports\RecentlyEditedReport
SideReport_RecentlyEdited: SilverStripe\CMS\Reports\RecentlyEditedReport
ContentControllerSearchExtension: SilverStripe\CMS\Search\ContentControllerSearchExtension
SearchForm: SilverStripe\CMS\Search\SearchForm
MigrateSiteTreeLinkingTask: SilverStripe\CMS\Tasks\MigrateSiteTreeLinkingTask
RemoveOrphanedPagesTask: SilverStripe\CMS\Tasks\RemoveOrphanedPagesTask
SiteTreeMaintenanceTask: SilverStripe\CMS\Tasks\SiteTreeMaintenanceTask
AssetAdmin: SilverStripe\AssetAdmin\Controller\AssetAdmin
AssetTableField: SilverStripe\AssetAdmin\Controller\AssetAdmin
CMSAddPageController: SilverStripe\CMS\Controllers\CMSPageAddController
CMSBatchActions: SilverStripe\Admin\CMSBatchAction
CMSSearch: SilverStripe\CMS\Search\SearchForm
ContentControl: SilverStripe\CMS\Controllers\ContentController
Permissions: SilverStripe\Security\Permission
SITETREE: SilverStripe\CMS\Model\SiteTree
CMSMain_left_ss: SilverStripe\CMS\Controllers\CMSMain
CMSPageHistoryController_versions_ss: SilverStripe\CMS\Controllers\CMSPageHistoryController
CMSPagesController_ContentToolbar_ss: SilverStripe\CMS\Controllers\CMSPageHistoryController
CMSSIteTreeFilter_PublishedPages: SilverStripe\CMS\Controllers\CMSSIteTreeFilter_PublishedPages
URLSegmentField: SilverStripe\CMS\Forms\SiteTreeURLSegmentField
CMSPagesController_Tools_ss: SilverStripe\CMS\Controllers\CMSPagesController
LeftAndMain: SilverStripe\Admin\LeftAndMain
CMSBatchActionsTest: SilverStripe\CMS\Tests\CMSBatchActionsTest
CMSMainTest: SilverStripe\CMS\Tests\CMSMainTest
CMSMainTest_ClassA: SilverStripe\CMS\Tests\CMSMainTest_ClassA
CMSMainTest_ClassB: SilverStripe\CMS\Tests\CMSMainTest_ClassB
CMSMainTest_HiddenClass: SilverStripe\CMS\Tests\CMSMainTest_HiddenClass
CMSMainTest_NotRoot: SilverStripe\CMS\Tests\CMSMainTest_NotRoot
CMSPageHistoryControllerTest: SilverStripe\CMS\Tests\CMSPageHistoryControllerTest
CMSSiteTreeFilterTest: SilverStripe\CMS\Tests\CMSSiteTreeFilterTest
CMSTreeTest: SilverStripe\CMS\Tests\CMSTreeTest
ContentControllerPermissionsTest: SilverStripe\CMS\Tests\ContentControllerPermissionsTest
ContentControllerSearchExtensionTest: SilverStripe\CMS\Tests\ContentControllerSearchExtensionTest
ContentControllerTest: SilverStripe\CMS\Tests\ContentControllerTest
ContentControllerTest_Page: SilverStripe\CMS\Tests\ContentControllerTest_Page
ContentControllerTest_PageController: SilverStripe\CMS\Tests\ContentControllerTest_PageController
ContentControllerTestPage: SilverStripe\CMS\Tests\ContentControllerTestPage
ContentControllerTestPageController: SilverStripe\CMS\Tests\ContentControllerTestPageController
ContentControllerTestPageWithoutController: SilverStripe\CMS\Tests\ContentControllerTestPageWithoutController
ModelAsControllerTest: SilverStripe\CMS\Tests\ModelAsControllerTest
RootURLControllerTest: SilverStripe\CMS\Tests\RootURLControllerTest
SilverStripeNavigatorTest: SilverStripe\CMS\Tests\SilverStripeNavigatorTest
SilverStripeNavigatorTest_ProtectedTestItem: SilverStripe\CMS\Tests\SilverStripeNavigatorTest_ProtectedTestItem
SilverStripeNavigatorTest_TestItem: SilverStripe\CMS\Tests\SilverStripeNavigatorTest_TestItem
FileLinkTrackingTest: SilverStripe\CMS\Tests\FileLinkTrackingTest
RedirectorPageTest: SilverStripe\CMS\Tests\RedirectorPageTest
RedirectorPageTest_RedirectExtension: SilverStripe\CMS\Tests\RedirectorPageTest_RedirectExtension
SiteTreeActionsTest: SilverStripe\CMS\Tests\SiteTreeActionsTest
SiteTreeActionsTest_Page: SilverStripe\CMS\Tests\SiteTreeActionsTest_Page
SiteTreeBacklinksTest: SilverStripe\CMS\Tests\SiteTreeBacklinksTest
SiteTreeBacklinksTest_DOD: SilverStripe\CMS\Tests\SiteTreeBacklinksTest_DOD
SiteTreeBrokenLinksTest: SilverStripe\CMS\Tests\SiteTreeBrokenLinksTest
SiteTreeHTMLEditorFieldTest: SilverStripe\CMS\Tests\SiteTreeHTMLEditorFieldTest
SiteTreeLinkTrackingTest: SilverStripe\CMS\Tests\SiteTreeLinkTrackingTest
SiteTreePermissionsTest: SilverStripe\CMS\Tests\SiteTreePermissionsTest
SiteTreeTest: SilverStripe\CMS\Tests\SiteTreeTest
SiteTreeTest_AdminDenied: SilverStripe\CMS\Tests\SiteTreeTest_AdminDenied
SiteTreeTest_AdminDeniedExtension: SilverStripe\CMS\Tests\SiteTreeTest_AdminDeniedExtension
SiteTreeTest_ClassA: SilverStripe\CMS\Tests\SiteTreeTest_ClassA
SiteTreeTest_ClassB: SilverStripe\CMS\Tests\SiteTreeTest_ClassB
SiteTreeTest_ClassC: SilverStripe\CMS\Tests\SiteTreeTest_ClassC
SiteTreeTest_ClassCext: SilverStripe\CMS\Tests\SiteTreeTest_ClassCext
SiteTreeTest_ClassD: SilverStripe\CMS\Tests\SiteTreeTest_ClassD
SiteTreeTest_ClassE: SilverStripe\CMS\Tests\SiteTreeTest_ClassE
SiteTreeTest_Conflicted: SilverStripe\CMS\Tests\SiteTreeTest_Conflicted
SiteTreeTest_ConflictedController: SilverStripe\CMS\Tests\SiteTreeTest_ConflictedController
SiteTreeTest_DataObject: SilverStripe\CMS\Tests\SiteTreeTest_DataObject
SiteTreeTest_Extension: SilverStripe\CMS\Tests\SiteTreeTest_Extension
SiteTreeTest_ExtensionA: SilverStripe\CMS\Tests\SiteTreeTest_ExtensionA
SiteTreeTest_ExtensionB: SilverStripe\CMS\Tests\SiteTreeTest_ExtensionB
SiteTreeTest_LegacyControllerName: SilverStripe\CMS\Tests\SiteTreeTest_LegacyControllerName
SiteTreeTest_LegacyControllerName_Controller: SilverStripe\CMS\Tests\SiteTreeTest_LegacyControllerName_Controller
SiteTreeTest_NotRoot: SilverStripe\CMS\Tests\SiteTreeTest_NotRoot
SiteTreeTest_NullHtmlCleaner: SilverStripe\CMS\Tests\SiteTreeTest_NullHtmlCleaner
SiteTreeTest_PageNode: SilverStripe\CMS\Tests\SiteTreeTest_PageNode
SiteTreeTest_PageNodeController: SilverStripe\CMS\Tests\SiteTreeTest_PageNodeController
SiteTreeTest_StageStatusInherit: SilverStripe\CMS\Tests\SiteTreeTest_StageStatusInherit
VirtualPageTest: SilverStripe\CMS\Tests\VirtualPageTest
VirtualPageTest_ClassA: SilverStripe\CMS\Tests\VirtualPageTest_ClassA
VirtualPageTest_ClassAController: SilverStripe\CMS\Tests\VirtualPageTest_ClassAController
VirtualPageTest_ClassB: SilverStripe\CMS\Tests\VirtualPageTest_ClassB
VirtualPageTest_ClassC: SilverStripe\CMS\Tests\VirtualPageTest_ClassC
VirtualPageTest_NotRoot: SilverStripe\CMS\Tests\VirtualPageTest_NotRoot
VirtualPageTest_PageExtension: SilverStripe\CMS\Tests\VirtualPageTest_PageExtension
VirtualPageTest_PageWithAllowedChildren: SilverStripe\CMS\Tests\VirtualPageTest_PageWithAllowedChildren
VirtualPageTest_TestDBField: SilverStripe\CMS\Tests\VirtualPageTest_TestDBField
VirtualPageTest_VirtualPageSub: SilverStripe\CMS\Tests\VirtualPageTest_VirtualPageSub
CmsReportsTest: SilverStripe\CMS\Tests\CmsReportsTest
CMSMainSearchFormTest: SilverStripe\CMS\Tests\CMSMainSearchFormTest
ZZZSearchFormTest: SilverStripe\CMS\Tests\ZZZSearchFormTest
MigrateSiteTreeLinkingTaskTest: SilverStripe\CMS\Tests\MigrateSiteTreeLinkingTaskTest
RemoveOrphanedPagesTaskTest: SilverStripe\CMS\Tests\RemoveOrphanedPagesTaskTest
excludedPaths:
- '*/_config/legacy.yml'
warnings:
methods:
'SilverStripe\CMS\Model\SiteTree->getIsAddedToStage()':
message: 'Moved to Versioned->isOnDraftOnly()'
replacement: 'isOnDraftOnly'
'SilverStripe\CMS\Model\SiteTree->getIsModifiedOnStage()':
message: 'Moved to Versioned->isModifiedOnDraft()'
replacement: 'isModifiedOnDraft'
'SilverStripe\CMS\Model\SiteTree->getExistsOnLive()':
message: 'Removed in favour of isPublished()'
replacement: 'isPublished'

View File

@ -1,4 +1,4 @@
Copyright (c) 2016, SilverStripe Ltd. Copyright (c) 2016, Silverstripe Ltd.
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without

View File

@ -7,7 +7,7 @@ PHP Content Management System (CMS), see [http://silverstripe.org](http://silver
## Installation ## Installation
See [installation instructions](https://docs.silverstripe.org/en/getting_started/installation/). See the [getting started documentation](https://docs.silverstripe.org/en/getting_started/).
## Bugtracker ## Bugtracker

View File

@ -4,7 +4,6 @@ use SilverStripe\Admin\CMSMenu;
use SilverStripe\CMS\Controllers\CMSMain; use SilverStripe\CMS\Controllers\CMSMain;
use SilverStripe\CMS\Controllers\CMSPageAddController; use SilverStripe\CMS\Controllers\CMSPageAddController;
use SilverStripe\CMS\Controllers\CMSPageEditController; use SilverStripe\CMS\Controllers\CMSPageEditController;
use SilverStripe\CMS\Controllers\CMSPageHistoryController;
use SilverStripe\CMS\Controllers\CMSPageSettingsController; use SilverStripe\CMS\Controllers\CMSPageSettingsController;
use SilverStripe\CMS\Model\SiteTree; use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Core\Manifest\ModuleLoader; use SilverStripe\Core\Manifest\ModuleLoader;
@ -33,12 +32,7 @@ ShortcodeParser::get('default')->register(
[SiteTree::class, 'link_shortcode_handler'] [SiteTree::class, 'link_shortcode_handler']
); );
// TODO Remove once we can configure CMSMenu through static, nested configuration files
CMSMenu::remove_menu_class(CMSMain::class); CMSMenu::remove_menu_class(CMSMain::class);
CMSMenu::remove_menu_class(CMSPageEditController::class); CMSMenu::remove_menu_class(CMSPageEditController::class);
CMSMenu::remove_menu_class(CMSPageSettingsController::class); CMSMenu::remove_menu_class(CMSPageSettingsController::class);
if (class_exists(CMSPageHistoryController::class)) {
// this class will be removed in CMS 5
CMSMenu::remove_menu_class(CMSPageHistoryController::class);
}
CMSMenu::remove_menu_class(CMSPageAddController::class); CMSMenu::remove_menu_class(CMSPageAddController::class);

View File

@ -1,8 +0,0 @@
---
Name: cmslegacy
---
SilverStripe\ORM\DatabaseAdmin:
classname_value_remapping:
SiteTree: 'SilverStripe\CMS\Model\SiteTree'
RedirectorPage: SilverStripe\CMS\Model\RedirectorPage
VirtualPage: SilverStripe\CMS\Model\VirtualPage

View File

@ -5,8 +5,6 @@ After: '#coreroutes'
SilverStripe\Control\Director: SilverStripe\Control\Director:
rules: rules:
'': 'SilverStripe\CMS\Controllers\RootURLController' '': 'SilverStripe\CMS\Controllers\RootURLController'
'RemoveOrphanedPagesTask//$Action/$ID/$OtherID': 'SilverStripe\CMS\Tasks\RemoveOrphanedPagesTask'
'SiteTreeMaintenanceTask//$Action/$ID/$OtherID': 'SilverStripe\CMS\Tasks\SiteTreeMaintenanceTask'
--- ---
Name: legacycmsroutes Name: legacycmsroutes
--- ---

View File

@ -1,6 +1,6 @@
--- ---
Name: cmsversion Name: cmsversion
After: 'framework/*' After: 'framework/coreconfig'
--- ---
SilverStripe\Core\Manifest\VersionProvider: SilverStripe\Core\Manifest\VersionProvider:
modules: modules:

View File

@ -1,32 +0,0 @@
<?php
namespace SilverStripe\CMS\GraphQL;
use GraphQL\Type\Definition\ResolveInfo;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\GraphQL\Scaffolding\Scaffolders\CRUD\ReadOne;
use SilverStripe\GraphQL\Scaffolding\StaticSchema;
use SilverStripe\ORM\DataList;
if (!class_exists(ReadOne::class)) {
return;
}
/**
* Shim to make readOnePage work like GraphQL 4
*
* @internal Use GraphQL v4
* @deprecated 4.8..5.0 Use silverstripe/graphql:^4 functionality.
*/
class ReadOneResolver
{
public static function resolve($obj, array $args, array $context, ResolveInfo $info)
{
$idKey = StaticSchema::inst()->formatField('ID');
$id = $args['filter'][$idKey]['eq'];
$readOne = Injector::inst()->createWithArgs(ReadOne::class, ['Page']);
unset($args['filter']);
$args[$idKey] = $id;
return $readOne->resolve($obj, $args, $context, $info);
}
}

6
babel.config.json Normal file
View File

@ -0,0 +1,6 @@
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
]
}

View File

@ -1 +1 @@
!function(e){function t(n){if(r[n])return r[n].exports;var a=r[n]={i:n,l:!1,exports:{}};return e[n].call(a.exports,a,a.exports,t),a.l=!0,a.exports}var r={};t.m=e,t.c=r,t.i=function(e){return e},t.d=function(e,r,n){t.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:n})},t.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(r,"a",r),r},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s="./client/src/legacy/SilverStripeNavigator.js")}({"./client/src/legacy/SilverStripeNavigator.js":function(e,t,r){"use strict";!function(){function e(e){return document.getElementsByTagName("base")[0].href.replace("http://","").replace(/\//g,"_").replace(/\./g,"_")+e}function t(e){var t=getComputedStyle(e).display;e.style.display="none",e.dataset.__toggle_display=t}function r(e){e.style.display=e.dataset.__toggle_display?e.dataset.__toggle_display:"block"}function n(e){"none"!==getComputedStyle(e).display?t(e):r(e)}var a=document.querySelectorAll("#switchView a.newWindow");if(a.length>0){var i=!0,l=!1,o=void 0;try{for(var u,c=a.values()[Symbol.iterator]();!(i=(u=c.next()).done);i=!0){var f=u.value;!function(t){t.addEventListener("click",function(r){return r.preventDefault(),window.open(t.href,e(t.target)).focus(),!1})}(f)}}catch(e){l=!0,o=e}finally{try{!i&&c.return&&c.return()}finally{if(l)throw o}}}var v=document.getElementById("SilverStripeNavigatorLinkPopup");if(v){var s=document.getElementById("SilverStripeNavigatorLink");s&&s.addEventListener("click",function(e){return e.preventDefault(),n(v),!1});var d=v.querySelectorAll("a.close");if(d.length>0){var y=!0,p=!1,g=void 0;try{for(var S,m=d.values()[Symbol.iterator]();!(y=(S=m.next()).done);y=!0)S.value.addEventListener("click",function(e){return e.preventDefault(),t(v),!1})}catch(e){p=!0,g=e}finally{try{!y&&m.return&&m.return()}finally{if(p)throw g}}}var h=v.querySelectorAll("input");if(h.length>0){var _=!0,w=!1,b=void 0;try{for(var x,E=h.values()[Symbol.iterator]();!(_=(x=E.next()).done);_=!0){var k=x.value;!function(e){e.addEventListener("focus",function(t){e.select()})}(k)}}catch(e){w=!0,b=e}finally{try{!_&&E.return&&E.return()}finally{if(w)throw b}}}}}()}}); !function(){"use strict";!function(){function e(e){const t=getComputedStyle(e).display;e.style.display="none",e.dataset.__toggle_display=t}const t=document.querySelectorAll("#switchView a.newWindow");if(t.length>0)for(const e of t.values())e.addEventListener("click",(function(t){t.preventDefault();var n;return window.open(e.href,(n=e.target,document.getElementsByTagName("base")[0].href.replace("http://","").replace(/\//g,"_").replace(/\./g,"_")+n)).focus(),!1}));const n=document.getElementById("SilverStripeNavigatorLinkPopup");if(n){const t=document.getElementById("SilverStripeNavigatorLink");t&&t.addEventListener("click",(function(t){var o;return t.preventDefault(),o=n,"none"!==getComputedStyle(o).display?e(o):function(e){e.style.display=e.dataset.__toggle_display?e.dataset.__toggle_display:"block"}(o),!1}));const o=n.querySelectorAll("a.close");if(o.length>0)for(const t of o.values())t.addEventListener("click",(function(t){return t.preventDefault(),e(n),!1}));const l=n.querySelectorAll("input");if(l.length>0)for(const e of l.values())e.addEventListener("focus",(function(t){e.select()}))}}()}();

View File

@ -1 +1 @@
!function(e){function t(r){if(n[r])return n[r].exports;var i=n[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var n={};t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s="./client/src/legacy/TinyMCE_sslink-anchor.js")}({"./client/src/legacy/TinyMCE_sslink-anchor.js":function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var i=n(1),o=r(i),a=n(9),l=r(a),c=n(2),s=r(c),u=n(5),d=r(u),p=n(4),f=n(6),A=n(0),E=r(A),_=n(8),h=r(_),C=n(7),g=n(3),R=n("./client/src/state/anchorSelector/AnchorSelectorActions.js"),O={init:function(e){l.default.addAction("sslink",{text:o.default._t("CMS.LINKLABEL_ANCHOR","Anchor on a page"),onclick:function(e){return e.execCommand("sslinkanchor")},priority:60},e.settings.editorIdentifier).addCommandWithUrlTest("sslinkanchor",/^\[sitetree_link.+]#[^#\]]+$/),e.addCommand("sslinkanchor",function(){var t=(0,E.default)("#"+e.id).entwine("ss"),n=Number((0,E.default)("#Form_EditForm_ID").val()||0),r=e.$("[id],[name]",e.getBody()).toArray().map(function(e){return e.id||e.name});ss.store.dispatch((0,R.updatedCurrentField)(n,r,e.id)),t.openLinkAnchorDialog()})}},T="insert-link__dialog-wrapper--anchor",m=(0,g.provideInjector)((0,C.createInsertLinkModal)("SilverStripe\\CMS\\Controllers\\CMSPageEditController","editorAnchorLink"));E.default.entwine("ss",function(e){e("textarea.htmleditor").entwine({openLinkAnchorDialog:function(){var t=e("#"+T);t.length||(t=e('<div id="'+T+'" />'),e("body").append(t)),t.addClass("insert-link__dialog-wrapper"),t.setElement(this),t.open()}}),e("#"+T).entwine({renderModal:function(t){var n=this,r=ss.store,i=ss.apolloClient,a=function(){return n.close()},l=function(){return n.handleInsert.apply(n,arguments)},c=this.getOriginalAttributes(),u=this.getRequireLinkText(),A=Number(e("#Form_EditForm_ID").val()||0);d.default.render(s.default.createElement(p.ApolloProvider,{client:i},s.default.createElement(f.Provider,{store:r},s.default.createElement(m,{isOpen:t,onInsert:l,onClosed:a,title:o.default._t("CMS.LINK_ANCHOR","Link to an anchor on a page"),bodyClassName:"modal__dialog",className:"insert-link__dialog-wrapper--anchor",fileAttributes:c,identifier:"Admin.InsertLinkAnchorModal",requireLinkText:u,currentPageID:A}))),this[0])},buildAttributes:function(e){return{href:h.default.serialise({name:"sitetree_link",properties:{id:e.PageID}},!0)+(e.Anchor&&e.Anchor.length?"#"+e.Anchor:""),target:e.TargetBlank?"_blank":"",title:e.Description}},getOriginalAttributes:function(){var t=this.getElement().getEditor(),n=e(t.getSelectedNode()),r=(n.attr("href")||"").split("#");if(!r[0])return{};var i=h.default.match("sitetree_link",!1,r[0]);return i?{PageID:i.properties.id?parseInt(i.properties.id,10):0,Anchor:r[1]||"",Description:n.attr("title"),TargetBlank:!!n.attr("target")}:{}}})}),tinymce.PluginManager.add("sslinkanchor",function(e){return O.init(e)}),t.default=O},"./client/src/state/anchorSelector/AnchorSelectorActionTypes.js":function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default={ANCHORSELECTOR_CURRENT_FIELD:"ANCHORSELECTOR_CURRENT_FIELD",ANCHORSELECTOR_UPDATED:"ANCHORSELECTOR_UPDATED",ANCHORSELECTOR_UPDATING:"ANCHORSELECTOR_UPDATING",ANCHORSELECTOR_UPDATE_FAILED:"ANCHORSELECTOR_UPDATE_FAILED"}},"./client/src/state/anchorSelector/AnchorSelectorActions.js":function(e,t,n){"use strict";function r(e){return{type:c.default.ANCHORSELECTOR_UPDATING,payload:{pageId:e}}}function i(e,t){var n=arguments.length>2&&void 0!==arguments[2]&&arguments[2];return{type:c.default.ANCHORSELECTOR_UPDATED,payload:{pageId:e,anchors:t,cacheResult:n}}}function o(e,t,n){return{type:c.default.ANCHORSELECTOR_CURRENT_FIELD,payload:{pageId:e,anchors:t,fieldID:n}}}function a(e){return{type:c.default.ANCHORSELECTOR_UPDATE_FAILED,payload:{pageId:e}}}Object.defineProperty(t,"__esModule",{value:!0}),t.beginUpdating=r,t.updated=i,t.updatedCurrentField=o,t.updateFailed=a;var l=n("./client/src/state/anchorSelector/AnchorSelectorActionTypes.js"),c=function(e){return e&&e.__esModule?e:{default:e}}(l)},0:function(e,t){e.exports=jQuery},1:function(e,t){e.exports=i18n},2:function(e,t){e.exports=React},3:function(e,t){e.exports=Injector},4:function(e,t){e.exports=ReactApollo},5:function(e,t){e.exports=ReactDom},6:function(e,t){e.exports=ReactRedux},7:function(e,t){e.exports=InsertLinkModal},8:function(e,t){e.exports=ShortcodeSerialiser},9:function(e,t){e.exports=TinyMCEActionRegistrar}}); !function(){"use strict";var e={964:function(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;t.default={ANCHORSELECTOR_CURRENT_FIELD:"ANCHORSELECTOR_CURRENT_FIELD",ANCHORSELECTOR_UPDATED:"ANCHORSELECTOR_UPDATED",ANCHORSELECTOR_UPDATING:"ANCHORSELECTOR_UPDATING",ANCHORSELECTOR_UPDATE_FAILED:"ANCHORSELECTOR_UPDATE_FAILED"}},447:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.beginUpdating=function(e){return{type:i.default.ANCHORSELECTOR_UPDATING,payload:{pageId:e}}},t.updateFailed=function(e){return{type:i.default.ANCHORSELECTOR_UPDATE_FAILED,payload:{pageId:e}}},t.updated=function(e,t){let n=arguments.length>2&&void 0!==arguments[2]&&arguments[2];return{type:i.default.ANCHORSELECTOR_UPDATED,payload:{pageId:e,anchors:t,cacheResult:n}}},t.updatedCurrentField=function(e,t,n){return{type:i.default.ANCHORSELECTOR_CURRENT_FIELD,payload:{pageId:e,anchors:t,fieldID:n}}};var r,i=(r=n(964))&&r.__esModule?r:{default:r}},939:function(e){e.exports=ApolloClient},648:function(e){e.exports=Injector},595:function(e){e.exports=InsertLinkModal},363:function(e){e.exports=React},691:function(e){e.exports=ReactDomClient},624:function(e){e.exports=ReactRedux},265:function(e){e.exports=ShortcodeSerialiser},196:function(e){e.exports=TinyMCEActionRegistrar},754:function(e){e.exports=i18n},311:function(e){e.exports=jQuery}},t={};function n(r){var i=t[r];if(void 0!==i)return i.exports;var o=t[r]={exports:{}};return e[r](o,o.exports,n),o.exports}!function(){var e=p(n(754)),t=p(n(196)),r=p(n(363)),i=n(691),o=n(939),a=n(624),d=p(n(311)),l=p(n(265)),s=n(595),u=n(648),c=n(447);function p(e){return e&&e.__esModule?e:{default:e}}const f="sslinkanchor";t.default.addAction("sslink",{text:e.default._t("CMS.LINKLABEL_ANCHOR","Anchor on a page"),onAction:e=>e.execCommand(f),priority:60},editorIdentifier).addCommandWithUrlTest(f,/^\[sitetree_link.+]#[^#\]]+$/);const E={init(e){e.addCommand(f,(()=>{const t=(0,d.default)(`#${e.id}`).entwine("ss"),n=Number((0,d.default)("#Form_EditForm_ID").val()||0),r=(0,d.default)(e.getBody()).find("[id],[name]").toArray().map((e=>e.id||e.name));ss.store.dispatch((0,c.updatedCurrentField)(n,r,e.id)),t.openLinkAnchorDialog()}))}},A="insert-link__dialog-wrapper--anchor",C=(0,u.provideInjector)((0,s.createInsertLinkModal)("SilverStripe\\CMS\\Controllers\\CMSPageEditController","editorAnchorLink"));d.default.entwine("ss",(t=>{t("textarea.htmleditor").entwine({openLinkAnchorDialog(){let e=t(`#${A}`);e.length||(e=t(`<div id="${A}" />`),t("body").append(e)),e.addClass("insert-link__dialog-wrapper"),e.setElement(this),e.open()}}),t(`#${A}`).entwine({ReactRoot:null,renderModal(n){var d=this;const l=ss.store,s=ss.apolloClient,u=this.getOriginalAttributes(),c=this.getRequireLinkText(),p=Number(t("#Form_EditForm_ID").val()||0);let f=this.getReactRoot();f||(f=(0,i.createRoot)(this[0]),this.setReactRoot(f)),f.render(r.default.createElement(o.ApolloProvider,{client:s},r.default.createElement(a.Provider,{store:l},r.default.createElement(C,{isOpen:n,onInsert:function(){return d.handleInsert(...arguments)},onClosed:()=>this.close(),title:e.default._t("CMS.LINK_ANCHOR","Link to an anchor on a page"),bodyClassName:"modal__dialog",className:"insert-link__dialog-wrapper--anchor",fileAttributes:u,identifier:"Admin.InsertLinkAnchorModal",requireLinkText:c,currentPageID:p}))))},buildAttributes(e){return{href:`${l.default.serialise({name:"sitetree_link",properties:{id:e.PageID}},!0)}${e.Anchor&&e.Anchor.length?`#${e.Anchor}`:""}`,target:e.TargetBlank?"_blank":"",title:e.Description}},getOriginalAttributes(){const e=this.getElement().getEditor(),n=t(e.getSelectedNode()),r=(n.attr("href")||"").split("#");if(!r[0])return{};const i=l.default.match("sitetree_link",!1,r[0]);return i?{PageID:i.properties.id?parseInt(i.properties.id,10):0,Anchor:r[1]||"",Description:n.attr("title"),TargetBlank:!!n.attr("target")}:{}}})})),tinymce.PluginManager.add(f,(e=>E.init(e)))}()}();

View File

@ -1 +1 @@
!function(e){function t(r){if(n[r])return n[r].exports;var i=n[r]={i:r,l:!1,exports:{}};return e[r].call(i.exports,i,i.exports,t),i.l=!0,i.exports}var n={};t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s="./client/src/legacy/TinyMCE_sslink-internal.js")}({"./client/src/legacy/TinyMCE_sslink-internal.js":function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var i=n(1),o=r(i),l=n(9),a=r(l),s=n(2),u=r(s),c=n(5),d=r(c),f=n(4),p=n(6),g=n(0),k=r(g),_=n(8),m=r(_),h=n(7),x=n(3),I={init:function(e){a.default.addAction("sslink",{text:o.default._t("CMS.LINKLABEL_PAGE","Page on this site"),onclick:function(e){return e.execCommand("sslinkinternal")},priority:90},e.settings.editorIdentifier).addCommandWithUrlTest("sslinkinternal",/^\[sitetree_link.+]$/),e.addCommand("sslinkinternal",function(){(0,k.default)("#"+e.id).entwine("ss").openLinkInternalDialog()})}},A="insert-link__dialog-wrapper--internal",C=(0,x.provideInjector)((0,h.createInsertLinkModal)("SilverStripe\\CMS\\Controllers\\CMSPageEditController","editorInternalLink"));k.default.entwine("ss",function(e){e("textarea.htmleditor").entwine({openLinkInternalDialog:function(){var t=e("#"+A);t.length||(t=e('<div id="'+A+'" />'),e("body").append(t)),t.addClass("insert-link__dialog-wrapper"),t.setElement(this),t.open()}}),e("#"+A).entwine({renderModal:function(e){var t=this,n=ss.store,r=ss.apolloClient,i=function(){return t.close()},l=function(){return t.handleInsert.apply(t,arguments)},a=this.getOriginalAttributes(),s=this.getRequireLinkText();d.default.render(u.default.createElement(f.ApolloProvider,{client:r},u.default.createElement(p.Provider,{store:n},u.default.createElement(C,{isOpen:e,onInsert:l,onClosed:i,title:o.default._t("CMS.LINK_PAGE","Link to a page"),bodyClassName:"modal__dialog",className:"insert-link__dialog-wrapper--internal",fileAttributes:a,identifier:"Admin.InsertLinkInternalModal",requireLinkText:s}))),this[0])},buildAttributes:function(e){return{href:m.default.serialise({name:"sitetree_link",properties:{id:e.PageID}},!0)+(e.Anchor&&e.Anchor.length?"#"+e.Anchor:""),target:e.TargetBlank?"_blank":"",title:e.Description}},getOriginalAttributes:function(){var t=this.getElement().getEditor(),n=e(t.getSelectedNode()),r=(n.attr("href")||"").split("#");if(!r[0])return{};var i=m.default.match("sitetree_link",!1,r[0]);return i?{PageID:i.properties.id?parseInt(i.properties.id,10):0,Anchor:r[1]||"",Description:n.attr("title"),TargetBlank:!!n.attr("target")}:{}}})}),tinymce.PluginManager.add("sslinkinternal",function(e){return I.init(e)}),t.default=I},0:function(e,t){e.exports=jQuery},1:function(e,t){e.exports=i18n},2:function(e,t){e.exports=React},3:function(e,t){e.exports=Injector},4:function(e,t){e.exports=ReactApollo},5:function(e,t){e.exports=ReactDom},6:function(e,t){e.exports=ReactRedux},7:function(e,t){e.exports=InsertLinkModal},8:function(e,t){e.exports=ShortcodeSerialiser},9:function(e,t){e.exports=TinyMCEActionRegistrar}}); !function(){"use strict";var e={939:function(e){e.exports=ApolloClient},648:function(e){e.exports=Injector},595:function(e){e.exports=InsertLinkModal},363:function(e){e.exports=React},691:function(e){e.exports=ReactDomClient},624:function(e){e.exports=ReactRedux},265:function(e){e.exports=ShortcodeSerialiser},196:function(e){e.exports=TinyMCEActionRegistrar},754:function(e){e.exports=i18n},311:function(e){e.exports=jQuery}},t={};function n(i){var r=t[i];if(void 0!==r)return r.exports;var o=t[i]={exports:{}};return e[i](o,o.exports,n),o.exports}!function(){var e=u(n(754)),t=u(n(196)),i=u(n(363)),r=n(691),o=n(939),a=n(624),l=u(n(311)),s=u(n(265)),d=n(595),c=n(648);function u(e){return e&&e.__esModule?e:{default:e}}const p="sslinkinternal";t.default.addAction("sslink",{text:e.default._t("CMS.LINKLABEL_PAGE","Page on this site"),onAction:e=>e.execCommand(p),priority:90},editorIdentifier).addCommandWithUrlTest(p,/^\[sitetree_link.+]$/);const f={init(e){e.addCommand(p,(()=>{(0,l.default)(`#${e.id}`).entwine("ss").openLinkInternalDialog()}))}},g="insert-link__dialog-wrapper--internal",h=(0,c.provideInjector)((0,d.createInsertLinkModal)("SilverStripe\\CMS\\Controllers\\CMSPageEditController","editorInternalLink"));l.default.entwine("ss",(t=>{t("textarea.htmleditor").entwine({openLinkInternalDialog(){let e=t(`#${g}`);e.length||(e=t(`<div id="${g}" />`),t("body").append(e)),e.addClass("insert-link__dialog-wrapper"),e.setElement(this),e.open()}}),t(`#${g}`).entwine({ReactRoot:null,renderModal(t){var n=this;const l=ss.store,s=ss.apolloClient,d=this.getOriginalAttributes(),c=this.getRequireLinkText();let u=this.getReactRoot();u||(u=(0,r.createRoot)(this[0]),this.setReactRoot(u)),u.render(i.default.createElement(o.ApolloProvider,{client:s},i.default.createElement(a.Provider,{store:l},i.default.createElement(h,{isOpen:t,onInsert:function(){return n.handleInsert(...arguments)},onClosed:()=>this.close(),title:e.default._t("CMS.LINK_PAGE","Link to a page"),bodyClassName:"modal__dialog",className:"insert-link__dialog-wrapper--internal",fileAttributes:d,identifier:"Admin.InsertLinkInternalModal",requireLinkText:c}))))},buildAttributes(e){return{href:`${s.default.serialise({name:"sitetree_link",properties:{id:e.PageID}},!0)}${e.Anchor&&e.Anchor.length?`#${e.Anchor}`:""}`,target:e.TargetBlank?"_blank":"",title:e.Description}},getOriginalAttributes(){const e=this.getElement().getEditor(),n=t(e.getSelectedNode()),i=(n.attr("href")||"").split("#");if(!i[0])return{};const r=s.default.match("sitetree_link",!1,i[0]);return r?{PageID:r.properties.id?parseInt(r.properties.id,10):0,Anchor:i[1]||"",Description:n.attr("title"),TargetBlank:!!n.attr("target")}:{}}})})),tinymce.PluginManager.add(p,(e=>f.init(e)))}()}();

View File

@ -1 +1,48 @@
!function(e){function t(r){if(n[r])return n[r].exports;var a=n[r]={i:r,l:!1,exports:{}};return e[r].call(a.exports,a,a.exports,t),a.l=!0,a.exports}var n={};t.m=e,t.c=n,t.i=function(e){return e},t.d=function(e,n,r){t.o(e,n)||Object.defineProperty(e,n,{configurable:!1,enumerable:!0,get:r})},t.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(n,"a",n),n},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s="./client/src/bundles/bundle.js")}({"./client/src/boot/index.js":function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}var a=n("./client/src/boot/registerReducers.js"),o=r(a),i=n("./client/src/boot/registerComponents.js"),s=r(i);window.document.addEventListener("DOMContentLoaded",function(){(0,s.default)(),(0,o.default)()})},"./client/src/boot/registerComponents.js":function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(3),o=r(a),i=n("./client/src/components/AnchorSelectorField/AnchorSelectorField.js"),s=r(i),l=n("./client/src/state/history/readOnePageQuery.js"),d=r(l),c=n("./client/src/state/history/rollbackPageMutation.js"),u=r(c);t.default=function(){o.default.component.register("AnchorSelectorField",s.default),o.default.transform("pages-history",function(e){e.component("HistoryViewer.pages-controller-cms-content",d.default,"PageHistoryViewer")}),o.default.transform("pages-history-revert",function(e){e.component("HistoryViewerToolbar.VersionedAdmin.HistoryViewer.SiteTree.HistoryViewerVersionDetail",u.default,"PageRevertMutation")})}},"./client/src/boot/registerReducers.js":function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var a=n(3),o=r(a),i=n(12),s=n("./client/src/state/anchorSelector/AnchorSelectorReducer.js"),l=r(s);t.default=function(){o.default.reducer.register("cms",(0,i.combineReducers)({anchorSelector:l.default}))}},"./client/src/bundles/bundle.js":function(e,t,n){"use strict";n("./client/src/legacy/CMSMain.AddForm.js"),n("./client/src/legacy/CMSMain.EditForm.js"),n("./client/src/legacy/CMSMain.js"),n("./client/src/legacy/CMSMain.Tree.js"),n("./client/src/legacy/CMSPageHistoryController.js"),n("./client/src/legacy/RedirectorPage.js"),n("./client/src/legacy/SiteTreeURLSegmentField.js"),n("./client/src/boot/index.js")},"./client/src/components/AnchorSelectorField/AnchorSelectorField.js":function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function a(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);t<e.length;t++)n[t]=e[t];return n}return Array.from(e)}function o(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function s(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}function l(e,t){var n=(0,b.formValueSelector)(t.formid,O.default),r=t&&t.data&&t.data.targetFieldName||"PageID",a=Number(n(e,r)||0),o=[],i=a?e.cms.anchorSelector.pages.find(function(e){return e.id===a}):null;!i||i.loadingState!==E.default.SUCCESS&&i.loadingState!==E.default.DIRTY&&i.loadingState!==E.default.FIELD_ONLY||(o=i.anchors);var s=null;return s=i?i.loadingState:a?E.default.DIRTY:E.default.SUCCESS,{pageId:a,anchors:o,loadingState:s}}function d(e){return{actions:{anchorSelector:(0,_.bindActionCreators)(w,e)}}}Object.defineProperty(t,"__esModule",{value:!0}),t.ConnectedAnchorSelectorField=t.Component=void 0;var c=function(){function e(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}return function(t,n,r){return n&&e(t.prototype,n),r&&e(t,r),t}}(),u=n(1),f=r(u),p=n(2),h=r(p),m=n(15),g=r(m),v=n(6),_=n(12),b=n(18),C=n(19),y=r(C),S=n("./client/src/state/anchorSelector/AnchorSelectorActions.js"),w=function(e){if(e&&e.__esModule)return e;var t={};if(null!=e)for(var n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t.default=e,t}(S),P=n("./client/src/state/anchorSelector/AnchorSelectorStates.js"),E=r(P),x=n(14),F=r(x),R=n(16),A=n(21),O=r(A),T=n(20),j=r(T),L=n(11),M=r(L),D=function(){return null},I=function(e){function t(e){o(this,t);var n=i(this,(t.__proto__||Object.getPrototypeOf(t)).call(this,e));return n.handleChange=n.handleChange.bind(n),n.handleLoadingError=n.handleLoadingError.bind(n),n}return s(t,e),c(t,[{key:"componentDidMount",value:function(){this.ensurePagesLoaded()}},{key:"componentDidUpdate",value:function(e){this.props.pageId!==e.pageId&&this.ensurePagesLoaded()}},{key:"ensurePagesLoaded",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.props;if(t.loadingState===E.default.UPDATING||t.loadingState===E.default.SUCCESS||!t.pageId)return Promise.resolve();var n=[];t.loadingState===E.default.FIELD_ONLY&&(n=this.props.anchors),t.actions.anchorSelector.beginUpdating(t.pageId);var r=t.data.endpoint.replace(/:id/,t.pageId);return(0,g.default)(r,{credentials:"same-origin"}).then(function(e){return e.json()}).then(function(e){var r=[].concat(a(new Set([].concat(a(e),a(n)))));return t.actions.anchorSelector.updated(t.pageId,r),r}).catch(function(n){t.actions.anchorSelector.updateFailed(t.pageId),e.handleLoadingError(n,t)})}},{key:"getDropdownOptions",value:function(){var e=this,t=this.props.anchors.map(function(e){return{value:e}});return this.props.value&&!this.props.anchors.find(function(t){return t===e.props.value})&&t.unshift({value:this.props.value}),t}},{key:"handleChange",value:function(e){"function"==typeof this.props.onChange&&this.props.onChange(e?e.value:"")}},{key:"handleLoadingError",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.props;if(t.onLoadingError===D)throw e;return t.onLoadingError({errors:[{value:e.message,type:"error"}]})}},{key:"render",value:function(){var e={id:this.props.id},t=(0,j.default)("anchorselectorfield",this.props.extraClass),n=this.getDropdownOptions(),r=this.props.value||"",a=f.default._t("CMS.ANCHOR_SELECT_OR_TYPE","Select or enter anchor");return h.default.createElement(R.Creatable,{searchable:!0,options:n,className:t,name:this.props.name,inputProps:e,onChange:this.handleChange,onBlurResetsInput:!0,value:r,placeholder:a,labelKey:"value"})}}]),t}(y.default);I.propTypes={extraClass:M.default.string,id:M.default.string,name:M.default.string.isRequired,onChange:M.default.func,value:M.default.string,attributes:M.default.oneOfType([M.default.object,M.default.array]),pageId:M.default.number,anchors:M.default.array,loadingState:M.default.oneOf(Object.keys(E.default).map(function(e){return E.default[e]})),onLoadingError:M.default.func,data:M.default.shape({endpoint:M.default.string,targetFieldName:M.default.string})},I.defaultProps={value:"",extraClass:"",onLoadingError:D,attributes:{}};var k=(0,v.connect)(l,d)(I);t.Component=I,t.ConnectedAnchorSelectorField=k,t.default=(0,F.default)(k)},"./client/src/legacy/CMSMain.AddForm.js":function(e,t,n){"use strict";var r=n(0);(function(e){return e&&e.__esModule?e:{default:e}})(r).default.entwine("ss",function(e){e(".TreeDropdownField").entwine({OldValue:null}),e("#Form_AddForm_ParentID_Holder .treedropdownfield").entwine({onmatch:function(){this._super(),e(".cms-add-form").updateTypeList()}}),e(".cms-add-form .parent-mode :input").entwine({onclick:function(e){var t=this.closest("form").find("#Form_AddForm_ParentID_Holder .TreeDropdownField");"top"==this.val()?(t.setOldValue(t.getValue()),t.setValue(0)):(t.setValue(t.getOldValue()||0),t.setOldValue(null)),t.refresh(),t.trigger("change")}}),e(".cms-add-form").entwine({ParentCache:{},onadd:function(){var t=this;this.find("#Form_AddForm_ParentID_Holder .TreeDropdownField").on("change",function(){t.updateTypeList()}),this.find(".SelectionGroup.parent-mode").on("change",function(){t.updateTypeList()}),"top"==e(".cms-add-form .parent-mode :input").val()&&this.updateTypeList()},loadCachedChildren:function(e){var t=this.getParentCache();return void 0!==t[e]?t[e]:null},saveCachedChildren:function(e,t){var n=this.getParentCache();n[e]=t,this.setParentCache(n)},updateTypeList:function(){var t=this.data("hints"),n=this.find("#Form_AddForm_ParentID"),r=this.find("input[name=ParentModeField]:checked").val(),a=n.data("metadata"),o="child"===r?n.getValue():null,i=a?a.ClassName:null,s=i&&"child"===r&&o?i:"Root",l=void 0!==t[s]?t[s]:null,d=this,c=l&&void 0!==l.defaultChild?l.defaultChild:null,u=[];if(o){if(this.hasClass("loading"))return;return this.addClass("loading"),null!==(u=this.loadCachedChildren(o))?(this.updateSelectionFilter(u,c),void this.removeClass("loading")):(e.ajax({url:d.data("childfilter"),data:{ParentID:o},success:function(e){d.saveCachedChildren(o,e),d.updateSelectionFilter(e,c)},complete:function(){d.removeClass("loading")}}),!1)}u=l&&void 0!==l.disallowedChildren?l.disallowedChildren:[],this.updateSelectionFilter(u,c)},updateSelectionFilter:function(t,n){var r=this.find("#Form_AddForm_PageType div.radio.selected")[0],a=!1,o=null;if(this.find("#Form_AddForm_PageType div.radio").each(function(n,i){var s=e(this).find("input").val(),l=-1===e.inArray(s,t);i===r&&l&&(a=!0),e(this).setEnabled(l),l||e(this).setSelected(!1),o=null===o?l:o&&l}),a)var i=e(r).parents("li:first");else if(n)var i=this.find("#Form_AddForm_PageType div.radio input[value="+n+"]").parents("li:first");else var i=this.find("#Form_AddForm_PageType div.radio:not(.disabled):first");i.setSelected(!0),i.siblings().setSelected(!1),this.find("#Form_AddForm_PageType div.radio:not(.disabled)").length?this.find("button[name=action_doAdd]").removeAttr("disabled"):this.find("button[name=action_doAdd]").attr("disabled","disabled"),this.find(".message-restricted")[o?"hide":"show"]()}}),e(".cms-add-form #Form_AddForm_PageType div.radio").entwine({onclick:function(e){this.setSelected(!0)},setSelected:function(e){var t=this.find("input");e&&!t.is(":disabled")?(this.siblings().setSelected(!1),this.toggleClass("selected",!0),t.prop("checked",!0)):(this.toggleClass("selected",!1),t.prop("checked",!1))},setEnabled:function(t){e(this).toggleClass("disabled",!t),t?e(this).find("input").removeAttr("disabled"):e(this).find("input").attr("disabled","disabled").removeAttr("checked")}}),e(".cms-content-addpage-button").entwine({onclick:function(t){var n,r=e(".cms-tree"),a=e(".cms-list"),o=0;if(r.is(":visible")){var i=r.jstree("get_selected");o=i?e(i[0]).data("id"):null}else{var s=a.find('input[name="Page[GridState]"]').val();s&&(o=parseInt(JSON.parse(s).ParentID,10))}var l,d={selector:this.data("targetPanel"),pjax:this.data("pjax")};o?(n=this.data("extraParams")?this.data("extraParams"):"",l=e.path.addSearchParams(i18n.sprintf(this.data("urlAddpage"),o),n)):l=this.attr("href"),e(".cms-container").loadPanel(l,null,d),t.preventDefault(),this.blur()}})})},"./client/src/legacy/CMSMain.EditForm.js":function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function a(e){return function(){var t=e.apply(this,arguments);return new Promise(function(e,n){function r(a,o){try{var i=t[a](o),s=i.value}catch(e){return void n(e)}if(!i.done)return Promise.resolve(s).then(function(e){r("next",e)},function(e){r("throw",e)});e(s)}return r("next")})}}var o=n(0),i=r(o),s=n(1),l=r(s),d=n("./node_modules/@silverstripe/reactstrap-confirm/dist/index.js"),c=r(d);i.default.entwine("ss",function(e){e(".cms-edit-form :input#Form_EditForm_ClassName").entwine({onchange:function(){alert(l.default._t("CMS.ALERTCLASSNAME"))}}),e(".cms-edit-form input[name=Title]").entwine({onmatch:function(){var t=this;t.data("OrigVal",t.val());var n=t.closest("form"),r=e("input:text[name=URLSegment]",n),a=e("input[name=LiveLink]",n);r.length>0&&(t._addActions(),this.on("change",function(n){var o=t.data("OrigVal"),i=t.val();t.data("OrigVal",i),0===r.val().indexOf(r.data("defaultUrl"))&&""==a.val()?t.updateURLSegment(i):e(".update",t.parent()).show().parent(".form__field-holder").addClass("input-group"),t.updateRelatedFields(i,o),t.updateBreadcrumbLabel(i)})),this._super()},onunmatch:function(){this._super()},updateRelatedFields:function(t,n){this.parents("form").find("input[name=MetaTitle], input[name=MenuTitle]").each(function(){var r=e(this);r.val()==n&&(r.val(t),r.updatedRelatedFields&&r.updatedRelatedFields())})},updateURLSegment:function(t){var n=e("input:text[name=URLSegment]",this.closest("form")),r=n.closest(".field.urlsegment"),a=e(".update",this.parent());r.update(t),a.is(":visible")&&a.hide().parent(".form__field-holder").removeClass("input-group")},updateBreadcrumbLabel:function(t){var n=(e(".cms-edit-form input[name=ID]").val(),e("span.cms-panel-link.crumb"));t&&""!=t&&n.text(t)},_addActions:function(){var t,n=this;t=e("<button />",{class:"update btn btn-outline-secondary form__field-update-url",text:l.default._t("CMS.UpdateURL"),type:"button",click:function(e){e.preventDefault(),n.updateURLSegment(n.val())}}),t.insertAfter(n),t.hide()}}),e(".cms-edit-form .parentTypeSelector").entwine({onmatch:function(){var e=this;this.find(":input[name=ParentType]").on("click",function(t){e._toggleSelection(t)}),this.find(".TreeDropdownField").on("change",function(t){e._changeParentId(t)}),this._changeParentId(),this._toggleSelection(),this._super()},onunmatch:function(){this._super()},_toggleSelection:function(t){var n=this.find(":input[name=ParentType]:checked").val(),r=this.find("#Form_EditForm_ParentID_Holder");"root"==n?this.find(":input[name=ParentID]").val(0):this.find(":input[name=ParentID]").val(this.find("#Form_EditForm_ParentType_subpage").data("parentIdValue")),"root"!=n?r.slideDown(400,function(){e(this).css("overflow","visible")}):r.slideUp()},_changeParentId:function(e){var t=this.find(":input[name=ParentID]").val();this.find("#Form_EditForm_ParentType_subpage").data("parentIdValue",t)}}),e(".cms-edit-form .btn-toolbar #Form_EditForm_action_doRollback, .cms-edit-form .btn-toolbar #Form_EditForm_action_rollback").entwine({onclick:function(e){if(this.is(":disabled"))return e.preventDefault(),!1;var t=this.parents("form:first").find(":input[name=Version]").val(),n=t?l.default.sprintf(l.default._t("CMS.RollbackToVersion","Do you really want to roll back to version #%s of this page?"),t):l.default._t("CMS.ConfirmRestoreFromLive","Are you sure you want to revert draft to when the page was last published?");return confirm(n)?(this.parents("form:first").addClass("loading"),this._super(e)):(e.preventDefault(),!1)}}),e(".cms-edit-form .btn-toolbar #Form_EditForm_action_archive:not(.homepage-warning)").entwine({onclick:function(e){var t=this.parents("form:first"),n="";return n=t.find("input[name=ArchiveWarningMessage]").val().replace(/\\n/g,"\n"),!!confirm(n)&&(this.parents("form:first").addClass("loading"),this._super(e))}}),e(".cms-edit-form .btn-toolbar #Form_EditForm_action_restore").entwine({onclick:function(e){var t=this.parents("form:first"),n=t.find(":input[name=Version]").val(),r="",a=this.data("toRoot");return r=l.default.sprintf(l.default._t(a?"CMS.RestoreToRoot":"CMS.Restore"),n),!!confirm(r)&&(this.parents("form:first").addClass("loading"),this._super(e))}}),e(".cms-edit-form .btn-toolbar #Form_EditForm_action_unpublish:not(.homepage-warning)").entwine({onclick:function(e){var t=this.parents("form:first"),n=t.find(":input[name=Version]").val(),r="";return r=l.default.sprintf(l.default._t("CMS.Unpublish"),n),!!confirm(r)&&(this.parents("form:first").addClass("loading"),this._super(e))}}),e(".cms-edit-form.changed").entwine({onmatch:function(t){this.find("button[data-text-alternate]").each(function(){var t=e(this),n=t.find(".btn__title"),r=t.data("textAlternate");r&&(t.data("textStandard",n.text()),n.text(r));var a=t.data("btnAlternate");a&&(t.data("btnStandard",t.attr("class")),t.attr("class",a),t.removeClass("btn-outline-secondary").addClass("btn-primary"));var o=t.data("btnAlternateAdd");o&&t.addClass(o);var i=t.data("btnAlternateRemove");i&&t.removeClass(i)}),this._super(t)},onunmatch:function(t){this.find("button[data-text-alternate]").each(function(){var t=e(this),n=t.find(".btn__title"),r=t.data("textStandard");r&&n.text(r);var a=t.data("btnStandard");a&&(t.attr("class",a),t.addClass("btn-outline-secondary").removeClass("btn-primary"));var o=t.data("btnAlternateAdd");o&&t.removeClass(o);var i=t.data("btnAlternateRemove");i&&t.addClass(i)}),this._super(t)}}),e(".cms-edit-form .btn-toolbar button[name=action_publish]").entwine({onbuttonafterrefreshalternate:function(){this.data("showingAlternate")?(this.addClass("btn-primary"),this.removeClass("btn-secondary")):(this.removeClass("btn-primary"),this.addClass("btn-secondary"))}}),e(".cms-edit-form .btn-toolbar button[name=action_save]").entwine({onbuttonafterrefreshalternate:function(){this.data("showingAlternate")?(this.addClass("btn-primary"),this.removeClass("btn-secondary")):(this.removeClass("btn-primary"),this.addClass("btn-secondary"))}}),e('.cms-edit-form.CMSPageSettingsController input[name="ParentType"]:checked').entwine({onmatch:function(){this.redraw(),this._super()},onunmatch:function(){this._super()},redraw:function(){var t=e(".cms-edit-form.CMSPageSettingsController #Form_EditForm_ParentID_Holder");"Form_EditForm_ParentType_root"==e(this).attr("id")?t.slideUp():t.slideDown()},onclick:function(){this.redraw()}}),"Form_EditForm_ParentType_root"==e('.cms-edit-form.CMSPageSettingsController input[name="ParentType"]:checked').attr("id")&&e(".cms-edit-form.CMSPageSettingsController #Form_EditForm_ParentID_Holder").hide();var t=!1;e(".cms-edit-form .btn-toolbar #Form_EditForm_action_unpublish.homepage-warning,.cms-edit-form .btn-toolbar #Form_EditForm_action_archive.homepage-warning,#Form_EditForm_URLSegment_Holder.homepage-warning .btn.update").entwine({onclick:function(){function e(e){return n.apply(this,arguments)}var n=a(regeneratorRuntime.mark(function e(n){var r;return regeneratorRuntime.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:if(!t){e.next=2;break}return e.abrupt("return",this._super(n));case 2:return n.stopPropagation(),r=l.default._t("CMS.RemoveHomePageWarningMessage","Warning: This page is the home page. By changing the URL segment visitors will not be able to view it."),e.next=6,(0,c.default)(r,{title:l.default._t("CMS.RemoveHomePageWarningTitle","Remove your home page?"),confirmLabel:l.default._t("CMS.RemoveHomePageWarningLabel","Remove"),confirmColor:"danger"});case 6:if(!e.sent){e.next=10;break}t=!0,this.trigger("click"),t=!1;case 10:return e.abrupt("return",!1);case 11:case"end":return e.stop()}},e,this)}));return e}()})})},"./client/src/legacy/CMSMain.Tree.js":function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function a(e){return function(){var t=e.apply(this,arguments);return new Promise(function(e,n){function r(a,o){try{var i=t[a](o),s=i.value}catch(e){return void n(e)}if(!i.done)return Promise.resolve(s).then(function(e){r("next",e)},function(e){r("throw",e)});e(s)}return r("next")})}}var o=n(0),i=r(o),s=n(1),l=r(s),d=n("./node_modules/@silverstripe/reactstrap-confirm/dist/index.js"),c=r(d);i.default.entwine("ss.tree",function(e){e(".cms-tree").entwine({fromDocument:{"oncontext_show.vakata":function(e){this.adjustContextClass()}},adjustContextClass:function(){var t=e("#vakata-contextmenu").find("ul ul");t.each(function(n){var r="1",a=e(t[n]).find("li").length;a>20?r="3":a>10&&(r="2"),e(t[n]).addClass("vakata-col-"+r).removeClass("right"),e(t[n]).find("li").on("mouseenter",function(t){e(this).parent("ul").removeClass("right")})})},showListViewFor:function(t){localStorage.setItem("ss.pages-view-type","listview");var n=this.closest(".cms-content-view"),r=n.data("url-listviewroot"),a=e.path.addSearchParams(r,{ParentID:t}),o=e("base").attr("href")||"";window.location.assign(o+a)},getTreeConfig:function(){var t=this,n=this._super();return this.getHints(),n.plugins.push("contextmenu"),n.contextmenu={items:function(n){var r={edit:{label:n.hasClass("edit-disabled")?l.default._t("CMS.EditPage","Edit page",100,"Used in the context menu when right-clicking on a page node in the CMS tree"):l.default._t("CMS.ViewPage","View page",100,"Used in the context menu when right-clicking on a page node in the CMS tree"),action:function(n){e(".cms-container").entwine(".ss").loadPanel(l.default.sprintf(t.data("urlEditpage"),n.data("id")))}}};n.hasClass("nochildren")||(r.showaslist={label:l.default._t("CMS.ShowAsList"),action:function(e){t.showListViewFor(e.data("id"))}});var a=(n.data("pagetype"),n.data("id")),o=n.find(">a .item").data("allowedchildren"),i={},s=!1;return e.each(o,function(n,r){s=!0,i["allowedchildren-"+r.ClassName]={label:'<span class="jstree-pageicon '+r.IconClass+'"></span>'+r.Title,_class:"class-"+r.ClassName.replace(/[^a-zA-Z0-9\-_:.]+/g,"_"),action:function(n){e(".cms-container").entwine(".ss").loadPanel(e.path.addSearchParams(l.default.sprintf(t.data("urlAddpage"),a,r.ClassName),t.data("extraParams")))}}}),s&&(r.addsubpage={label:l.default._t("CMS.AddSubPage","Add page under this page",100,"Used in the context menu when right-clicking on a page node in the CMS tree"),submenu:i}),n.hasClass("edit-disabled")||(r.duplicate={label:l.default._t("CMS.Duplicate"),submenu:[{label:l.default._t("CMS.ThisPageOnly"),action:function(n){e(".cms-container").entwine(".ss").loadPanel(e.path.addSearchParams(l.default.sprintf(t.data("urlDuplicate"),n.data("id")),t.data("extraParams")))}},{label:l.default._t("CMS.ThisPageAndSubpages"),action:function(n){e(".cms-container").entwine(".ss").loadPanel(e.path.addSearchParams(l.default.sprintf(t.data("urlDuplicatewithchildren"),n.data("id")),t.data("extraParams")))}}]}),r}},n},canMove:function(){function e(e){return t.apply(this,arguments)}var t=a(regeneratorRuntime.mark(function e(t){var n,r,a,o;return regeneratorRuntime.wrap(function(e){for(;;)switch(e.prev=e.next){case 0:if(n=t.rslt.o.find(".homepage").first().length>0){e.next=3;break}return e.abrupt("return",!0);case 3:if(r=t.rslt.op.data("id"),a=t.rslt.np.data("id"),r!==a){e.next=7;break}return e.abrupt("return",!0);case 7:return o=l.default._t("CMS.RemoveHomePageWarningMessage","Warning: This page is the home page. By changing the URL segment visitors will not be able to view it."),e.next=10,(0,c.default)(o,{title:l.default._t("CMS.RemoveHomePageWarningTitle","Remove your home page?"),confirmLabel:l.default._t("CMS.RemoveHomePageWarningLabel","Remove"),confirmColor:"danger"});case 10:return e.abrupt("return",e.sent);case 11:case"end":return e.stop()}},e,this)}));return e}()}),e(".cms-tree a.jstree-clicked").entwine({onmatch:function(){var e=this,t=e.parents(".cms-tree-view-sidebar");if(e.offset().top<0||e.offset().top>t.height()-e.height()){var n=e.parent();n.prev().length&&(n=n.prev()),n.get(0).scrollIntoView()}}}),e(".cms-tree-filtered .clear-filter").entwine({onclick:function(){window.location=location.protocol+"//"+location.host+location.pathname}}),e(".cms-tree .subtree-list-link").entwine({onclick:function(e){e.preventDefault(),this.closest(".cms-tree").showListViewFor(this.data("id"))}})})},"./client/src/legacy/CMSMain.js":function(e,t,n){"use strict";var r=n(0);(function(e){return e&&e.__esModule?e:{default:e}})(r).default.entwine("ss",function(e){e(".cms-content-header-info").entwine({"from .cms-panel":{ontoggle:function(e){var t=this.closest(".cms-content").find(e.target);0!==t.length&&this.parent()[t.hasClass("collapsed")?"addClass":"removeClass"]("collapsed")}}}),e(".cms-panel-deferred.cms-content-view").entwine({onadd:function(){if(!this.data("no-ajax")){var e=localStorage.getItem("ss.pages-view-type")||"treeview";this.closest(".cms-content-tools").length>0&&(e="treeview");var t=this.data("url-"+e),n=localStorage.getItem("ss.pages-view-filtered");"string"==typeof n&&"false"===n.toLowerCase()&&(n=!1),localStorage.setItem("ss.pages-view-filtered",!1),this.data("deferredNoCache",n||"listview"===e),this.data("url",t+location.search),this._super()}}}),e(".js-injector-boot .search-holder--cms").entwine({search:function(e){localStorage.setItem("ss.pages-view-filtered",!0),this._super(e)}}),e(".cms .page-view-link").entwine({onclick:function(t){t.preventDefault();var n=e(this).data("view"),r=this.closest(".cms-content-view"),a=r.data("url-"+n),o=0!==r.closest(".cms-content-tools").length;if(localStorage.setItem("ss.pages-view-type",n),o&&"listview"===n){var i=e("base").attr("href")||"";return void window.location.assign(i+r.data("url-listviewroot"))}r.data("url",a+location.search),r.redraw()}}),e(".cms .cms-clear-filter").entwine({onclick:function(t){t.preventDefault(),window.location=e(this).prop("href")}}),e(".cms-content-toolbar").entwine({onmatch:function(){var t=this;this._super(),e.each(this.find(".cms-actions-buttons-row .tool-button"),function(){var n=e(this),r=n.data("toolid");n.hasClass("active"),void 0!==r&&(n.data("active",!1).removeClass("active"),e("#"+r).hide(),t.bindActionButtonEvents(n))})},onunmatch:function(){var t=this;this._super(),e.each(this.find(".cms-actions-buttons-row .tool-button"),function(){var n=e(this);t.unbindActionButtonEvents(n)})},bindActionButtonEvents:function(e){var t=this;e.on("click.cmsContentToolbar",function(n){t.showHideTool(e)})},unbindActionButtonEvents:function(e){e.off(".cmsContentToolbar")},showHideTool:function(t){var n=t.data("active"),r=t.data("toolid"),a=e("#"+r);e.each(this.find(".cms-actions-buttons-row .tool-button"),function(){var t=e(this),n=e("#"+t.data("toolid"));t.data("toolid")!==r&&(n.hide(),t.data("active",!1))}),t[n?"removeClass":"addClass"]("active"),a[n?"hide":"show"](),t.data("active",!n)}})})},"./client/src/legacy/CMSPageHistoryController.js":function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}var a=n(0),o=r(a),i=n(1),s=r(i);o.default.entwine("ss",function(e){e("#Form_VersionsForm").entwine({onmatch:function(){this._super()},onunmatch:function(){this._super()},onsubmit:function(t){t.preventDefault();var n=this.find(":input[name=ID]").val();if(!n)return!1;var r=null,a=null,o=null,i=this.find(":input[name=CompareMode]").is(":checked"),l=this.find("table input[type=checkbox]").filter(":checked");if(i){if(2!==l.length)return!1;a=l.eq(0).val(),o=l.eq(1).val(),r=s.default.sprintf(this.data("linkTmplCompare"),n,o,a)}else a=l.eq(0).val(),r=s.default.sprintf(this.data("linkTmplShow"),n,a);return e(".cms-container").loadPanel(r,"",{pjax:"CurrentForm"}),!0}}),e("#Form_VersionsForm input[name=ShowUnpublished]").entwine({onmatch:function(){this.toggle(),this._super()},onunmatch:function(){this._super()},onchange:function(){this.toggle()},toggle:function(){var t=e(this),n=t.parents("form").find("tr[data-published=false]");t.attr("checked")?n.removeClass("ui-helper-hidden").show():n.addClass("ui-helper-hidden").hide()._unselect()}}),e("#Form_VersionsForm tbody tr").entwine({onclick:function(){var e=this.parents("form").find(":input[name=CompareMode]").attr("checked"),t=this.siblings(".active");return e&&this.hasClass("active")?void this._unselect():e?t.length>1?void alert(s.default._t("CMS.ONLYSELECTTWO","You can only compare two versions at this time.")):(this._select(),void(1===t.length&&this.parents("form").submit())):(this._select(),t._unselect(),void this.parents("form").submit())},_unselect:function(){this.get(0).classList.remove("active"),this.find(":input[type=checkbox][checked]").attr("checked",!1)},_select:function(){this.addClass("active"),this.find(":input[type=checkbox]").attr("checked",!0)}})})},"./client/src/legacy/RedirectorPage.js":function(e,t,n){"use strict";var r=n(0);(function(e){return e&&e.__esModule?e:{default:e}})(r).default.entwine("ss",function(e){e("#Form_EditForm_RedirectionType input").entwine({onmatch:function(){e(this).attr("checked")&&this.toggle(),this._super()},onunmatch:function(){this._super()},onclick:function(){this.toggle()},toggle:function(){"Internal"==e(this).attr("value")?(e("#Form_EditForm_ExternalURL_Holder").hide(),e("#Form_EditForm_LinkToID_Holder").show(),e("#Form_EditForm_LinkToFile_Holder").hide()):"External"==e(this).attr("value")?(e("#Form_EditForm_ExternalURL_Holder").show(),e("#Form_EditForm_LinkToID_Holder").hide(),e("#Form_EditForm_LinkToFile_Holder").hide()):(e("#Form_EditForm_LinkToFile_Holder").show(),e("#Form_EditForm_ExternalURL_Holder").hide(),e("#Form_EditForm_LinkToID_Holder").hide())}})})},"./client/src/legacy/SiteTreeURLSegmentField.js":function(e,t,n){"use strict";var r=n(0);(function(e){return e&&e.__esModule?e:{default:e}})(r).default.entwine("ss",function(e){e(".field.urlsegment:not(.readonly)").entwine({MaxPreviewLength:55,Ellipsis:"...",onmatch:function(){this.find(":text").length&&this.toggleEdit(!1),this.redraw(),this._super()},redraw:function(){var e=this.find(":text"),t=decodeURI(e.data("prefix")+e.val()),n=t;t.length>this.getMaxPreviewLength()&&(n=this.getEllipsis()+t.substr(t.length-this.getMaxPreviewLength(),t.length)),this.find(".URL-link").attr("href",encodeURI(t+e.data("suffix"))).text(n)},toggleEdit:function(e){var t=this.find(":text");this.find(".preview-holder")[e?"hide":"show"](),this.find(".edit-holder")[e?"show":"hide"](),e&&(t.data("origval",t.val()),t.focus())},update:function(){var e=this,t=this.find(":text"),n=t.data("origval"),r=arguments[0],a=r&&""!==r?r:t.val();n!=a?(this.addClass("loading"),this.suggest(a,function(n){t.val(decodeURIComponent(n.value)),e.toggleEdit(!1),e.removeClass("loading"),e.redraw()})):(this.toggleEdit(!1),this.redraw())},cancel:function(){var e=this.find(":text");e.val(e.data("origval")),this.toggleEdit(!1)},suggest:function(t,n){var r=this,a=r.find(":text"),o=e.path.parseUrl(r.closest("form").attr("action")),i=o.hrefNoSearch+"/field/"+a.attr("name")+"/suggest/?value="+encodeURIComponent(t);o.search&&(i+="&"+o.search.replace(/^\?/,"")),e.ajax({url:i,success:function(e){n.apply(this,arguments)},error:function(e,t){e.statusText=e.responseText},complete:function(){r.removeClass("loading")}})}}),e(".field.urlsegment .text").entwine({onkeydown:function(e){13===e.keyCode&&(e.preventDefault(),this.closest(".field").update())}}),e(".field.urlsegment .edit").entwine({onclick:function(e){e.preventDefault(),this.closest(".field").toggleEdit(!0)}}),e(".field.urlsegment .update").entwine({onclick:function(e){e.preventDefault(),this.closest(".field").update()}}),e(".field.urlsegment .cancel").entwine({onclick:function(e){e.preventDefault(),this.closest(".field").cancel()}})})},"./client/src/state/anchorSelector/AnchorSelectorActionTypes.js":function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default={ANCHORSELECTOR_CURRENT_FIELD:"ANCHORSELECTOR_CURRENT_FIELD",ANCHORSELECTOR_UPDATED:"ANCHORSELECTOR_UPDATED",ANCHORSELECTOR_UPDATING:"ANCHORSELECTOR_UPDATING",ANCHORSELECTOR_UPDATE_FAILED:"ANCHORSELECTOR_UPDATE_FAILED"}},"./client/src/state/anchorSelector/AnchorSelectorActions.js":function(e,t,n){"use strict";function r(e){return{type:l.default.ANCHORSELECTOR_UPDATING,payload:{pageId:e}}}function a(e,t){var n=arguments.length>2&&void 0!==arguments[2]&&arguments[2];return{type:l.default.ANCHORSELECTOR_UPDATED,payload:{pageId:e,anchors:t,cacheResult:n}}}function o(e,t,n){return{type:l.default.ANCHORSELECTOR_CURRENT_FIELD,payload:{pageId:e,anchors:t,fieldID:n}}}function i(e){return{type:l.default.ANCHORSELECTOR_UPDATE_FAILED,payload:{pageId:e}}}Object.defineProperty(t,"__esModule",{value:!0}),t.beginUpdating=r,t.updated=a,t.updatedCurrentField=o,t.updateFailed=i;var s=n("./client/src/state/anchorSelector/AnchorSelectorActionTypes.js"),l=function(e){return e&&e.__esModule?e:{default:e}}(s)},"./client/src/state/anchorSelector/AnchorSelectorReducer.js":function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function a(e){if(Array.isArray(e)){for(var t=0,n=Array(e.length);t<e.length;t++)n[t]=e[t];return n}return Array.from(e)}function o(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:f,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null,n=function(n,r){var o=t.payload.pageId;return(0,s.default)({pages:[].concat(a(e.pages.filter(function(e){return e.id!==o})),[{id:o,loadingState:n,anchors:r}]).sort(function(e,t){return e.id-t.id})})};switch(t.type){case d.default.ANCHORSELECTOR_UPDATING:return n(u.default.UPDATING,[]);case d.default.ANCHORSELECTOR_UPDATED:var r=t.payload,o=r.anchors,i=r.cacheResult,l=u.default.SUCCESS,c=u.default.DIRTY;return n(i?l:c,o);case d.default.ANCHORSELECTOR_CURRENT_FIELD:var p=t.payload.anchors;return n(u.default.FIELD_ONLY,p);case d.default.ANCHORSELECTOR_UPDATE_FAILED:return n(u.default.FAILED,[]);default:return e}}Object.defineProperty(t,"__esModule",{value:!0}),t.default=o;var i=n(13),s=r(i),l=n("./client/src/state/anchorSelector/AnchorSelectorActionTypes.js"),d=r(l),c=n("./client/src/state/anchorSelector/AnchorSelectorStates.js"),u=r(c),f=(0,s.default)({pages:[]})},"./client/src/state/anchorSelector/AnchorSelectorStates.js":function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default={SUCCESS:"SUCCESS",DIRTY:"DIRTY",FIELD_ONLY:"FIELD_ONLY",UPDATING:"UPDATING",FAILED:"FAILED"}},"./client/src/state/history/readOnePageQuery.js":function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.config=t.query=void 0;var r=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},a=function(e,t){return Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}(["\nquery ReadHistoryViewerPage ($page_id: ID!, $limit: Int!, $offset: Int!) {\n readOnePage(\n versioning: {\n mode: ALL_VERSIONS\n },\n filter: {\n id: { eq: $page_id }\n }\n ) {\n id\n versions (limit: $limit, offset: $offset, sort: {\n version: DESC\n }) {\n pageInfo {\n totalCount\n }\n nodes {\n version\n absoluteLink\n author {\n firstName\n surname\n }\n publisher {\n firstName\n surname\n }\n deleted\n draft\n published\n liveVersion\n latestDraftVersion\n lastEdited\n }\n }\n }\n}\n"],["\nquery ReadHistoryViewerPage ($page_id: ID!, $limit: Int!, $offset: Int!) {\n readOnePage(\n versioning: {\n mode: ALL_VERSIONS\n },\n filter: {\n id: { eq: $page_id }\n }\n ) {\n id\n versions (limit: $limit, offset: $offset, sort: {\n version: DESC\n }) {\n pageInfo {\n totalCount\n }\n nodes {\n version\n absoluteLink\n author {\n firstName\n surname\n }\n publisher {\n firstName\n surname\n }\n deleted\n draft\n published\n liveVersion\n latestDraftVersion\n lastEdited\n }\n }\n }\n}\n"]),o=n(4),i=n(10),s=function(e){return e&&e.__esModule?e:{default:e}}(i),l=(0,s.default)(a),d={options:function(e){var t=e.recordId,n=e.limit;return{variables:{limit:n,offset:((e.page||1)-1)*n,page_id:t},fetchPolicy:"network-only"}},props:function(e){var t=e.data,n=t.error,a=t.refetch,o=t.readOnePage,i=t.loading,s=e.ownProps,l=s.actions,d=void 0===l?{versions:{}}:l,c=s.limit,u=s.recordId,f=o||null,p=n&&n.graphQLErrors&&n.graphQLErrors.map(function(e){return e.message});return{loading:i||!f,versions:f,graphQLErrors:p,actions:r({},d,{versions:r({},f,{goToPage:function(e){a({offset:((e||1)-1)*c,limit:c,page_id:u})}})})}}};t.query=l,t.config=d,t.default=(0,o.graphql)(l,d)},"./client/src/state/history/rollbackPageMutation.js":function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.config=t.mutation=void 0;var r=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},a=function(e,t){return Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}(["\nmutation rollbackPage($id:ID!, $toVersion:Int!) {\n rollbackPage(\n id: $id\n toVersion: $toVersion\n ) {\n id\n }\n}\n"],["\nmutation rollbackPage($id:ID!, $toVersion:Int!) {\n rollbackPage(\n id: $id\n toVersion: $toVersion\n ) {\n id\n }\n}\n"]),o=n(4),i=n(10),s=function(e){return e&&e.__esModule?e:{default:e}}(i),l=(0,s.default)(a),d={props:function(e){var t=e.mutate,n=e.ownProps.actions,a=function(e,n){return t({variables:{id:e,toVersion:n}})};return{actions:r({},n,{rollbackPage:a,revertToVersion:a})}},options:{refetchQueries:["ReadHistoryViewerPage"]}};t.mutation=l,t.config=d,t.default=(0,o.graphql)(l,d)},"./node_modules/@babel/runtime/helpers/extends.js":function(e,t){function n(){return e.exports=n=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},e.exports.default=e.exports,e.exports.__esModule=!0,n.apply(this,arguments)}e.exports=n,e.exports.default=e.exports,e.exports.__esModule=!0},"./node_modules/@babel/runtime/helpers/inheritsLoose.js":function(e,t,n){function r(e,t){e.prototype=Object.create(t.prototype),e.prototype.constructor=e,a(e,t)}var a=n("./node_modules/@babel/runtime/helpers/setPrototypeOf.js");e.exports=r,e.exports.default=e.exports,e.exports.__esModule=!0},"./node_modules/@babel/runtime/helpers/interopRequireDefault.js":function(e,t){function n(e){return e&&e.__esModule?e:{default:e}}e.exports=n,e.exports.default=e.exports,e.exports.__esModule=!0},"./node_modules/@babel/runtime/helpers/interopRequireWildcard.js":function(e,t,n){function r(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(r=function(e){return e?n:t})(e)}function a(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!==o(e)&&"function"!=typeof e)return{default:e};var n=r(t);if(n&&n.has(e))return n.get(e);var a={},i=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var s in e)if("default"!==s&&Object.prototype.hasOwnProperty.call(e,s)){var l=i?Object.getOwnPropertyDescriptor(e,s):null;l&&(l.get||l.set)?Object.defineProperty(a,s,l):a[s]=e[s]}return a.default=e,n&&n.set(e,a),a}var o=n("./node_modules/@babel/runtime/helpers/typeof.js").default;e.exports=a,e.exports.default=e.exports,e.exports.__esModule=!0},"./node_modules/@babel/runtime/helpers/setPrototypeOf.js":function(e,t){function n(t,r){return e.exports=n=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e},e.exports.default=e.exports,e.exports.__esModule=!0,n(t,r)}e.exports=n,e.exports.default=e.exports,e.exports.__esModule=!0},"./node_modules/@babel/runtime/helpers/typeof.js":function(e,t){function n(t){"@babel/helpers - typeof";return"function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?(e.exports=n=function(e){return typeof e},e.exports.default=e.exports,e.exports.__esModule=!0):(e.exports=n=function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},e.exports.default=e.exports,e.exports.__esModule=!0),n(t)}e.exports=n,e.exports.default=e.exports,e.exports.__esModule=!0},"./node_modules/@silverstripe/reactstrap-confirm/dist/Confirmation.js":function(e,t,n){"use strict";var r=n("./node_modules/@babel/runtime/helpers/interopRequireWildcard.js"),a=n("./node_modules/@babel/runtime/helpers/interopRequireDefault.js");t.__esModule=!0,t.default=void 0;var o=a(n("./node_modules/@babel/runtime/helpers/inheritsLoose.js")),i=r(n(2)),s=a(n(11)),l=n(17),d=function(e){function t(t){var n;return n=e.call(this,t)||this,n.state={isOpen:!0},n}return(0,o.default)(t,e),t.prototype.render=function(){var e=this,t=this.props,n=t.onConfirm,r=t.onCancel,a=t.title,o=t.body,s=t.confirmLabel,d=t.confirmColor,c=t.dismissLabel,u=t.showDismissButton,f=this.state.isOpen,p=function(){"function"==typeof r&&r(),e.setState({isOpen:!1})},h=function(){n(),e.setState({isOpen:!1})};return i.default.createElement(l.Modal,{isOpen:f,toggle:p},a&&i.default.createElement(l.ModalHeader,{toggle:p},a),i.default.createElement(l.ModalBody,null,o),i.default.createElement(l.ModalFooter,null,i.default.createElement(l.Button,{color:d,onClick:h},s),(u||!a)&&i.default.createElement(l.Button,{onClick:p},c||"Cancel")))},t}(i.Component);d.propTypes={onConfirm:s.default.func.isRequired,body:s.default.string.isRequired,onCancel:s.default.func,title:s.default.string,confirmLabel:s.default.string,confirmColor:s.default.string,dismissLabel:s.default.string},d.defaultProps={confirmLabel:"Confirm",confirmColor:"primary"};var c=d;t.default=c},"./node_modules/@silverstripe/reactstrap-confirm/dist/confirm.js":function(e,t,n){"use strict";var r=n("./node_modules/@babel/runtime/helpers/interopRequireDefault.js");t.__esModule=!0,t.default=void 0;var a=r(n("./node_modules/@babel/runtime/helpers/extends.js")),o=r(n(2)),i=r(n(5)),s=r(n("./node_modules/@silverstripe/reactstrap-confirm/dist/Confirmation.js")),l=function(e,t,n,r,l){void 0===t&&(t={}),void 0===n&&(n=document.body),void 0===r&&(r=350);var d=l||s.default,c=n.appendChild(document.createElement("div"));return new Promise(function(s){var l=function(e){return function(){s(e),setTimeout(function(){i.default.unmountComponentAtNode(c),setTimeout(function(){return n.removeChild(c)})},r)}};i.default.render(o.default.createElement(d,(0,a.default)({},t,{onConfirm:l(!0),onCancel:l(!1),body:e})),c)})},d=l;t.default=d},"./node_modules/@silverstripe/reactstrap-confirm/dist/index.js":function(e,t,n){"use strict";var r=n("./node_modules/@babel/runtime/helpers/interopRequireDefault.js");t.__esModule=!0,t.default=void 0;var a=r(n("./node_modules/@silverstripe/reactstrap-confirm/dist/confirm.js")),o=r(n("./node_modules/@silverstripe/reactstrap-confirm/dist/Confirmation.js"));t.Confirmation=o.default;var i=a.default;t.default=i},0:function(e,t){e.exports=jQuery},1:function(e,t){e.exports=i18n},10:function(e,t){e.exports=GraphQLTag},11:function(e,t){e.exports=PropTypes},12:function(e,t){e.exports=Redux},13:function(e,t){e.exports=DeepFreezeStrict},14:function(e,t){e.exports=FieldHolder},15:function(e,t){e.exports=IsomorphicFetch},16:function(e,t){e.exports=ReactSelect},17:function(e,t){e.exports=Reactstrap},18:function(e,t){e.exports=ReduxForm},19:function(e,t){e.exports=SilverStripeComponent},2:function(e,t){e.exports=React},20:function(e,t){e.exports=classnames},21:function(e,t){e.exports=getFormState},3:function(e,t){e.exports=Injector},4:function(e,t){e.exports=ReactApollo},5:function(e,t){e.exports=ReactDom},6:function(e,t){e.exports=ReactRedux}}); !function(){"use strict";var e={274:function(e,t,n){var a=i(n(180)),o=i(n(521));function i(e){return e&&e.__esModule?e:{default:e}}window.document.addEventListener("DOMContentLoaded",(()=>{(0,o.default)(),(0,a.default)()}))},521:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var a=s(n(648)),o=s(n(93)),i=s(n(436)),r=s(n(149));function s(e){return e&&e.__esModule?e:{default:e}}t.default=()=>{a.default.component.register("AnchorSelectorField",o.default),a.default.transform("pages-history",(e=>{e.component("HistoryViewer.pages-controller-cms-content",i.default,"PageHistoryViewer")})),a.default.transform("pages-history-revert",(e=>{e.component("HistoryViewerToolbar.VersionedAdmin.HistoryViewer.SiteTree.HistoryViewerVersionDetail",r.default,"PageRevertMutation")}))}},180:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var a=r(n(648)),o=n(827),i=r(n(572));function r(e){return e&&e.__esModule?e:{default:e}}t.default=()=>{a.default.reducer.register("cms",(0,o.combineReducers)({anchorSelector:i.default}))}},93:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.ConnectedAnchorSelectorField=t.Component=void 0;var a=C(n(754)),o=C(n(363)),i=C(n(875)),r=n(624),s=n(827),l=n(762),d=C(n(277)),u=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=_(t);if(n&&n.has(e))return n.get(e);var a={},o=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var i in e)if("default"!==i&&Object.prototype.hasOwnProperty.call(e,i)){var r=o?Object.getOwnPropertyDescriptor(e,i):null;r&&(r.get||r.set)?Object.defineProperty(a,i,r):a[i]=e[i]}a.default=e,n&&n.set(e,a);return a}(n(447)),c=C(n(892)),f=C(n(42)),p=C(n(453)),h=C(n(78)),m=C(n(720)),g=C(n(820)),v=C(n(86));function _(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(_=function(e){return e?n:t})(e)}function C(e){return e&&e.__esModule?e:{default:e}}const b=()=>null;class w extends d.default{constructor(e){super(e),this.handleChange=this.handleChange.bind(this),this.handleLoadingError=this.handleLoadingError.bind(this)}componentDidMount(){this.ensurePagesLoaded()}componentDidUpdate(e){this.props.pageId!==e.pageId&&this.ensurePagesLoaded()}ensurePagesLoaded(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:this.props;if(e.loadingState===c.default.UPDATING||e.loadingState===c.default.SUCCESS||!e.pageId)return Promise.resolve();let t=[];e.loadingState===c.default.FIELD_ONLY&&(t=this.props.anchors),e.actions.anchorSelector.beginUpdating(e.pageId);const n=e.data.endpoint.replace(/:id/,e.pageId);return(0,i.default)(n,{credentials:"same-origin"}).then((e=>e.json())).then((n=>{const a=[...new Set([...n,...t])];return e.actions.anchorSelector.updated(e.pageId,a),a})).catch((t=>{e.actions.anchorSelector.updateFailed(e.pageId),this.handleLoadingError(t,e)}))}getDropdownOptions(){const e=this.props.anchors.map((e=>({value:e})));return this.props.value&&!this.props.anchors.find((e=>e===this.props.value))&&e.unshift({value:this.props.value}),e}handleChange(e){"function"==typeof this.props.onChange&&this.props.onChange(e?e.value:"")}handleLoadingError(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.props;if(t.onLoadingError===b)throw e;return t.onLoadingError({errors:[{value:e.message,type:"error"}]})}render(){const{extraClass:e,CreatableSelectComponent:t}=this.props,n=(0,g.default)("anchorselectorfield",e),i=this.getDropdownOptions(),r=this.props.value||"",s=a.default._t("CMS.ANCHOR_SELECT_OR_TYPE","Select or enter anchor");return o.default.createElement(h.default,null,o.default.createElement(t,{isSearchable:!0,isClearable:!0,options:i,className:n,name:this.props.name,onChange:this.handleChange,value:{value:r},noOptionsMessage:()=>a.default._t("CMS.ANCHOR_NO_OPTIONS","No options"),placeholder:s,getOptionLabel:e=>{let{value:t}=e;return t},classNamePrefix:"anchorselectorfield"}))}}t.Component=w,w.propTypes={extraClass:v.default.string,id:v.default.string,name:v.default.string.isRequired,onChange:v.default.func,value:v.default.string,attributes:v.default.oneOfType([v.default.object,v.default.array]),pageId:v.default.number,anchors:v.default.array,loadingState:v.default.oneOf(Object.keys(c.default).map((e=>c.default[e]))),onLoadingError:v.default.func,data:v.default.shape({endpoint:v.default.string,targetFieldName:v.default.string})},w.defaultProps={value:"",extraClass:"",onLoadingError:b,attributes:{},CreatableSelectComponent:p.default};const S=(0,r.connect)((function(e,t){const n=(0,l.formValueSelector)(t.formid,m.default),a=t&&t.data&&t.data.targetFieldName||"PageID",o=Number(n(e,a)||0);let i=[];const r=o?e.cms.anchorSelector.pages.find((e=>e.id===o)):null;!r||r.loadingState!==c.default.SUCCESS&&r.loadingState!==c.default.DIRTY&&r.loadingState!==c.default.FIELD_ONLY||(i=r.anchors);let s=null;return s=r?r.loadingState:o?c.default.DIRTY:c.default.SUCCESS,{pageId:o,anchors:i,loadingState:s}}),(function(e){return{actions:{anchorSelector:(0,s.bindActionCreators)(u,e)}}}))(w);t.ConnectedAnchorSelectorField=S;var E=(0,f.default)(S);t.default=E},554:function(e,t,n){var a;((a=n(311))&&a.__esModule?a:{default:a}).default.entwine("ss",(function(e){e(".TreeDropdownField").entwine({OldValue:null}),e("#Form_AddForm_ParentID_Holder .treedropdownfield").entwine({onmatch(){this._super(),e(".cms-add-form").updateTypeList()}}),e(".cms-add-form .parent-mode :input").entwine({onclick:function(e){var t=this.closest("form").find("#Form_AddForm_ParentID_Holder .TreeDropdownField");"top"==this.val()?(t.setOldValue(t.getValue()),t.setValue(0)):(t.setValue(t.getOldValue()||0),t.setOldValue(null)),t.refresh(),t.trigger("change")}}),e(".cms-add-form").entwine({ParentCache:{},onadd:function(){var t=this;this.find("#Form_AddForm_ParentID_Holder .TreeDropdownField").on("change",(function(){t.updateTypeList()})),this.find(".SelectionGroup.parent-mode").on("change",(function(){t.updateTypeList()})),"top"==e(".cms-add-form .parent-mode :input").val()&&this.updateTypeList()},loadCachedChildren:function(e){var t=this.getParentCache();return void 0!==t[e]?t[e]:null},saveCachedChildren:function(e,t){var n=this.getParentCache();n[e]=t,this.setParentCache(n)},updateTypeList:function(){var t=this.data("hints"),n=this.find("#Form_AddForm_ParentID"),a=this.find("input[name=ParentModeField]:checked").val(),o=n.data("metadata"),i="child"===a?n.getValue():null,r=o?o.ClassName:null,s=r&&"child"===a&&i?r:"Root",l=void 0!==t[s]?t[s]:null,d=this,u=l&&void 0!==l.defaultChild?l.defaultChild:null,c=[];if(i){if(this.hasClass("loading"))return;return this.addClass("loading"),null!==(c=this.loadCachedChildren(i))?(this.updateSelectionFilter(c,u),void this.removeClass("loading")):(e.ajax({url:d.data("childfilter"),data:{ParentID:i},success:function(e){d.saveCachedChildren(i,e),d.updateSelectionFilter(e,u)},complete:function(){d.removeClass("loading")}}),!1)}c=l&&void 0!==l.disallowedChildren?l.disallowedChildren:[],this.updateSelectionFilter(c,u)},updateSelectionFilter:function(t,n){var a=this.find("#Form_AddForm_PageType div.radio.selected")[0],o=!1,i=null;if(this.find("#Form_AddForm_PageType div.radio").each((function(n,r){var s=e(this).find("input").val(),l=-1===e.inArray(s,t);r===a&&l&&(o=!0),e(this).setEnabled(l),l||e(this).setSelected(!1),i=(null===i||i)&&l})),o)var r=e(a).parents("li:first");else if(n)r=this.find("#Form_AddForm_PageType div.radio input[value="+n+"]").parents("li:first");else r=this.find("#Form_AddForm_PageType div.radio:not(.disabled):first");r.setSelected(!0),r.siblings().setSelected(!1),this.find("#Form_AddForm_PageType div.radio:not(.disabled)").length?this.find("button[name=action_doAdd]").removeAttr("disabled"):this.find("button[name=action_doAdd]").attr("disabled","disabled"),this.find(".message-restricted")[i?"hide":"show"]()}}),e(".cms-add-form #Form_AddForm_PageType div.radio").entwine({onclick:function(e){this.setSelected(!0)},setSelected:function(e){var t=this.find("input");e&&!t.is(":disabled")?(this.siblings().setSelected(!1),this.toggleClass("selected",!0),t.prop("checked",!0)):(this.toggleClass("selected",!1),t.prop("checked",!1))},setEnabled:function(t){e(this).toggleClass("disabled",!t),t?e(this).find("input").removeAttr("disabled"):e(this).find("input").attr("disabled","disabled").removeAttr("checked")}}),e(".cms-content-addpage-button").entwine({onclick:function(t){var n,a=e(".cms-tree"),o=e(".cms-list"),i=0;if(a.is(":visible")){var r=a.jstree("get_selected");i=r?e(r[0]).data("id"):null}else{var s=o.find('input[name="Page[GridState]"]').val();s&&(i=parseInt(JSON.parse(s).ParentID,10))}var l,d={selector:this.data("targetPanel"),pjax:this.data("pjax")};i?(n=this.data("extraParams")?this.data("extraParams"):"",l=e.path.addSearchParams(i18n.sprintf(this.data("urlAddpage"),i),n)):l=this.attr("href"),e(".cms-container").loadPanel(l,null,d),t.preventDefault(),this.blur()}})}))},649:function(e,t,n){var a=r(n(311)),o=r(n(754)),i=r(n(141));function r(e){return e&&e.__esModule?e:{default:e}}a.default.entwine("ss",(function(e){e(".cms-edit-form :input#Form_EditForm_ClassName").entwine({onchange:function(){alert(o.default._t("CMS.ALERTCLASSNAME"))}}),e(".cms-edit-form input[name=Title]").entwine({onmatch:function(){var t=this;t.data("OrigVal",t.val());var n=t.closest("form"),a=e("input:text[name=URLSegment]",n),o=e("input[name=LiveLink]",n);a.length>0&&(t._addActions(),this.on("change",(function(n){var i=t.data("OrigVal"),r=t.val();t.data("OrigVal",r),0===a.val().indexOf(a.data("defaultUrl"))&&""==o.val()?t.updateURLSegment(r):e(".update",t.parent()).show().parent(".form__field-holder").addClass("input-group"),t.updateRelatedFields(r,i),t.updateBreadcrumbLabel(r)}))),this._super()},onunmatch:function(){this._super()},updateRelatedFields:function(t,n){this.parents("form").find("input[name=MetaTitle], input[name=MenuTitle]").each((function(){var a=e(this);a.val()==n&&(a.val(t),a.updatedRelatedFields&&a.updatedRelatedFields())}))},updateURLSegment:function(t){var n=e("input:text[name=URLSegment]",this.closest("form")).closest(".field.urlsegment"),a=e(".update",this.parent());n.update(t),a.is(":visible")&&a.hide().parent(".form__field-holder").removeClass("input-group")},updateBreadcrumbLabel:function(t){e(".cms-edit-form input[name=ID]").val();var n=e("span.cms-panel-link.crumb");t&&""!=t&&n.text(t)},_addActions:function(){var t,n=this;(t=e("<button />",{class:"update btn btn-outline-secondary form__field-update-url",text:o.default._t("CMS.UpdateURL"),type:"button",click:function(e){e.preventDefault(),n.updateURLSegment(n.val())}})).insertAfter(n),t.hide()}}),e(".cms-edit-form .parentTypeSelector").entwine({onmatch:function(){var e=this;this.find(":input[name=ParentType]").on("click",(function(t){e._toggleSelection(t)})),this.find(".TreeDropdownField").on("change",(function(t){e._changeParentId(t)})),this._changeParentId(),this._toggleSelection(),this._super()},onunmatch:function(){this._super()},_toggleSelection:function(t){var n=this.find(":input[name=ParentType]:checked").val(),a=this.find("#Form_EditForm_ParentID_Holder");"root"==n?this.find(":input[name=ParentID]").val(0):this.find(":input[name=ParentID]").val(this.find("#Form_EditForm_ParentType_subpage").data("parentIdValue")),"root"!=n?a.slideDown(400,(function(){e(this).css("overflow","visible")})):a.slideUp()},_changeParentId:function(e){var t=this.find(":input[name=ParentID]").val();this.find("#Form_EditForm_ParentType_subpage").data("parentIdValue",t)}}),e(".cms-edit-form .btn-toolbar #Form_EditForm_action_doRollback, .cms-edit-form .btn-toolbar #Form_EditForm_action_rollback").entwine({onclick:function(e){if(this.is(":disabled"))return e.preventDefault(),!1;const t=this.parents("form:first").find(":input[name=Version]").val(),n=t?o.default.sprintf(o.default._t("CMS.RollbackToVersion","Do you really want to roll back to version #%s of this page?"),t):o.default._t("CMS.ConfirmRestoreFromLive","Are you sure you want to revert draft to when the page was last published?");return confirm(n)?(this.parents("form:first").addClass("loading"),this._super(e)):(e.preventDefault(),!1)}}),e(".cms-edit-form .btn-toolbar #Form_EditForm_action_archive:not(.homepage-warning)").entwine({onclick:function(e){var t;return t=this.parents("form:first").find("input[name=ArchiveWarningMessage]").val().replace(/\\n/g,"\n"),!!confirm(t)&&(this.parents("form:first").addClass("loading"),this._super(e))}}),e(".cms-edit-form .btn-toolbar #Form_EditForm_action_restore").entwine({onclick:function(e){var t,n=this.parents("form:first").find(":input[name=Version]").val(),a=this.data("toRoot");return t=o.default.sprintf(o.default._t(a?"CMS.RestoreToRoot":"CMS.Restore"),n),!!confirm(t)&&(this.parents("form:first").addClass("loading"),this._super(e))}}),e(".cms-edit-form .btn-toolbar #Form_EditForm_action_unpublish:not(.homepage-warning)").entwine({onclick:function(e){var t,n=this.parents("form:first").find(":input[name=Version]").val();return t=o.default.sprintf(o.default._t("CMS.Unpublish"),n),!!confirm(t)&&(this.parents("form:first").addClass("loading"),this._super(e))}}),e(".cms-edit-form.changed").entwine({onmatch:function(t){this.find("button[data-text-alternate]").each((function(){const t=e(this),n=t.find(".btn__title"),a=t.data("textAlternate");a&&(t.data("textStandard",n.text()),n.text(a));const o=t.data("btnAlternate");o&&(t.data("btnStandard",t.attr("class")),t.attr("class",o),t.removeClass("btn-outline-secondary").addClass("btn-primary"));const i=t.data("btnAlternateAdd");i&&t.addClass(i);const r=t.data("btnAlternateRemove");r&&t.removeClass(r)})),this._super(t)},onunmatch:function(t){this.find("button[data-text-alternate]").each((function(){const t=e(this),n=t.find(".btn__title"),a=t.data("textStandard");a&&n.text(a);const o=t.data("btnStandard");o&&(t.attr("class",o),t.addClass("btn-outline-secondary").removeClass("btn-primary"));const i=t.data("btnAlternateAdd");i&&t.removeClass(i);const r=t.data("btnAlternateRemove");r&&t.addClass(r)})),this._super(t)}}),e(".cms-edit-form .btn-toolbar button[name=action_publish]").entwine({onbuttonafterrefreshalternate:function(){this.data("showingAlternate")?(this.addClass("btn-primary"),this.removeClass("btn-secondary")):(this.removeClass("btn-primary"),this.addClass("btn-secondary"))}}),e(".cms-edit-form .btn-toolbar button[name=action_save]").entwine({onbuttonafterrefreshalternate:function(){this.data("showingAlternate")?(this.addClass("btn-primary"),this.removeClass("btn-secondary")):(this.removeClass("btn-primary"),this.addClass("btn-secondary"))}}),e('.cms-edit-form.CMSPageSettingsController input[name="ParentType"]:checked').entwine({onmatch:function(){this.redraw(),this._super()},onunmatch:function(){this._super()},redraw:function(){var t=e(".cms-edit-form.CMSPageSettingsController #Form_EditForm_ParentID_Holder");"Form_EditForm_ParentType_root"==e(this).attr("id")?t.slideUp():t.slideDown()},onclick:function(){this.redraw()}}),"Form_EditForm_ParentType_root"==e('.cms-edit-form.CMSPageSettingsController input[name="ParentType"]:checked').attr("id")&&e(".cms-edit-form.CMSPageSettingsController #Form_EditForm_ParentID_Holder").hide();var t=!1;e(".cms-edit-form .btn-toolbar #Form_EditForm_action_unpublish.homepage-warning,.cms-edit-form .btn-toolbar #Form_EditForm_action_archive.homepage-warning,#Form_EditForm_URLSegment_Holder.homepage-warning .btn.update").entwine({onclick:async function(e){if(t)return this._super(e);e.stopPropagation();var n=o.default._t("CMS.RemoveHomePageWarningMessage","Warning: This page is the home page. By changing the URL segment visitors will not be able to view it.");return await(0,i.default)({title:o.default._t("CMS.RemoveHomePageWarningTitle","Remove your home page?"),message:n,confirmText:o.default._t("CMS.RemoveHomePageWarningLabel","Remove"),confirmColor:"danger"})&&(t=!0,this.trigger("click"),t=!1),!1}})}))},978:function(e,t,n){var a=s(n(311)),o=s(n(754)),i=s(n(141)),r=n(845);function s(e){return e&&e.__esModule?e:{default:e}}a.default.entwine("ss.tree",(function(e){e(".cms-tree").entwine({fromDocument:{"oncontext_show.vakata":function(e){this.adjustContextClass()}},adjustContextClass:function(){var t=e("#vakata-contextmenu").find("ul ul");t.each((function(n){var a="1",o=e(t[n]).find("li").length;o>20?a="3":o>10&&(a="2"),e(t[n]).addClass("vakata-col-"+a).removeClass("right"),e(t[n]).find("li").on("mouseenter",(function(t){e(this).parent("ul").removeClass("right")}))}))},showListViewFor:function(t){localStorage.setItem("ss.pages-view-type","listview");const n=this.closest(".cms-content-view").data("url-listviewroot"),a=e.path.addSearchParams(n,{ParentID:t}),o=e("base").attr("href")||"";window.location.assign((0,r.joinUrlPaths)(o,a))},getTreeConfig:function(){var t=this,n=this._super();this.getHints();return n.plugins.push("contextmenu"),n.contextmenu={items:function(n){var a={edit:{label:n.hasClass("edit-disabled")?o.default._t("CMS.EditPage","Edit page",100,"Used in the context menu when right-clicking on a page node in the CMS tree"):o.default._t("CMS.ViewPage","View page",100,"Used in the context menu when right-clicking on a page node in the CMS tree"),action:function(n){e(".cms-container").entwine(".ss").loadPanel(o.default.sprintf(t.data("urlEditpage"),n.data("id")))}}};n.hasClass("nochildren")||(a.showaslist={label:o.default._t("CMS.ShowAsList"),action:function(e){t.showListViewFor(e.data("id"))}});n.data("pagetype");var i=n.data("id"),r=n.find(">a .item").data("allowedchildren"),s={},l=!1;return e.each(r,(function(n,a){l=!0,s["allowedchildren-"+a.ClassName]={label:'<span class="jstree-pageicon '+a.IconClass+'"></span>'+a.Title,_class:"class-"+a.ClassName.replace(/[^a-zA-Z0-9\-_:.]+/g,"_"),action:function(n){e(".cms-container").entwine(".ss").loadPanel(e.path.addSearchParams(o.default.sprintf(t.data("urlAddpage"),i,a.ClassName),t.data("extraParams")))}}})),l&&(a.addsubpage={label:o.default._t("CMS.AddSubPage","Add page under this page",100,"Used in the context menu when right-clicking on a page node in the CMS tree"),submenu:s}),n.hasClass("edit-disabled")||(a.duplicate={label:o.default._t("CMS.Duplicate"),submenu:[{label:o.default._t("CMS.ThisPageOnly"),action:function(n){e(".cms-container").entwine(".ss").loadPanel(e.path.addSearchParams(o.default.sprintf(t.data("urlDuplicate"),n.data("id")),t.data("extraParams")))}},{label:o.default._t("CMS.ThisPageAndSubpages"),action:function(n){e(".cms-container").entwine(".ss").loadPanel(e.path.addSearchParams(o.default.sprintf(t.data("urlDuplicatewithchildren"),n.data("id")),t.data("extraParams")))}}]}),a}},n},canMove:async function(e){if(!(e.rslt.o.find(".homepage").first().length>0))return!0;if(e.rslt.op.data("id")===e.rslt.np.data("id"))return!0;var t=o.default._t("CMS.RemoveHomePageWarningMessage","Warning: This page is the home page. By changing the URL segment visitors will not be able to view it.");return await(0,i.default)({title:o.default._t("CMS.RemoveHomePageWarningTitle","Remove your home page?"),message:t,confirmText:o.default._t("CMS.RemoveHomePageWarningLabel","Remove"),confirmColor:"danger"})}}),e(".cms-tree a.jstree-clicked").entwine({onmatch:function(){var e=this,t=e.parents(".cms-tree-view-sidebar");if(e.offset().top<0||e.offset().top>t.height()-e.height()){var n=e.parent();n.prev().length&&(n=n.prev()),n.get(0).scrollIntoView()}}}),e(".cms-tree-filtered .clear-filter").entwine({onclick:function(){window.location=location.protocol+"//"+location.host+location.pathname}}),e(".cms-tree .subtree-list-link").entwine({onclick:function(e){e.preventDefault(),this.closest(".cms-tree").showListViewFor(this.data("id"))}})}))},580:function(e,t,n){var a,o=(a=n(311))&&a.__esModule?a:{default:a},i=n(845);o.default.entwine("ss",(function(e){const t="treeview",n="listview";e(".cms-content-header-info").entwine({"from .cms-panel":{ontoggle:function(e){var t=this.closest(".cms-content").find(e.target);0!==t.length&&this.parent()[t.hasClass("collapsed")?"addClass":"removeClass"]("collapsed")}}}),e(".cms-panel-deferred.cms-content-view").entwine({onadd:function(){if(this.data("no-ajax"))return;var e=localStorage.getItem("ss.pages-view-type")||t;this.closest(".cms-content-tools").length>0&&(e=t);const a=this.data(`url-${e}`);let o=localStorage.getItem("ss.pages-view-filtered");"string"==typeof o&&"false"===o.toLowerCase()&&(o=!1),localStorage.setItem("ss.pages-view-filtered",!1),this.data("deferredNoCache",o||e===n),this.data("url",a+location.search),this._super()}}),e(".js-injector-boot .search-holder--cms").entwine({search(e){localStorage.setItem("ss.pages-view-filtered",!0),this._super(e)}}),e(".cms .page-view-link").entwine({onclick:function(t){t.preventDefault();const a=e(this).data("view"),o=this.closest(".cms-content-view"),r=o.data(`url-${a}`),s=0!==o.closest(".cms-content-tools").length;if(localStorage.setItem("ss.pages-view-type",a),s&&a===n){const t=e("base").attr("href")||"";window.location.assign((0,i.joinUrlPaths)(t,o.data("url-listviewroot")))}else o.data("url",r+location.search),o.redraw()}}),e(".cms .cms-clear-filter").entwine({onclick:function(t){t.preventDefault(),window.location=e(this).prop("href")}}),e(".cms-content-toolbar").entwine({onmatch:function(){var t=this;this._super(),e.each(this.find(".cms-actions-buttons-row .tool-button"),(function(){var n=e(this),a=n.data("toolid");n.hasClass("active");void 0!==a&&(n.data("active",!1).removeClass("active"),e("#"+a).hide(),t.bindActionButtonEvents(n))}))},onunmatch:function(){var t=this;this._super(),e.each(this.find(".cms-actions-buttons-row .tool-button"),(function(){var n=e(this);t.unbindActionButtonEvents(n)}))},bindActionButtonEvents:function(e){var t=this;e.on("click.cmsContentToolbar",(function(n){t.showHideTool(e)}))},unbindActionButtonEvents:function(e){e.off(".cmsContentToolbar")},showHideTool:function(t){var n=t.data("active"),a=t.data("toolid"),o=e("#"+a);e.each(this.find(".cms-actions-buttons-row .tool-button"),(function(){var t=e(this),n=e("#"+t.data("toolid"));t.data("toolid")!==a&&(n.hide(),t.data("active",!1))})),t[n?"removeClass":"addClass"]("active"),o[n?"hide":"show"](),t.data("active",!n)}})}))},907:function(e,t,n){var a;((a=n(311))&&a.__esModule?a:{default:a}).default.entwine("ss",(function(e){e("#Form_EditForm_RedirectionType input").entwine({onmatch:function(){e(this).attr("checked")&&this.toggle(),this._super()},onunmatch:function(){this._super()},onclick:function(){this.toggle()},toggle:function(){"Internal"==e(this).attr("value")?(e("#Form_EditForm_ExternalURL_Holder").hide(),e("#Form_EditForm_LinkToID_Holder").show(),e("#Form_EditForm_LinkToFile_Holder").hide()):"External"==e(this).attr("value")?(e("#Form_EditForm_ExternalURL_Holder").show(),e("#Form_EditForm_LinkToID_Holder").hide(),e("#Form_EditForm_LinkToFile_Holder").hide()):(e("#Form_EditForm_LinkToFile_Holder").show(),e("#Form_EditForm_ExternalURL_Holder").hide(),e("#Form_EditForm_LinkToID_Holder").hide())}})}))},806:function(e,t,n){var a;((a=n(311))&&a.__esModule?a:{default:a}).default.entwine("ss",(function(e){e(".field.urlsegment:not(.readonly)").entwine({MaxPreviewLength:55,Ellipsis:"...",onmatch:function(){this.find(":text").length&&this.toggleEdit(!1),this.redraw(),this._super()},redraw:function(){var e=this.find(":text"),t=decodeURI(e.data("prefix")+e.val()),n=t;t.length>this.getMaxPreviewLength()&&(n=this.getEllipsis()+t.substr(t.length-this.getMaxPreviewLength(),t.length)),this.find(".URL-link").attr("href",encodeURI(t+e.data("suffix"))).text(n)},toggleEdit:function(e){var t=this.find(":text");this.find(".preview-holder")[e?"hide":"show"](),this.find(".edit-holder")[e?"show":"hide"](),e&&(t.data("origval",t.val()),t.focus())},update:function(){var e=this,t=this.find(":text"),n=t.data("origval"),a=arguments[0],o=a&&""!==a?a:t.val();n!=o?(this.addClass("loading"),this.suggest(o,(function(n){t.val(decodeURIComponent(n.value)),e.toggleEdit(!1),e.removeClass("loading"),e.redraw()}))):(this.toggleEdit(!1),this.redraw())},cancel:function(){var e=this.find(":text");e.val(e.data("origval")),this.toggleEdit(!1)},suggest:function(t,n){var a=this,o=a.find(":text"),i=e.path.parseUrl(a.closest("form").attr("action")),r=i.hrefNoSearch+"/field/"+o.attr("name")+"/suggest/?value="+encodeURIComponent(t);i.search&&(r+="&"+i.search.replace(/^\?/,"")),e.ajax({url:r,success:function(e){n.apply(this,arguments)},error:function(e,t){e.statusText=e.responseText},complete:function(){a.removeClass("loading")}})}}),e(".field.urlsegment .text").entwine({onkeydown:function(e){13===e.keyCode&&(e.preventDefault(),this.closest(".field").update())}}),e(".field.urlsegment .edit").entwine({onclick:function(e){e.preventDefault(),this.closest(".field").toggleEdit(!0)}}),e(".field.urlsegment .update").entwine({onclick:function(e){e.preventDefault(),this.closest(".field").update()}}),e(".field.urlsegment .cancel").entwine({onclick:function(e){e.preventDefault(),this.closest(".field").cancel()}})}))},964:function(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;t.default={ANCHORSELECTOR_CURRENT_FIELD:"ANCHORSELECTOR_CURRENT_FIELD",ANCHORSELECTOR_UPDATED:"ANCHORSELECTOR_UPDATED",ANCHORSELECTOR_UPDATING:"ANCHORSELECTOR_UPDATING",ANCHORSELECTOR_UPDATE_FAILED:"ANCHORSELECTOR_UPDATE_FAILED"}},447:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.beginUpdating=function(e){return{type:o.default.ANCHORSELECTOR_UPDATING,payload:{pageId:e}}},t.updateFailed=function(e){return{type:o.default.ANCHORSELECTOR_UPDATE_FAILED,payload:{pageId:e}}},t.updated=function(e,t){let n=arguments.length>2&&void 0!==arguments[2]&&arguments[2];return{type:o.default.ANCHORSELECTOR_UPDATED,payload:{pageId:e,anchors:t,cacheResult:n}}},t.updatedCurrentField=function(e,t,n){return{type:o.default.ANCHORSELECTOR_CURRENT_FIELD,payload:{pageId:e,anchors:t,fieldID:n}}};var a,o=(a=n(964))&&a.__esModule?a:{default:a}},572:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:s,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;const n=(n,o)=>{const i=t.payload.pageId;return(0,a.default)({pages:[...e.pages.filter((e=>e.id!==i)),{id:i,loadingState:n,anchors:o}].sort(((e,t)=>e.id-t.id))})};switch(t.type){case o.default.ANCHORSELECTOR_UPDATING:return n(i.default.UPDATING,[]);case o.default.ANCHORSELECTOR_UPDATED:{const{anchors:e,cacheResult:a}=t.payload,{SUCCESS:o,DIRTY:r}=i.default;return n(a?o:r,e)}case o.default.ANCHORSELECTOR_CURRENT_FIELD:{const{anchors:e}=t.payload;return n(i.default.FIELD_ONLY,e)}case o.default.ANCHORSELECTOR_UPDATE_FAILED:return n(i.default.FAILED,[]);default:return e}};var a=r(n(752)),o=r(n(964)),i=r(n(892));function r(e){return e&&e.__esModule?e:{default:e}}const s=(0,a.default)({pages:[]})},892:function(e,t){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;t.default={SUCCESS:"SUCCESS",DIRTY:"DIRTY",FIELD_ONLY:"FIELD_ONLY",UPDATING:"UPDATING",FAILED:"FAILED"}},436:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.query=t.default=t.config=void 0;var a,o=n(732);const i=((a=n(306))&&a.__esModule?a:{default:a}).default`
query ReadHistoryViewerPage ($page_id: ID!, $limit: Int!, $offset: Int!) {
readOnePage(
versioning: {
mode: ALL_VERSIONS
},
filter: {
id: { eq: $page_id }
}
) {
id
versions (limit: $limit, offset: $offset, sort: {
version: DESC
}) {
pageInfo {
totalCount
}
nodes {
version
absoluteLink
author {
firstName
surname
}
publisher {
firstName
surname
}
deleted
draft
published
liveVersion
latestDraftVersion
lastEdited
}
}
}
}
`;t.query=i;const r={options(e){let{recordId:t,limit:n,page:a}=e;return{variables:{limit:n,offset:((a||1)-1)*n,page_id:t},fetchPolicy:"network-only"}},props(e){let{data:{error:t,refetch:n,readOnePage:a,loading:o},ownProps:{actions:i={versions:{}},limit:r,recordId:s}}=e;const l=a||null;return{loading:o||!l,versions:l,graphQLErrors:t&&t.graphQLErrors&&t.graphQLErrors.map((e=>e.message)),actions:{...i,versions:{...l,goToPage(e){n({offset:((e||1)-1)*r,limit:r,page_id:s})}}}}}};t.config=r;var s=(0,o.graphql)(i,r);t.default=s},149:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.mutation=t.default=t.config=void 0;var a,o=n(732);const i=((a=n(306))&&a.__esModule?a:{default:a}).default`
mutation rollbackPage($id:ID!, $toVersion:Int!) {
rollbackPage(
id: $id
toVersion: $toVersion
) {
id
}
}
`;t.mutation=i;const r={props:e=>{let{mutate:t,ownProps:{actions:n}}=e;const a=(e,n)=>t({variables:{id:e,toVersion:n}});return{actions:{...n,rollbackPage:a,revertToVersion:a}}},options:{refetchQueries:["ReadHistoryViewerPage"]}};t.config=r;var s=(0,o.graphql)(i,r);t.default=s},112:function(e,t,n){function a(e){return a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},a(e)}Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o,i=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!==a(e)&&"function"!=typeof e)return{default:e};var n=l(t);if(n&&n.has(e))return n.get(e);var o={},i=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var r in e)if("default"!==r&&Object.prototype.hasOwnProperty.call(e,r)){var s=i?Object.getOwnPropertyDescriptor(e,r):null;s&&(s.get||s.set)?Object.defineProperty(o,r,s):o[r]=e[r]}o.default=e,n&&n.set(e,o);return o}(n(363)),r=(o=n(86))&&o.__esModule?o:{default:o},s=n(127);function l(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(l=function(e){return e?n:t})(e)}function d(){return d=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var a in n)Object.prototype.hasOwnProperty.call(n,a)&&(e[a]=n[a])}return e},d.apply(this,arguments)}var u=function(e){var t=e.onClose,n=e.message,a=e.title,o=e.confirmText,r=e.cancelText,l=e.confirmColor,u=e.cancelColor,c=e.className,f=e.buttonsComponent,p=e.size,h=e.bodyComponent,m=e.modalProps,g=i.default.createElement(i.Fragment,null,r&&i.default.createElement(s.Button,{color:u,onClick:function(){return t(!1)}},r)," ",i.default.createElement(s.Button,{color:l,onClick:function(){return t(!0)}},o));if(f){var v=f;g=i.default.createElement(v,{onClose:t})}var _=h;return i.default.createElement(s.Modal,d({size:p,isOpen:!0,toggle:function(){return t(!1)},className:"reactstrap-confirm ".concat(c)},m),a&&i.default.createElement(s.ModalHeader,{toggle:function(){return t(!1)}},a||null),i.default.createElement(s.ModalBody,null,h?i.default.createElement(_,null):n),i.default.createElement(s.ModalFooter,null,g))};u.defaultProps={message:"Are you sure?",title:"Warning!",confirmText:"Ok",cancelText:"Cancel",confirmColor:"primary",cancelColor:"",className:"",buttonsComponent:null,size:null,bodyComponent:null,modalProps:{}},u.propTypes={onClose:r.default.func.isRequired,message:r.default.node,title:r.default.node,confirmText:r.default.node,cancelText:r.default.node,confirmColor:r.default.string,cancelColor:r.default.string,className:r.default.string,size:r.default.string,buttonsComponent:r.default.func,bodyComponent:r.default.func,modalProps:r.default.object};var c=u;t.default=c},141:function(e,t,n){Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var a=r(n(363)),o=n(394),i=r(n(112));function r(e){return e&&e.__esModule?e:{default:e}}function s(){return s=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var a in n)Object.prototype.hasOwnProperty.call(n,a)&&(e[a]=n[a])}return e},s.apply(this,arguments)}var l=function(e){return new Promise((function(t){var n=document.createElement("div");(0,o.render)(a.default.createElement(i.default,s({},e,{onClose:function(e){(0,o.unmountComponentAtNode)(n),n=null,t(e)}})),n)}))};t.default=l},732:function(e){e.exports=ApolloClientReactHoc},752:function(e){e.exports=DeepFreezeStrict},78:function(e){e.exports=EmotionCssCacheProvider},42:function(e){e.exports=FieldHolder},306:function(e){e.exports=GraphQLTag},648:function(e){e.exports=Injector},875:function(e){e.exports=IsomorphicFetch},86:function(e){e.exports=PropTypes},363:function(e){e.exports=React},394:function(e){e.exports=ReactDom},624:function(e){e.exports=ReactRedux},453:function(e){e.exports=ReactSelectCreatable},127:function(e){e.exports=Reactstrap},827:function(e){e.exports=Redux},762:function(e){e.exports=ReduxForm},277:function(e){e.exports=SilverStripeComponent},820:function(e){e.exports=classnames},720:function(e){e.exports=getFormState},754:function(e){e.exports=i18n},311:function(e){e.exports=jQuery},845:function(e){e.exports=ssUrlLib}},t={};function n(a){var o=t[a];if(void 0!==o)return o.exports;var i=t[a]={exports:{}};return e[a](i,i.exports,n),i.exports}n(554),n(649),n(580),n(978),n(907),n(806),n(274)}();

View File

@ -1 +1 @@
#SilverStripeNavigator{position:fixed;bottom:0;left:0;width:100%;border-top:2px solid #d4d0c8;background-color:#81858d;height:22px}#SilverStripeNavigator *{font-family:Arial,Helvetica,sans-serif;font-size:10px!important}#SilverStripeNavigator .holder{text-align:center;padding-top:4px;padding-left:3px;padding-right:6px;color:#fff;border-top:1px solid #555}#SilverStripeNavigator #logInStatus{float:right}#SilverStripeNavigator #switchView{float:left}#SilverStripeNavigator a{color:#fff;text-decoration:underline}#SilverStripeNavigator a,#SilverStripeNavigator a:hover{background-color:transparent}#SilverStripeNavigator .bottomTabs a{margin-right:8px;text-decoration:underline}#SilverStripeNavigator .bottomTabs a.current{font-weight:700;text-decoration:none}#SilverStripeNavigatorMessage{font-family:Lucida Grande,Verdana,Arial,"sans-serif";position:fixed;z-index:1000;right:20px;top:40px;padding:10px;border-color:#c99;color:#fff;background-color:#c00;border:1px solid #000}#SilverStripeNavigatorLinkPopup{display:none;position:absolute;top:-60px;height:50px;width:350px;left:200px;background-color:#fff;border:1px solid #000;z-index:100;color:#000;padding:5px}#SilverStripeNavigatorLinkPopup input{width:250px}#SilverStripeNavigatorLinkPopup a.close{color:blue;text-align:right;width:80%;border:none!important;cursor:pointer} #SilverStripeNavigator{position:fixed;bottom:0;left:0;width:100%;border-top:2px solid #d4d0c8;background-color:#81858d;height:22px}#SilverStripeNavigator *{font-family:Arial,Helvetica,sans-serif;font-size:10px !important}#SilverStripeNavigator .holder{text-align:center;padding-top:4px;padding-left:3px;padding-right:6px;color:#fff;border-top:1px solid #555}#SilverStripeNavigator #logInStatus{float:right}#SilverStripeNavigator #switchView{float:left}#SilverStripeNavigator a{color:#fff;background-color:rgba(0,0,0,0);text-decoration:underline}#SilverStripeNavigator a:hover{background-color:rgba(0,0,0,0)}#SilverStripeNavigator .bottomTabs a{margin-right:8px;text-decoration:underline}#SilverStripeNavigator .bottomTabs a.current{font-weight:bold;text-decoration:none}#SilverStripeNavigatorMessage{font-family:"Lucida Grande",Verdana,Arial,"sans-serif";position:fixed;z-index:1000;right:20px;top:40px;padding:10px;border-color:#c99;color:#fff;background-color:#c00;border:1px solid #000}#SilverStripeNavigatorLinkPopup{display:none;position:absolute;top:-60px;height:50px;width:350px;left:200px;background-color:#fff;border:1px solid #000;z-index:100;color:#000;padding:5px}#SilverStripeNavigatorLinkPopup input{width:250px}#SilverStripeNavigatorLinkPopup a.close{color:blue;text-align:right;width:80%;border:none !important;cursor:pointer}

View File

@ -1 +1 @@
#cms-page-history-versions tr.loading{color:#999}#cms-page-history-versions tr.loading td:hover{cursor:none}#cms-page-history-versions td:hover{cursor:pointer}.CMSPageHistoryController{overflow:hidden}.CMSPageHistoryController ins{background-color:#dfd;padding:2px;text-decoration:none}.CMSPageHistoryController del{background-color:#fdd;padding:2px;color:#f44}.CMSPageHistoryController .htmleditorfield.readonly img{max-width:100%;height:auto}.CMSPageHistoryController .cms-content-tools.collapsed{overflow:hidden}#cms-content-listview .cms-tree-expand-trigger,#cms-content-treeview .cms-tree-expand-trigger{display:none}.cms-content-tools #cms-content-treeview .cms-content-toolbar{border-bottom:none;-webkit-box-shadow:none;box-shadow:none;margin-bottom:0}.cms-content-tools #cms-content-treeview .cms-tree-expand-trigger{display:block;float:left;margin:0 0 2px}.cms-content-tools #cms-content-treeview .cms-tree-expand-trigger span.ui-button-text{padding-right:8px}.cms-content-tools #cms-content-treeview .cms-tree .badge{display:none}.cms-content-tools #cms-content-treeview .cms-tree .jstree-clicked>.text>.badge,.cms-content-tools #cms-content-treeview .cms-tree a:hover>.text>.badge{display:inline-block}#cms-content-tools-CMSMain .search-form{right:0}.cms-list .cms-list__item-breadcrumbs{margin-left:21px;margin-bottom:0;font-size:.9em;word-break:break-word}.cms-content-toolbar .view-controls{margin-top:0}.cms-content-toolbar .view-controls .page-view-link{display:inline-block;margin-right:-5px}.cms-content-toolbar .view-controls.view-controls--listview .font-icon-list,.cms-content-toolbar .view-controls.view-controls--treeview .font-icon-tree{display:none}#pages-controller-cms-content,#pages-controller-cms-content+.cms-preview{width:50%}.field.urlsegment .input-group{width:auto;-webkit-flex-wrap:nowrap;flex-wrap:nowrap}.field.urlsegment.loading .form__field-label{background-image:url(data:image/gif;base64,R0lGODlhEAAQAPQAAP///wpakvj6+z9+qYivyg9dlC5yotfk7KvG2R9om3umxGubveXt8py80sjZ5k+IsFyRtgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAAFUCAgjmRpnqUwFGwhKoRgqq2YFMaRGjWA8AbZiIBbjQQ8AmmFUJEQhQGJhaKOrCksgEla+KIkYvC6SJKQOISoNSYdeIk1ayA8ExTyeR3F749CACH5BAkKAAAALAAAAAAQABAAAAVoICCKR9KMaCoaxeCoqEAkRX3AwMHWxQIIjJSAZWgUEgzBwCBAEQpMwIDwY1FHgwJCtOW2UDWYIDyqNVVkUbYr6CK+o2eUMKgWrqKhj0FrEM8jQQALPFA3MAc8CQSAMA5ZBjgqDQmHIyEAIfkECQoAAAAsAAAAABAAEAAABWAgII4j85Ao2hRIKgrEUBQJLaSHMe8zgQo6Q8sxS7RIhILhBkgumCTZsXkACBC+0cwF2GoLLoFXREDcDlkAojBICRaFLDCOQtQKjmsQSubtDFU/NXcDBHwkaw1cKQ8MiyEAIfkECQoAAAAsAAAAABAAEAAABVIgII5kaZ6AIJQCMRTFQKiDQx4GrBfGa4uCnAEhQuRgPwCBtwK+kCNFgjh6QlFYgGO7baJ2CxIioSDpwqNggWCGDVVGphly3BkOpXDrKfNm/4AhACH5BAkKAAAALAAAAAAQABAAAAVgICCOZGmeqEAMRTEQwskYbV0Yx7kYSIzQhtgoBxCKBDQCIOcoLBimRiFhSABYU5gIgW01pLUBYkRItAYAqrlhYiwKjiWAcDMWY8QjsCf4DewiBzQ2N1AmKlgvgCiMjSQhACH5BAkKAAAALAAAAAAQABAAAAVfICCOZGmeqEgUxUAIpkA0AMKyxkEiSZEIsJqhYAg+boUFSTAkiBiNHks3sg1ILAfBiS10gyqCg0UaFBCkwy3RYKiIYMAC+RAxiQgYsJdAjw5DN2gILzEEZgVcKYuMJiEAOwAAAAAAAAAAAA==);background-repeat:no-repeat;background-position:100%;padding-right:20px}.field.urlsegment .URL-link{padding-top:8px;display:inline-block}.field.urlsegment input.text{-webkit-box-flex:0;-webkit-flex:0 1 250px;flex:0 1 250px}.field.urlsegment .input-group-append{z-index:2}.field.urlsegment .input-group-append:last-of-type{z-index:1}.field.urlsegment .input-group-append .btn{margin-top:0;padding-top:.5385rem;padding-bottom:.5385rem}.field.urlsegment .help{margin-left:0}.field.urlsegment .edit-holder{display:none}.field.urlsegment .edit-holder .form__field-description{clear:both}.form__field-update-url{border-radius:0 3px 3px 0;margin-right:0;margin-left:-1px} #cms-page-history-versions tr.loading{color:#999}#cms-page-history-versions tr.loading td:hover{cursor:none}#cms-page-history-versions td:hover{cursor:pointer}#cms-content-treeview .cms-tree-expand-trigger,#cms-content-listview .cms-tree-expand-trigger{display:none}.cms-content-tools #cms-content-treeview .cms-content-toolbar{border-bottom:none;box-shadow:none;margin-bottom:0}.cms-content-tools #cms-content-treeview .cms-tree-expand-trigger{display:block;float:left;margin:0 0 2px 0}.cms-content-tools #cms-content-treeview .cms-tree-expand-trigger span.ui-button-text{padding-right:8px}.cms-content-tools #cms-content-treeview .cms-tree .badge{display:none}.cms-content-tools #cms-content-treeview .cms-tree a:hover>.text>.badge,.cms-content-tools #cms-content-treeview .cms-tree .jstree-clicked>.text>.badge{display:inline-block}#cms-content-tools-CMSMain .search-form{right:0}.cms-list .cms-list__item-breadcrumbs{margin-left:21px;margin-bottom:0;font-size:.9em;word-break:break-word}.cms-content-toolbar .view-controls{margin-top:0}.cms-content-toolbar .view-controls .page-view-link{display:inline-block;margin-right:-5px}.cms-content-toolbar .view-controls.view-controls--treeview .font-icon-tree,.cms-content-toolbar .view-controls.view-controls--listview .font-icon-list{display:none}#pages-controller-cms-content,#pages-controller-cms-content+.cms-preview{width:50%}.field.urlsegment .input-group{width:auto;flex-wrap:nowrap}.field.urlsegment.loading .form__field-label{background-image:url(data:image/gif;base64,R0lGODlhEAAQAPQAAP///wpakvj6+z9+qYivyg9dlC5yotfk7KvG2R9om3umxGubveXt8py80sjZ5k+IsFyRtgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh/hpDcmVhdGVkIHdpdGggYWpheGxvYWQuaW5mbwAh+QQJCgAAACwAAAAAEAAQAAAFUCAgjmRpnqUwFGwhKoRgqq2YFMaRGjWA8AbZiIBbjQQ8AmmFUJEQhQGJhaKOrCksgEla+KIkYvC6SJKQOISoNSYdeIk1ayA8ExTyeR3F749CACH5BAkKAAAALAAAAAAQABAAAAVoICCKR9KMaCoaxeCoqEAkRX3AwMHWxQIIjJSAZWgUEgzBwCBAEQpMwIDwY1FHgwJCtOW2UDWYIDyqNVVkUbYr6CK+o2eUMKgWrqKhj0FrEM8jQQALPFA3MAc8CQSAMA5ZBjgqDQmHIyEAIfkECQoAAAAsAAAAABAAEAAABWAgII4j85Ao2hRIKgrEUBQJLaSHMe8zgQo6Q8sxS7RIhILhBkgumCTZsXkACBC+0cwF2GoLLoFXREDcDlkAojBICRaFLDCOQtQKjmsQSubtDFU/NXcDBHwkaw1cKQ8MiyEAIfkECQoAAAAsAAAAABAAEAAABVIgII5kaZ6AIJQCMRTFQKiDQx4GrBfGa4uCnAEhQuRgPwCBtwK+kCNFgjh6QlFYgGO7baJ2CxIioSDpwqNggWCGDVVGphly3BkOpXDrKfNm/4AhACH5BAkKAAAALAAAAAAQABAAAAVgICCOZGmeqEAMRTEQwskYbV0Yx7kYSIzQhtgoBxCKBDQCIOcoLBimRiFhSABYU5gIgW01pLUBYkRItAYAqrlhYiwKjiWAcDMWY8QjsCf4DewiBzQ2N1AmKlgvgCiMjSQhACH5BAkKAAAALAAAAAAQABAAAAVfICCOZGmeqEgUxUAIpkA0AMKyxkEiSZEIsJqhYAg+boUFSTAkiBiNHks3sg1ILAfBiS10gyqCg0UaFBCkwy3RYKiIYMAC+RAxiQgYsJdAjw5DN2gILzEEZgVcKYuMJiEAOwAAAAAAAAAAAA==);background-repeat:no-repeat;background-position:right center;padding-right:20px}.field.urlsegment .URL-link{padding-top:8px;display:inline-block}.field.urlsegment input.text{flex:0 1 250px}.field.urlsegment .input-group-append{z-index:2}.field.urlsegment .input-group-append:last-of-type{z-index:1}.field.urlsegment .input-group-append .btn{margin-top:0;padding-top:.5385rem;padding-bottom:.5385rem}.field.urlsegment .help{margin-left:0}.field.urlsegment .edit-holder{display:none}.field.urlsegment .edit-holder .form__field-description{clear:both}.form__field-update-url{border-radius:0 3px 3px 0;margin-right:0px;margin-left:-1px}.anchorselectorfield__menu{z-index:20000}

View File

@ -8,17 +8,17 @@ if (typeof(ss) === 'undefined' || typeof(ss.i18n) === 'undefined') {
ss.i18n.addDictionary('nl', { ss.i18n.addDictionary('nl', {
"CMS.ALERTCLASSNAME": "Het paginatype wordt aangepast na het opslaan van de pagina", "CMS.ALERTCLASSNAME": "Het paginatype wordt aangepast na het opslaan van de pagina",
"CMS.AddSubPage": "Voeg nieuwe pagina toe", "CMS.AddSubPage": "Voeg nieuwe pagina toe",
"CMS.ConfirmRestoreFromLive": "Weet je zeker dat je terug wil naar de laatst gepubliceerde versie van deze pagina?", "CMS.ConfirmRestoreFromLive": "Weet u zeker dat u terug wil naar de laatst gepubliceerde versie van deze pagina?",
"CMS.Duplicate": "Dupliceren", "CMS.Duplicate": "Dupliceren",
"CMS.EditPage": "Aanpassen", "CMS.EditPage": "Aanpassen",
"CMS.ONLYSELECTTWO": "Er kunnen maar 2 pagina's tegelijk worden vergeleken.", "CMS.ONLYSELECTTWO": "Er kunnen maar 2 pagina's tegelijk worden vergeleken.",
"CMS.Restore": "Weet je zeker dat deze pagina hersteld moet worden?", "CMS.Restore": "Weet u zeker dat deze pagina hersteld moet worden?",
"CMS.RestoreToRoot": "Weet je zeker dat deze pagina hersteld moet worden?\n\nDe bovenliggende pagina bestaat niet meer, waardoor deze pagina op het hoofdniveau terecht komt.", "CMS.RestoreToRoot": "Weet u zeker dat deze pagina hersteld moet worden?\n\nDe bovenliggende pagina bestaat niet meer, waardoor deze pagina op het hoofdniveau terecht komt.",
"CMS.RollbackToVersion": "Wil je teruggaan naar versie #%s van deze pagina?", "CMS.RollbackToVersion": "Wilt u terugdraaien naar versie #%s van deze pagina?",
"CMS.ShowAsList": "Toon onderliggende pagina's als lijst", "CMS.ShowAsList": "Toon onderliggende pagina's als lijst",
"CMS.ThisPageAndSubpages": "Deze pagina en subpagina's", "CMS.ThisPageAndSubpages": "Deze pagina en subpagina's",
"CMS.ThisPageOnly": "Enkel deze pagina", "CMS.ThisPageOnly": "Enkel deze pagina",
"CMS.Unpublish": "Weet je zeker dat deze pagina verwijderd moet worden?\n\nDe pagina blijft wel als concept beschikbaar.", "CMS.Unpublish": "Weet u zeker dat deze pagina verwijderd moet worden?\n\nDe pagina blijft wel als concept opgeslagen.",
"CMS.UpdateURL": "URL aanpassen", "CMS.UpdateURL": "URL aanpassen",
"CMS.ViewPage": "Bekijk" "CMS.ViewPage": "Bekijk"
}); });

View File

@ -1,17 +1,17 @@
{ {
"CMS.ALERTCLASSNAME": "Het paginatype wordt aangepast na het opslaan van de pagina", "CMS.ALERTCLASSNAME": "Het paginatype wordt aangepast na het opslaan van de pagina",
"CMS.AddSubPage": "Voeg nieuwe pagina toe", "CMS.AddSubPage": "Voeg nieuwe pagina toe",
"CMS.ConfirmRestoreFromLive": "Weet je zeker dat je terug wil naar de laatst gepubliceerde versie van deze pagina?", "CMS.ConfirmRestoreFromLive": "Weet u zeker dat u terug wil naar de laatst gepubliceerde versie van deze pagina?",
"CMS.Duplicate": "Dupliceren", "CMS.Duplicate": "Dupliceren",
"CMS.EditPage": "Aanpassen", "CMS.EditPage": "Aanpassen",
"CMS.ONLYSELECTTWO": "Er kunnen maar 2 pagina's tegelijk worden vergeleken.", "CMS.ONLYSELECTTWO": "Er kunnen maar 2 pagina's tegelijk worden vergeleken.",
"CMS.Restore": "Weet je zeker dat deze pagina hersteld moet worden?", "CMS.Restore": "Weet u zeker dat deze pagina hersteld moet worden?",
"CMS.RestoreToRoot": "Weet je zeker dat deze pagina hersteld moet worden?\n\nDe bovenliggende pagina bestaat niet meer, waardoor deze pagina op het hoofdniveau terecht komt.", "CMS.RestoreToRoot": "Weet u zeker dat deze pagina hersteld moet worden?\n\nDe bovenliggende pagina bestaat niet meer, waardoor deze pagina op het hoofdniveau terecht komt.",
"CMS.RollbackToVersion": "Wil je teruggaan naar versie #%s van deze pagina?", "CMS.RollbackToVersion": "Wilt u terugdraaien naar versie #%s van deze pagina?",
"CMS.ShowAsList": "Toon onderliggende pagina's als lijst", "CMS.ShowAsList": "Toon onderliggende pagina's als lijst",
"CMS.ThisPageAndSubpages": "Deze pagina en subpagina's", "CMS.ThisPageAndSubpages": "Deze pagina en subpagina's",
"CMS.ThisPageOnly": "Enkel deze pagina", "CMS.ThisPageOnly": "Enkel deze pagina",
"CMS.Unpublish": "Weet je zeker dat deze pagina verwijderd moet worden?\n\nDe pagina blijft wel als concept beschikbaar.", "CMS.Unpublish": "Weet u zeker dat deze pagina verwijderd moet worden?\n\nDe pagina blijft wel als concept opgeslagen.",
"CMS.UpdateURL": "URL aanpassen", "CMS.UpdateURL": "URL aanpassen",
"CMS.ViewPage": "Bekijk" "CMS.ViewPage": "Bekijk"
} }

View File

@ -1,17 +1,17 @@
{ {
"CMS.ALERTCLASSNAME": "Тип сторінки буде оновлено після збереження сторінки", "CMS.ALERTCLASSNAME": "The page type will be updated after the page is saved",
"CMS.AddSubPage": "Додати нову сторінку тут", "CMS.AddSubPage": "Add new page here",
"CMS.ConfirmRestoreFromLive": "Ви впевнені, що хочете повернути чернетку до часу останньої публікації сторінки?", "CMS.ConfirmRestoreFromLive": "Are you sure you want to revert draft to when the page was last published?",
"CMS.Duplicate": "Дублікат", "CMS.Duplicate": "Duplicate",
"CMS.EditPage": "Редагувати", "CMS.EditPage": "Edit",
"CMS.ONLYSELECTTWO": "Наразі можна порівняти лише дві версії.", "CMS.ONLYSELECTTWO": "You can only compare two versions at this time.",
"CMS.Restore": "Ви впевнені, що бажаєте відновити цю сторінку з архіву?", "CMS.Restore": "Are you sure you want to restore this page from archive?",
"CMS.RestoreToRoot": "Ви впевнені, що бажаєте відновити цю сторінку з архіву?\n\nОскільки батьківська сторінка недоступна, її буде відновлено до верхнього рівня.", "CMS.RestoreToRoot": "Are you sure you want to restore this page from archive?\n\nBecause the parent page is not available this will be restored to the top level.",
"CMS.RollbackToVersion": "Ви справді бажаєте повернутися до версії #%s цієї сторінки?", "CMS.RollbackToVersion": "Do you really want to roll back to version #%s of this page?",
"CMS.ShowAsList": "Показати дітей як список", "CMS.ShowAsList": "Show children as list",
"CMS.ThisPageAndSubpages": "Ця сторінка та підсторінки", "CMS.ThisPageAndSubpages": "This page and subpages",
"CMS.ThisPageOnly": "Тільки ця сторінка", "CMS.ThisPageOnly": "This page only",
"CMS.Unpublish": "Ви впевнені, що хочете видалити свою сторінку з опублікованого сайту?\n\nЦя сторінка все ще буде доступна в дереві сайту як чернетка.", "CMS.Unpublish": "Are you sure you want to remove your page from the published site?\n\nThis page will still be available in the sitetree as draft.",
"CMS.UpdateURL": "Оновити URL", "CMS.UpdateURL": "Update URL",
"CMS.ViewPage": "Переглянути" "CMS.ViewPage": "View"
} }

View File

@ -6,20 +6,20 @@ if (typeof(ss) === 'undefined' || typeof(ss.i18n) === 'undefined') {
} }
} else { } else {
ss.i18n.addDictionary('uk_UA', { ss.i18n.addDictionary('uk_UA', {
"CMS.ALERTCLASSNAME": "Тип сторінки буде оновлено після збереження сторінки", "CMS.ALERTCLASSNAME": "The page type will be updated after the page is saved",
"CMS.AddSubPage": "Додати нову сторінку тут", "CMS.AddSubPage": "Add new page here",
"CMS.ConfirmRestoreFromLive": "Ви впевнені, що хочете повернути чернетку до часу останньої публікації сторінки?", "CMS.ConfirmRestoreFromLive": "Are you sure you want to revert draft to when the page was last published?",
"CMS.Duplicate": "Дублікат", "CMS.Duplicate": "Duplicate",
"CMS.EditPage": "Редагувати", "CMS.EditPage": "Edit",
"CMS.ONLYSELECTTWO": "Наразі можна порівняти лише дві версії.", "CMS.ONLYSELECTTWO": "You can only compare two versions at this time.",
"CMS.Restore": "Ви впевнені, що бажаєте відновити цю сторінку з архіву?", "CMS.Restore": "Are you sure you want to restore this page from archive?",
"CMS.RestoreToRoot": "Ви впевнені, що бажаєте відновити цю сторінку з архіву?\n\nОскільки батьківська сторінка недоступна, її буде відновлено до верхнього рівня.", "CMS.RestoreToRoot": "Are you sure you want to restore this page from archive?\n\nBecause the parent page is not available this will be restored to the top level.",
"CMS.RollbackToVersion": "Ви справді бажаєте повернутися до версії #%s цієї сторінки?", "CMS.RollbackToVersion": "Do you really want to roll back to version #%s of this page?",
"CMS.ShowAsList": "Показати дітей як список", "CMS.ShowAsList": "Show children as list",
"CMS.ThisPageAndSubpages": "Ця сторінка та підсторінки", "CMS.ThisPageAndSubpages": "This page and subpages",
"CMS.ThisPageOnly": "Тільки ця сторінка", "CMS.ThisPageOnly": "This page only",
"CMS.Unpublish": "Ви впевнені, що хочете видалити свою сторінку з опублікованого сайту?\n\nЦя сторінка все ще буде доступна в дереві сайту як чернетка.", "CMS.Unpublish": "Are you sure you want to remove your page from the published site?\n\nThis page will still be available in the sitetree as draft.",
"CMS.UpdateURL": "Оновити URL", "CMS.UpdateURL": "Update URL",
"CMS.ViewPage": "Переглянути" "CMS.ViewPage": "View"
}); });
} }

View File

@ -2,7 +2,6 @@ require('../legacy/CMSMain.AddForm');
require('../legacy/CMSMain.EditForm'); require('../legacy/CMSMain.EditForm');
require('../legacy/CMSMain'); require('../legacy/CMSMain');
require('../legacy/CMSMain.Tree'); require('../legacy/CMSMain.Tree');
require('../legacy/CMSPageHistoryController');
require('../legacy/RedirectorPage'); require('../legacy/RedirectorPage');
require('../legacy/SiteTreeURLSegmentField'); require('../legacy/SiteTreeURLSegmentField');

View File

@ -8,7 +8,8 @@ import SilverStripeComponent from 'lib/SilverStripeComponent';
import * as anchorSelectorActions from 'state/anchorSelector/AnchorSelectorActions'; import * as anchorSelectorActions from 'state/anchorSelector/AnchorSelectorActions';
import anchorSelectorStates from 'state/anchorSelector/AnchorSelectorStates'; import anchorSelectorStates from 'state/anchorSelector/AnchorSelectorStates';
import fieldHolder from 'components/FieldHolder/FieldHolder'; import fieldHolder from 'components/FieldHolder/FieldHolder';
import { Creatable } from 'react-select'; import CreatableSelect from 'react-select/creatable';
import EmotionCssCacheProvider from 'containers/EmotionCssCacheProvider/EmotionCssCacheProvider';
import getFormState from 'lib/getFormState'; import getFormState from 'lib/getFormState';
import classnames from 'classnames'; import classnames from 'classnames';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
@ -117,26 +118,27 @@ class AnchorSelectorField extends SilverStripeComponent {
} }
render() { render() {
const inputProps = { const { extraClass, CreatableSelectComponent } = this.props;
id: this.props.id, const className = classnames('anchorselectorfield', extraClass);
};
const className = classnames('anchorselectorfield', this.props.extraClass);
const options = this.getDropdownOptions(); const options = this.getDropdownOptions();
const value = this.props.value || ''; const rawValue = this.props.value || '';
const placeholder = i18n._t('CMS.ANCHOR_SELECT_OR_TYPE', 'Select or enter anchor'); const placeholder = i18n._t('CMS.ANCHOR_SELECT_OR_TYPE', 'Select or enter anchor');
return ( return (
<Creatable <EmotionCssCacheProvider>
searchable <CreatableSelectComponent
isSearchable
isClearable
options={options} options={options}
className={className} className={className}
name={this.props.name} name={this.props.name}
inputProps={inputProps}
onChange={this.handleChange} onChange={this.handleChange}
onBlurResetsInput value={{ value: rawValue }}
value={value} noOptionsMessage={() => i18n._t('CMS.ANCHOR_NO_OPTIONS', 'No options')}
placeholder={placeholder} placeholder={placeholder}
labelKey="value" getOptionLabel={({ value }) => value}
classNamePrefix="anchorselectorfield"
/> />
</EmotionCssCacheProvider>
); );
} }
} }
@ -165,6 +167,7 @@ AnchorSelectorField.defaultProps = {
extraClass: '', extraClass: '',
onLoadingError: noop, onLoadingError: noop,
attributes: {}, attributes: {},
CreatableSelectComponent: CreatableSelect
}; };
function mapStateToProps(state, ownProps) { function mapStateToProps(state, ownProps) {

View File

@ -0,0 +1,3 @@
.anchorselectorfield__menu {
z-index: 20000;
}

View File

@ -1,4 +1,9 @@
/* global jest, describe, beforeEach, it, expect, setTimeout */ /* global jest, test, describe, beforeEach, it, expect, setTimeout */
import React from 'react';
import anchorSelectorStates from 'state/anchorSelector/AnchorSelectorStates';
import { render, screen } from '@testing-library/react';
import { Component as AnchorSelectorField } from '../AnchorSelectorField';
jest.mock('isomorphic-fetch', () => jest.mock('isomorphic-fetch', () =>
() => Promise.resolve({ () => Promise.resolve({
@ -6,17 +11,8 @@ jest.mock('isomorphic-fetch', () =>
})); }));
jest.mock('i18n'); jest.mock('i18n');
import React from 'react'; function makeProps(obj = {}) {
import ReactTestUtils from 'react-dom/test-utils'; return {
import { Component as AnchorSelectorField } from '../AnchorSelectorField';
import anchorSelectorStates from 'state/anchorSelector/AnchorSelectorStates';
describe('AnchorSelectorField', () => {
let props = null;
let field = null;
beforeEach(() => {
props = {
id: 'Form_Test', id: 'Form_Test',
name: 'Test', name: 'Test',
data: { data: {
@ -26,78 +22,108 @@ describe('AnchorSelectorField', () => {
anchors: ['anchor1', 'anchor2'], anchors: ['anchor1', 'anchor2'],
value: 'selectedanchor', value: 'selectedanchor',
loadingState: anchorSelectorStates.SUCCESS, loadingState: anchorSelectorStates.SUCCESS,
CreatableSelectComponent: ({ options }) => (
<div data-testid="test-creatable-select">
{options.map(option => <div key={option.value} data-option={option.value}/>)}
</div>
),
...obj,
};
}
test('AnchorSelectorField componentDidMount() Loads dirty selectors', async () => {
const beginUpdating = jest.fn();
render(<AnchorSelectorField {...makeProps({
loadingState: anchorSelectorStates.DIRTY,
actions: { actions: {
anchorSelector: { anchorSelector: {
beginUpdating: jest.fn(), beginUpdating,
updated: jest.fn(), updated: () => {},
updateFailed: jest.fn(), updateFailed: () => {},
}, },
}, },
}; })}
/>);
await screen.findByTestId('test-creatable-select');
expect(beginUpdating).toBeCalledWith(4);
}); });
describe('componentDidMount()', () => { test('AnchorSelectorField Merges value with page anchors', async () => {
it('Loads dirty selectors', () => { const beginUpdating = jest.fn();
props.loadingState = anchorSelectorStates.DIRTY; render(<AnchorSelectorField {...makeProps({
field = ReactTestUtils.renderIntoDocument(<AnchorSelectorField {...props} />); loadingState: anchorSelectorStates.DIRTY,
expect(props.actions.anchorSelector.beginUpdating) actions: {
.toHaveBeenCalledWith(4); anchorSelector: {
}); beginUpdating,
it('Does not load success selectors', () => { updated: () => {},
props.loadingState = anchorSelectorStates.SUCCESS; updateFailed: () => {},
field = ReactTestUtils.renderIntoDocument(<AnchorSelectorField {...props} />); },
expect(props.actions.anchorSelector.beginUpdating) },
.not })}
.toHaveBeenCalled(); />);
}); const select = await screen.findByTestId('test-creatable-select');
const options = select.querySelectorAll('[data-option]');
expect(options).toHaveLength(3);
expect(options[0].getAttribute('data-option')).toBe('selectedanchor');
expect(options[1].getAttribute('data-option')).toBe('anchor1');
expect(options[2].getAttribute('data-option')).toBe('anchor2');
}); });
describe('getDropdownOptions()', () => { test('AnchorSelectorField componentDidMount() Does not load success selectors', async () => {
it('Merges value with page anchors', () => { const beginUpdating = jest.fn();
field = ReactTestUtils.renderIntoDocument(<AnchorSelectorField {...props} />); render(<AnchorSelectorField {...makeProps({
expect(field.getDropdownOptions()).toEqual([ loadingState: anchorSelectorStates.SUCCESS,
{ value: 'selectedanchor' }, actions: {
{ value: 'anchor1' }, anchorSelector: {
{ value: 'anchor2' }, beginUpdating,
]); updated: () => {},
}); updateFailed: () => {},
},
},
})}
/>);
await screen.findByTestId('test-creatable-select');
expect(beginUpdating).not.toBeCalled();
}); });
describe('ensurePagesLoaded', () => { test('AnchorSelectorField ensurePagesLoaded Triggers loading on dirty', async () => {
it('Triggers loading on dirty', () => { const beginUpdating = jest.fn();
props.loadingState = anchorSelectorStates.DIRTY; const updated = jest.fn();
field = ReactTestUtils.renderIntoDocument(<AnchorSelectorField {...props} />); const updateFailed = jest.fn();
return field render(<AnchorSelectorField {...makeProps({
.ensurePagesLoaded() loadingState: anchorSelectorStates.DIRTY,
.then((result) => { actions: {
expect(props.actions.anchorSelector.beginUpdating) anchorSelector: {
.toHaveBeenCalledWith(4); beginUpdating,
expect(props.actions.anchorSelector.updated) updated,
.toHaveBeenCalledWith(4, ['anchor3', 'anchor4']); updateFailed,
expect(props.actions.anchorSelector.updateFailed) },
.not },
.toHaveBeenCalled(); })}
expect(result).toEqual(['anchor3', 'anchor4']); />);
}); await screen.findByTestId('test-creatable-select');
expect(beginUpdating).toBeCalledWith(4);
expect(updated).toBeCalledWith(4, ['anchor3', 'anchor4']);
expect(updateFailed).not.toBeCalled();
}); });
it('Does not trigger updating', () => { test('AnchorSelectorField ensurePagesLoaded Does not trigger updating', async () => {
props.loadingState = anchorSelectorStates.UPDATING; const beginUpdating = jest.fn();
field = ReactTestUtils.renderIntoDocument(<AnchorSelectorField {...props} />); const updated = jest.fn();
return field const updateFailed = jest.fn();
.ensurePagesLoaded() render(<AnchorSelectorField {...makeProps({
.then((result) => { loadingState: anchorSelectorStates.UPDATING,
expect(props.actions.anchorSelector.beginUpdating) actions: {
.not anchorSelector: {
.toHaveBeenCalled(); beginUpdating,
expect(props.actions.anchorSelector.updated) updated,
.not updateFailed,
.toHaveBeenCalled(); },
expect(props.actions.anchorSelector.updateFailed) },
.not })}
.toHaveBeenCalled(); />);
expect(result).toBe(undefined); await screen.findByTestId('test-creatable-select');
}); expect(beginUpdating).not.toBeCalled();
}); expect(updated).not.toBeCalled();
}); expect(updateFailed).not.toBeCalled();
}); });

View File

@ -3,7 +3,7 @@
*/ */
import $ from 'jquery'; import $ from 'jquery';
import i18n from 'i18n'; import i18n from 'i18n';
import reactConfirm from "@silverstripe/reactstrap-confirm"; import reactConfirm from 'reactstrap-confirm';
$.entwine('ss', function($){ $.entwine('ss', function($){
/** /**
@ -497,12 +497,13 @@ $.entwine('ss', function($){
'By changing the URL segment visitors will not be able to view it.' 'By changing the URL segment visitors will not be able to view it.'
); );
if (await reactConfirm(message, { if (await reactConfirm({
title: i18n._t( title: i18n._t(
'CMS.RemoveHomePageWarningTitle', 'CMS.RemoveHomePageWarningTitle',
'Remove your home page?' 'Remove your home page?'
), ),
confirmLabel: i18n._t( message,
confirmText: i18n._t(
'CMS.RemoveHomePageWarningLabel', 'CMS.RemoveHomePageWarningLabel',
'Remove' 'Remove'
), ),

View File

@ -1,6 +1,7 @@
import $ from 'jquery'; import $ from 'jquery';
import i18n from 'i18n'; import i18n from 'i18n';
import reactConfirm from "@silverstripe/reactstrap-confirm"; import reactConfirm from 'reactstrap-confirm';
import { joinUrlPaths } from 'lib/urls';
$.entwine('ss.tree', function($) { $.entwine('ss.tree', function($) {
$('.cms-tree').entwine({ $('.cms-tree').entwine({
@ -45,7 +46,7 @@ $.entwine('ss.tree', function($) {
}); });
const baseUrl = $('base').attr('href') || ''; // Edge17 and IE11 require absolute paths const baseUrl = $('base').attr('href') || ''; // Edge17 and IE11 require absolute paths
window.location.assign(baseUrl + urlWithParams); window.location.assign(joinUrlPaths(baseUrl, urlWithParams));
}, },
getTreeConfig: function() { getTreeConfig: function() {
@ -168,12 +169,13 @@ $.entwine('ss.tree', function($) {
'By changing the URL segment visitors will not be able to view it.' 'By changing the URL segment visitors will not be able to view it.'
); );
return await reactConfirm(message, { return await reactConfirm({
title: i18n._t( title: i18n._t(
'CMS.RemoveHomePageWarningTitle', 'CMS.RemoveHomePageWarningTitle',
'Remove your home page?' 'Remove your home page?'
), ),
confirmLabel: i18n._t( message,
confirmText: i18n._t(
'CMS.RemoveHomePageWarningLabel', 'CMS.RemoveHomePageWarningLabel',
'Remove' 'Remove'
), ),

View File

@ -1,4 +1,5 @@
import $ from 'jquery'; import $ from 'jquery';
import { joinUrlPaths } from 'lib/urls';
/** /**
* Behaviour for the CMS Content Toolbar. * Behaviour for the CMS Content Toolbar.
@ -81,7 +82,7 @@ $.entwine('ss', function ($) {
localStorage.setItem('ss.pages-view-type', viewType); localStorage.setItem('ss.pages-view-type', viewType);
if(isContentViewInSidebar && viewType === VIEW_TYPE_LIST) { if(isContentViewInSidebar && viewType === VIEW_TYPE_LIST) {
const baseUrl = $('base').attr('href') || ''; // Edge17 and IE11 need absolute path const baseUrl = $('base').attr('href') || ''; // Edge17 and IE11 need absolute path
window.location.assign(baseUrl + $contentView.data('url-listviewroot')); window.location.assign(joinUrlPaths(baseUrl, $contentView.data('url-listviewroot')));
return; return;
} }

View File

@ -1,183 +0,0 @@
import $ from 'jquery';
import i18n from 'i18n';
/**
* File: CMSPageHistoryController.js
*
* Handles related interactions between the version selection form on the
* left hand side of the panel and the version displaying on the right
* hand side.
*/
$.entwine('ss', ($) => { // eslint-disable-line no-shadow
/**
* Class: #Form_VersionsForm
*
* The left hand side version selection form is the main interface for
* users to select a version to view, or to compare two versions
*/
$('#Form_VersionsForm').entwine({
/**
* Constructor
*/
onmatch() {
this._super();
},
onunmatch() {
this._super();
},
/**
* Function: submit.
*
* Submits either the compare versions form or the view single form
* display based on whether we have two or 1 option selected
*
* Todo:
* Handle coupling to admin url
*/
onsubmit(e) {
e.preventDefault();
const id = this.find(':input[name=ID]').val();
if (!id) {
return false;
}
let url = null;
let to = null;
let from = null;
const compare = (this.find(':input[name=CompareMode]').is(':checked'));
const selected = this.find('table input[type=checkbox]').filter(':checked');
if (compare) {
if (selected.length !== 2) {
return false;
}
to = selected.eq(0).val();
from = selected.eq(1).val();
url = i18n.sprintf(this.data('linkTmplCompare'), id, from, to);
} else {
to = selected.eq(0).val();
url = i18n.sprintf(this.data('linkTmplShow'), id, to);
}
$('.cms-container').loadPanel(url, '', { pjax: 'CurrentForm' });
return true;
},
});
/**
* Class: :input[name=ShowUnpublished]
*
* Used for toggling whether to show or hide unpublished versions.
*/
$('#Form_VersionsForm input[name=ShowUnpublished]').entwine({
onmatch() {
this.toggle();
this._super();
},
onunmatch() {
this._super();
},
/**
* Event: :input[name=ShowUnpublished] change
*
* Changing the show unpublished checkbox toggles whether to show
* or hide the unpublished versions. Because those rows may be being
* compared this also ensures those rows are unselected.
*/
onchange() {
this.toggle();
},
toggle() {
const self = $(this);
const unpublished = self.parents('form').find('tr[data-published=false]');
if (self.attr('checked')) {
unpublished
.removeClass('ui-helper-hidden')
.show();
} else {
unpublished
.addClass('ui-helper-hidden')
.hide()
._unselect();
}
},
});
/**
* Class: #Form_VersionsForm tr
*
* An individual row in the versions form. Selecting the row updates
* the edit form depending on whether we're showing individual version
* information or displaying comparsion.
*/
$('#Form_VersionsForm tbody tr').entwine({
/**
* Function: onclick
*
* Selects or deselects the row (if in compare mode). Will trigger
* an update of the edit form if either selected (in single mode)
* or if this is the second row selected (in compare mode)
*/
onclick() {
// compare mode
const compare = this.parents('form').find(':input[name=CompareMode]').attr('checked');
const selected = this.siblings('.active');
if (compare && this.hasClass('active')) {
this._unselect();
return;
}
if (compare) {
// check if we have already selected more than two.
if (selected.length > 1) {
// eslint-disable-next-line no-alert
alert(i18n._t('CMS.ONLYSELECTTWO', 'You can only compare two versions at this time.'));
return;
}
this._select();
// if this is the second selected then we can compare.
if (selected.length === 1) {
this.parents('form').submit();
}
return;
}
this._select();
selected._unselect();
this.parents('form').submit();
},
/**
* Function: _unselect()
*
* Unselects the row from the form selection.
*
* Using regular js to update the class rather than this.removeClass('active')
* because the latter causes the browser to continuously call
* element.compareDocumentPosition, causing the browser to hang for long
* periods of time, especially on pages with lots of versions (e.g. 100+)
*/
_unselect() {
this.get(0).classList.remove('active');
this.find(':input[type=checkbox][checked]').attr('checked', false);
},
/**
* Function: _select()
*
* Selects the currently matched row in the form selection
*/
_select() {
this.addClass('active');
this.find(':input[type=checkbox]').attr('checked', true);
},
});
});

View File

@ -1,9 +1,9 @@
/* global tinymce, ss */ /* global tinymce, editorIdentifier, ss */
import i18n from 'i18n'; import i18n from 'i18n';
import TinyMCEActionRegistrar from 'lib/TinyMCEActionRegistrar'; import TinyMCEActionRegistrar from 'lib/TinyMCEActionRegistrar';
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import { createRoot } from 'react-dom/client';
import { ApolloProvider } from 'react-apollo'; import { ApolloProvider } from '@apollo/client';
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
import jQuery from 'jquery'; import jQuery from 'jquery';
import ShortcodeSerialiser from 'lib/ShortcodeSerialiser'; import ShortcodeSerialiser from 'lib/ShortcodeSerialiser';
@ -13,28 +13,27 @@ import { updatedCurrentField } from '../state/anchorSelector/AnchorSelectorActio
const commandName = 'sslinkanchor'; const commandName = 'sslinkanchor';
const plugin = { // Link to external url
init(editor) {
// Add "Anchor on a page" to link menu for this editor
TinyMCEActionRegistrar TinyMCEActionRegistrar
.addAction( .addAction(
'sslink', 'sslink',
{ {
text: i18n._t('CMS.LINKLABEL_ANCHOR', 'Anchor on a page'), text: i18n._t('CMS.LINKLABEL_ANCHOR', 'Anchor on a page'),
onclick: (activeEditor) => activeEditor.execCommand(commandName), onAction: (activeEditor) => activeEditor.execCommand(commandName),
priority: 60, priority: 60,
}, },
editor.settings.editorIdentifier, editorIdentifier,
) )
.addCommandWithUrlTest(commandName, /^\[sitetree_link.+]#[^#\]]+$/); .addCommandWithUrlTest(commandName, /^\[sitetree_link.+]#[^#\]]+$/);
// Add a command that corresponds with the above menu item const plugin = {
init(editor) {
editor.addCommand(commandName, () => { editor.addCommand(commandName, () => {
const field = jQuery(`#${editor.id}`).entwine('ss'); const field = jQuery(`#${editor.id}`).entwine('ss');
// Get the anchors in the current field and save them as props for AnchorSelectorField // Get the anchors in the current field and save them as props for AnchorSelectorField
const currentPageID = Number(jQuery('#Form_EditForm_ID').val() || 0); const currentPageID = Number(jQuery('#Form_EditForm_ID').val() || 0);
const validTargets = editor const validTargets = jQuery(editor.getBody())
.$('[id],[name]', editor.getBody()) .find('[id],[name]')
.toArray() .toArray()
.map((element) => element.id || element.name); .map((element) => element.id || element.name);
ss.store.dispatch(updatedCurrentField(currentPageID, validTargets, editor.id)); ss.store.dispatch(updatedCurrentField(currentPageID, validTargets, editor.id));
@ -69,6 +68,8 @@ jQuery.entwine('ss', ($) => {
* Assumes that $('.insert-link__dialog-wrapper').entwine({}); is defined for shared functions * Assumes that $('.insert-link__dialog-wrapper').entwine({}); is defined for shared functions
*/ */
$(`#${modalId}`).entwine({ $(`#${modalId}`).entwine({
ReactRoot: null,
renderModal(isOpen) { renderModal(isOpen) {
const store = ss.store; const store = ss.store;
const client = ss.apolloClient; const client = ss.apolloClient;
@ -79,7 +80,12 @@ jQuery.entwine('ss', ($) => {
const currentPageID = Number($('#Form_EditForm_ID').val() || 0); const currentPageID = Number($('#Form_EditForm_ID').val() || 0);
// create/update the react component // create/update the react component
ReactDOM.render( let root = this.getReactRoot();
if (!root) {
root = createRoot(this[0]);
this.setReactRoot(root);
}
root.render(
<ApolloProvider client={client}> <ApolloProvider client={client}>
<Provider store={store}> <Provider store={store}>
<InsertLinkInternalModal <InsertLinkInternalModal
@ -95,8 +101,7 @@ jQuery.entwine('ss', ($) => {
currentPageID={currentPageID} currentPageID={currentPageID}
/> />
</Provider> </Provider>
</ApolloProvider>, </ApolloProvider>
this[0]
); );
}, },

View File

@ -1,9 +1,9 @@
/* global tinymce, ss */ /* global tinymce, editorIdentifier, ss */
import i18n from 'i18n'; import i18n from 'i18n';
import TinyMCEActionRegistrar from 'lib/TinyMCEActionRegistrar'; import TinyMCEActionRegistrar from 'lib/TinyMCEActionRegistrar';
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import { createRoot } from 'react-dom/client';
import { ApolloProvider } from 'react-apollo'; import { ApolloProvider } from '@apollo/client';
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
import jQuery from 'jquery'; import jQuery from 'jquery';
import ShortcodeSerialiser from 'lib/ShortcodeSerialiser'; import ShortcodeSerialiser from 'lib/ShortcodeSerialiser';
@ -12,22 +12,21 @@ import { provideInjector } from 'lib/Injector';
const commandName = 'sslinkinternal'; const commandName = 'sslinkinternal';
const plugin = { // Link to external url
init(editor) {
// Add "Page on this site" to link menu for this editor
TinyMCEActionRegistrar TinyMCEActionRegistrar
.addAction( .addAction(
'sslink', 'sslink',
{ {
text: i18n._t('CMS.LINKLABEL_PAGE', 'Page on this site'), text: i18n._t('CMS.LINKLABEL_PAGE', 'Page on this site'),
onclick: (activeEditor) => activeEditor.execCommand(commandName), onAction: (activeEditor) => activeEditor.execCommand(commandName),
priority: 90, priority: 90,
}, },
editor.settings.editorIdentifier, editorIdentifier,
) )
.addCommandWithUrlTest(commandName, /^\[sitetree_link.+]$/); .addCommandWithUrlTest(commandName, /^\[sitetree_link.+]$/);
// Add a command that corresponds with the above menu item const plugin = {
init(editor) {
editor.addCommand(commandName, () => { editor.addCommand(commandName, () => {
const field = jQuery(`#${editor.id}`).entwine('ss'); const field = jQuery(`#${editor.id}`).entwine('ss');
@ -61,6 +60,8 @@ jQuery.entwine('ss', ($) => {
* Assumes that $('.insert-link__dialog-wrapper').entwine({}); is defined for shared functions * Assumes that $('.insert-link__dialog-wrapper').entwine({}); is defined for shared functions
*/ */
$(`#${modalId}`).entwine({ $(`#${modalId}`).entwine({
ReactRoot: null,
renderModal(isOpen) { renderModal(isOpen) {
const store = ss.store; const store = ss.store;
const client = ss.apolloClient; const client = ss.apolloClient;
@ -70,7 +71,12 @@ jQuery.entwine('ss', ($) => {
const requireLinkText = this.getRequireLinkText(); const requireLinkText = this.getRequireLinkText();
// create/update the react component // create/update the react component
ReactDOM.render( let root = this.getReactRoot();
if (!root) {
root = createRoot(this[0]);
this.setReactRoot(root);
}
root.render(
<ApolloProvider client={client}> <ApolloProvider client={client}>
<Provider store={store}> <Provider store={store}>
<InsertLinkInternalModal <InsertLinkInternalModal
@ -85,8 +91,7 @@ jQuery.entwine('ss', ($) => {
requireLinkText={requireLinkText} requireLinkText={requireLinkText}
/> />
</Provider> </Provider>
</ApolloProvider>, </ApolloProvider>
this[0]
); );
}, },

View File

@ -1,4 +1,4 @@
import { graphql } from 'react-apollo'; import { graphql } from '@apollo/client/react/hoc';
import gql from 'graphql-tag'; import gql from 'graphql-tag';
// GraphQL query for retrieving the version history of a specific page. The // GraphQL query for retrieving the version history of a specific page. The

View File

@ -1,4 +1,4 @@
import { graphql } from 'react-apollo'; import { graphql } from '@apollo/client/react/hoc';
import gql from 'graphql-tag'; import gql from 'graphql-tag';
const mutation = gql` const mutation = gql`

View File

@ -1,4 +1,4 @@
import { graphql } from 'react-apollo'; import { graphql } from '@apollo/client/react/hoc';
import gql from 'graphql-tag'; import gql from 'graphql-tag';
const mutation = gql` const mutation = gql`

View File

@ -7,3 +7,5 @@
@import "legacy/CMSMain"; @import "legacy/CMSMain";
@import "legacy/ReportAdmin"; @import "legacy/ReportAdmin";
@import "../components/AnchorSelectorField/AnchorSelectorField";

View File

@ -30,31 +30,6 @@
} }
} }
.CMSPageHistoryController {
overflow: hidden; // Fixes weird bug for double scroll in history area on browser resize
ins {
background-color: #DFD;
padding: 2px;
text-decoration: none;
}
del {
background-color: #FDD;
padding: 2px;
color: darken(#FDD, 30%);
}
.htmleditorfield.readonly img {
max-width: 100%;
height: auto;
}
.cms-content-tools.collapsed {
overflow: hidden;
}
}
/** -------------------------------------------- /** --------------------------------------------
* Tree View (collapsed for sidebar) * Tree View (collapsed for sidebar)
* -------------------------------------------- */ * -------------------------------------------- */

View File

@ -4,6 +4,7 @@ namespace SilverStripe\CMS\BatchActions;
use SilverStripe\ORM\SS_List; use SilverStripe\ORM\SS_List;
use SilverStripe\Admin\CMSBatchAction; use SilverStripe\Admin\CMSBatchAction;
use SilverStripe\Control\HTTPResponse;
/** /**
* Delete items batch action. * Delete items batch action.
@ -15,7 +16,7 @@ class CMSBatchAction_Archive extends CMSBatchAction
return _t(__CLASS__ . '.TITLE', 'Unpublish and archive'); return _t(__CLASS__ . '.TITLE', 'Unpublish and archive');
} }
public function run(SS_List $pages) public function run(SS_List $pages): HTTPResponse
{ {
return $this->batchaction( return $this->batchaction(
$pages, $pages,

View File

@ -3,6 +3,7 @@
namespace SilverStripe\CMS\BatchActions; namespace SilverStripe\CMS\BatchActions;
use SilverStripe\Admin\CMSBatchAction; use SilverStripe\Admin\CMSBatchAction;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\ORM\SS_List; use SilverStripe\ORM\SS_List;
/** /**
@ -15,7 +16,7 @@ class CMSBatchAction_Publish extends CMSBatchAction
return _t(__CLASS__ . '.PUBLISH_PAGES', 'Publish'); return _t(__CLASS__ . '.PUBLISH_PAGES', 'Publish');
} }
public function run(SS_List $pages) public function run(SS_List $pages): HTTPResponse
{ {
return $this->batchaction( return $this->batchaction(
$pages, $pages,

View File

@ -4,6 +4,7 @@ namespace SilverStripe\CMS\BatchActions;
use SilverStripe\Admin\CMSBatchAction; use SilverStripe\Admin\CMSBatchAction;
use SilverStripe\CMS\Model\SiteTree; use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\ORM\ArrayList; use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\SS_List; use SilverStripe\ORM\SS_List;
use SilverStripe\Versioned\Versioned; use SilverStripe\Versioned\Versioned;
@ -20,7 +21,7 @@ class CMSBatchAction_Restore extends CMSBatchAction
return _t(__CLASS__ . '.RESTORE', 'Restore'); return _t(__CLASS__ . '.RESTORE', 'Restore');
} }
public function run(SS_List $pages) public function run(SS_List $pages): HTTPResponse
{ {
// Sort pages by depth // Sort pages by depth
$pageArray = $pages->toArray(); $pageArray = $pages->toArray();

View File

@ -3,6 +3,7 @@
namespace SilverStripe\CMS\BatchActions; namespace SilverStripe\CMS\BatchActions;
use SilverStripe\Admin\CMSBatchAction; use SilverStripe\Admin\CMSBatchAction;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\ORM\SS_List; use SilverStripe\ORM\SS_List;
/** /**
@ -15,7 +16,7 @@ class CMSBatchAction_Unpublish extends CMSBatchAction
return _t(__CLASS__ . '.UNPUBLISH_PAGES', 'Unpublish'); return _t(__CLASS__ . '.UNPUBLISH_PAGES', 'Unpublish');
} }
public function run(SS_List $pages) public function run(SS_List $pages): HTTPResponse
{ {
return $this->batchaction( return $this->batchaction(
$pages, $pages,

View File

@ -2,13 +2,13 @@
namespace SilverStripe\CMS\Controllers; namespace SilverStripe\CMS\Controllers;
use SilverStripe\Dev\Deprecation;
use InvalidArgumentException; use InvalidArgumentException;
use Psr\SimpleCache\CacheInterface; use Psr\SimpleCache\CacheInterface;
use SilverStripe\Admin\AdminRootController; use SilverStripe\Admin\AdminRootController;
use SilverStripe\Admin\CMSBatchActionHandler; use SilverStripe\Admin\CMSBatchActionHandler;
use SilverStripe\Admin\LeftAndMain; use SilverStripe\Admin\LeftAndMain;
use SilverStripe\Admin\LeftAndMainFormRequestHandler; use SilverStripe\Admin\LeftAndMainFormRequestHandler;
use SilverStripe\Admin\Navigator\SilverStripeNavigator;
use SilverStripe\CMS\BatchActions\CMSBatchAction_Archive; use SilverStripe\CMS\BatchActions\CMSBatchAction_Archive;
use SilverStripe\CMS\BatchActions\CMSBatchAction_Publish; use SilverStripe\CMS\BatchActions\CMSBatchAction_Publish;
use SilverStripe\CMS\BatchActions\CMSBatchAction_Restore; use SilverStripe\CMS\BatchActions\CMSBatchAction_Restore;
@ -23,6 +23,7 @@ use SilverStripe\Control\Director;
use SilverStripe\Control\HTTPRequest; use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse; use SilverStripe\Control\HTTPResponse;
use SilverStripe\Control\HTTPResponse_Exception; use SilverStripe\Control\HTTPResponse_Exception;
use SilverStripe\Control\PjaxResponseNegotiator;
use SilverStripe\Core\Cache\MemberCacheFlusher; use SilverStripe\Core\Cache\MemberCacheFlusher;
use SilverStripe\Core\Config\Config; use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Convert; use SilverStripe\Core\Convert;
@ -69,10 +70,9 @@ use SilverStripe\SiteConfig\SiteConfig;
use SilverStripe\Versioned\ChangeSet; use SilverStripe\Versioned\ChangeSet;
use SilverStripe\Versioned\ChangeSetItem; use SilverStripe\Versioned\ChangeSetItem;
use SilverStripe\Versioned\Versioned; use SilverStripe\Versioned\Versioned;
use SilverStripe\VersionedAdmin\Controllers\CMSPageHistoryViewerController;
use SilverStripe\View\ArrayData; use SilverStripe\View\ArrayData;
use SilverStripe\View\Requirements; use SilverStripe\View\Requirements;
use Translatable;
use SilverStripe\VersionedAdmin\Controllers\CMSPageHistoryViewerController;
/** /**
* The main "content" area of the CMS. * The main "content" area of the CMS.
@ -80,8 +80,6 @@ use SilverStripe\VersionedAdmin\Controllers\CMSPageHistoryViewerController;
* This class creates a 2-frame layout - left-tree and right-form - to sit beneath the main * This class creates a 2-frame layout - left-tree and right-form - to sit beneath the main
* admin menu. * admin menu.
* *
* @todo Create some base classes to contain the generic functionality that will be replicated.
*
* @mixin LeftAndMainPageIconsExtension * @mixin LeftAndMainPageIconsExtension
*/ */
class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionProvider, Flushable, MemberCacheFlusher class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionProvider, Flushable, MemberCacheFlusher
@ -107,12 +105,6 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
private static $tree_class = SiteTree::class; private static $tree_class = SiteTree::class;
/**
* @deprecated 1.13.0 Do not use this options.
* @config
*/
private static $subitem_class = Member::class;
private static $session_namespace = self::class; private static $session_namespace = self::class;
private static $required_permission_codes = 'CMS_ACCESS_CMSMain'; private static $required_permission_codes = 'CMS_ACCESS_CMSMain';
@ -188,19 +180,13 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
protected function init() protected function init()
{ {
// set reading lang
if (SiteTree::has_extension('Translatable') && !$this->getRequest()->isAjax()) {
Translatable::choose_site_locale(array_keys(Translatable::get_existing_content_languages(SiteTree::class) ?? []));
}
parent::init(); parent::init();
Requirements::javascript('silverstripe/cms: client/dist/js/bundle.js'); Requirements::javascript('silverstripe/cms: client/dist/js/bundle.js');
Requirements::javascript('silverstripe/cms: client/dist/js/SilverStripeNavigator.js'); Requirements::javascript('silverstripe/cms: client/dist/js/SilverStripeNavigator.js');
Requirements::css('silverstripe/cms: client/dist/styles/bundle.css'); Requirements::css('silverstripe/cms: client/dist/styles/bundle.css');
Requirements::customCSS($this->generatePageIconsCss(), self::PAGE_ICONS_ID);
Requirements::add_i18n_javascript('silverstripe/cms: client/lang', false, true); Requirements::add_i18n_javascript('silverstripe/cms: client/lang', false);
CMSBatchActionHandler::register('restore', CMSBatchAction_Restore::class); CMSBatchActionHandler::register('restore', CMSBatchAction_Restore::class);
CMSBatchActionHandler::register('archive', CMSBatchAction_Archive::class); CMSBatchActionHandler::register('archive', CMSBatchAction_Archive::class);
@ -208,7 +194,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
CMSBatchActionHandler::register('publish', CMSBatchAction_Publish::class); CMSBatchActionHandler::register('publish', CMSBatchAction_Publish::class);
} }
public function index($request) public function index(HTTPRequest $request): HTTPResponse
{ {
// In case we're not showing a specific record, explicitly remove any session state, // In case we're not showing a specific record, explicitly remove any session state,
// to avoid it being highlighted in the tree, and causing an edit form to show. // to avoid it being highlighted in the tree, and causing an edit form to show.
@ -219,7 +205,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
return parent::index($request); return parent::index($request);
} }
public function getResponseNegotiator() public function getResponseNegotiator(): PjaxResponseNegotiator
{ {
$negotiator = parent::getResponseNegotiator(); $negotiator = parent::getResponseNegotiator();
@ -414,10 +400,13 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
public function LinkPageHistory() public function LinkPageHistory()
{ {
if ($id = $this->currentPageID()) { $controller = Injector::inst()->get(CMSPageHistoryViewerController::class);
if (($id = $this->currentPageID()) && $controller) {
if ($controller) {
return $this->LinkWithSearch( return $this->LinkWithSearch(
Controller::join_links(CMSPageHistoryViewerController::singleton()->Link('show'), $id) Controller::join_links($controller->Link('show'), $id)
); );
}
} else { } else {
return null; return null;
} }
@ -664,11 +653,8 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
/** /**
* Get a subtree underneath the request param 'ID'. * Get a subtree underneath the request param 'ID'.
* If ID = 0, then get the whole tree. * If ID = 0, then get the whole tree.
*
* @param HTTPRequest $request
* @return string
*/ */
public function getsubtree($request) public function getsubtree(HTTPRequest $request): HTTPResponse
{ {
$html = $this->getSiteTreeFor( $html = $this->getSiteTreeFor(
$this->config()->get('tree_class'), $this->config()->get('tree_class'),
@ -683,7 +669,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
$html = preg_replace('/^[\s\t\r\n]*<ul[^>]*>/', '', $html ?? ''); $html = preg_replace('/^[\s\t\r\n]*<ul[^>]*>/', '', $html ?? '');
$html = preg_replace('/<\/ul[^>]*>[\s\t\r\n]*$/', '', $html ?? ''); $html = preg_replace('/<\/ul[^>]*>[\s\t\r\n]*$/', '', $html ?? '');
return $html; return $this->getResponse()->setBody($html);
} }
/** /**
@ -691,11 +677,8 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
* Similar to {@link getsubtree()}, but doesn't enforce loading * Similar to {@link getsubtree()}, but doesn't enforce loading
* all children with the node. Useful to refresh views after * all children with the node. Useful to refresh views after
* state modifications, e.g. saving a form. * state modifications, e.g. saving a form.
*
* @param HTTPRequest $request
* @return HTTPResponse
*/ */
public function updatetreenodes($request) public function updatetreenodes(HTTPRequest $request): HTTPResponse
{ {
$data = []; $data = [];
$ids = explode(',', $request->getVar('ids') ?? ''); $ids = explode(',', $request->getVar('ids') ?? '');
@ -717,7 +700,6 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
$markingSet->markUnexpanded($record); $markingSet->markUnexpanded($record);
// Find the next & previous nodes, for proper positioning (Sort isn't good enough - it's not a raw offset) // Find the next & previous nodes, for proper positioning (Sort isn't good enough - it's not a raw offset)
// TODO: These methods should really be in hierarchy - for a start it assumes Sort exists
$prev = null; $prev = null;
$className = $this->config()->get('tree_class'); $className = $this->config()->get('tree_class');
@ -763,17 +745,15 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
* - 'SiblingIDs': Array of all sibling nodes to the moved node (incl. the node itself). * - 'SiblingIDs': Array of all sibling nodes to the moved node (incl. the node itself).
* In case of a 'ParentID' change, relates to the new siblings under the new parent. * In case of a 'ParentID' change, relates to the new siblings under the new parent.
* *
* @param HTTPRequest $request
* @return HTTPResponse JSON string with a
* @throws HTTPResponse_Exception * @throws HTTPResponse_Exception
*/ */
public function savetreenode($request) public function savetreenode(HTTPRequest $request): HTTPResponse
{ {
if (!SecurityToken::inst()->checkRequest($request)) { if (!SecurityToken::inst()->checkRequest($request)) {
return $this->httpError(400); $this->httpError(400);
} }
if (!$this->CanOrganiseSitetree()) { if (!$this->CanOrganiseSitetree()) {
return $this->httpError( $this->httpError(
403, 403,
_t( _t(
__CLASS__.'.CANT_REORGANISE', __CLASS__.'.CANT_REORGANISE',
@ -786,14 +766,14 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
$id = $request->requestVar('ID'); $id = $request->requestVar('ID');
$parentID = $request->requestVar('ParentID'); $parentID = $request->requestVar('ParentID');
if (!is_numeric($id) || !is_numeric($parentID)) { if (!is_numeric($id) || !is_numeric($parentID)) {
return $this->httpError(400); $this->httpError(400);
} }
// Check record exists in the DB // Check record exists in the DB
/** @var SiteTree $node */ /** @var SiteTree $node */
$node = DataObject::get_by_id($className, $id); $node = DataObject::get_by_id($className, $id);
if (!$node) { if (!$node) {
return $this->httpError( $this->httpError(
500, 500,
_t( _t(
__CLASS__.'.PLEASESAVE', __CLASS__.'.PLEASESAVE',
@ -805,7 +785,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
// Check top level permissions // Check top level permissions
$root = $node->getParentType(); $root = $node->getParentType();
if (($parentID == '0' || $root == 'root') && !SiteConfig::current_site_config()->canCreateTopLevel()) { if (($parentID == '0' || $root == 'root') && !SiteConfig::current_site_config()->canCreateTopLevel()) {
return $this->httpError( $this->httpError(
403, 403,
_t( _t(
__CLASS__.'.CANT_REORGANISE', __CLASS__.'.CANT_REORGANISE',
@ -1000,7 +980,6 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
); );
// Create the form // Create the form
/** @skipUpgrade */
$form = Form::create( $form = Form::create(
$this, $this,
'SearchForm', 'SearchForm',
@ -1037,7 +1016,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
return $pageTypes; return $pageTypes;
} }
public function doSearch($data, $form) public function doSearch(array $data, Form $form): HTTPResponse
{ {
return $this->getsubtree($this->getRequest()); return $this->getsubtree($this->getRequest());
} }
@ -1352,8 +1331,9 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
} }
// Added in-line to the form, but plucked into different view by LeftAndMain.Preview.js upon load // Added in-line to the form, but plucked into different view by LeftAndMain.Preview.js upon load
/** @skipUpgrade */ if (($record instanceof CMSPreviewable || $record->has_extension(CMSPreviewable::class))
if ($record instanceof CMSPreviewable && !$fields->fieldByName('SilverStripeNavigator')) { && !$fields->fieldByName('SilverStripeNavigator')
) {
$navField = new LiteralField('SilverStripeNavigator', $this->getSilverStripeNavigator()); $navField = new LiteralField('SilverStripeNavigator', $this->getSilverStripeNavigator());
$navField->setAllowHTML(true); $navField->setAllowHTML(true);
$fields->push($navField); $fields->push($navField);
@ -1389,7 +1369,6 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
} }
} }
// TODO Can't merge $FormAttributes in template at the moment
$form->addExtraClass('center ' . $this->BaseCSSClasses()); $form->addExtraClass('center ' . $this->BaseCSSClasses());
// Set validation exemptions for specific actions // Set validation exemptions for specific actions
$form->setValidationExemptActions([ $form->setValidationExemptActions([
@ -1404,7 +1383,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
]); ]);
// Announce the capability so the frontend can decide whether to allow preview or not. // Announce the capability so the frontend can decide whether to allow preview or not.
if ($record instanceof CMSPreviewable) { if ($record instanceof CMSPreviewable || $record->has_extension(CMSPreviewable::class)) {
$form->addExtraClass('cms-previewable'); $form->addExtraClass('cms-previewable');
} }
$form->addExtraClass('fill-height flexbox-area-grow'); $form->addExtraClass('fill-height flexbox-area-grow');
@ -1560,17 +1539,14 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
/** /**
* Callback to request the list of page types allowed under a given page instance. * Callback to request the list of page types allowed under a given page instance.
* Provides a slower but more precise response over SiteTreeHints * Provides a slower but more precise response over SiteTreeHints
*
* @param HTTPRequest $request
* @return HTTPResponse
*/ */
public function childfilter($request) public function childfilter(HTTPRequest $request): HTTPResponse
{ {
// Check valid parent specified // Check valid parent specified
$parentID = $request->requestVar('ParentID'); $parentID = $request->requestVar('ParentID');
$parent = SiteTree::get()->byID($parentID); $parent = SiteTree::get()->byID($parentID);
if (!$parent || !$parent->exists()) { if (!$parent || !$parent->exists()) {
return $this->httpError(404); $this->httpError(404);
} }
// Build hints specific to this class // Build hints specific to this class
@ -1757,12 +1733,9 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
/** /**
* Save and Publish page handler * Save and Publish page handler
* *
* @param array $data
* @param Form $form
* @return HTTPResponse
* @throws HTTPResponse_Exception * @throws HTTPResponse_Exception
*/ */
public function save($data, $form) public function save(array $data, Form $form): HTTPResponse
{ {
$className = $this->config()->get('tree_class'); $className = $this->config()->get('tree_class');
@ -1791,7 +1764,6 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
return Security::permissionFailure($this); return Security::permissionFailure($this);
} }
// TODO Coupling to SiteTree
$record->HasBrokenLink = 0; $record->HasBrokenLink = 0;
$record->HasBrokenFile = 0; $record->HasBrokenFile = 0;
@ -1905,12 +1877,9 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
* *
* @uses SiteTree->doRevertToLive() * @uses SiteTree->doRevertToLive()
* *
* @param array $data
* @param Form $form
* @return HTTPResponse
* @throws HTTPResponse_Exception * @throws HTTPResponse_Exception
*/ */
public function revert($data, $form) public function revert(array $data, Form $form): HTTPResponse
{ {
if (!isset($data['ID'])) { if (!isset($data['ID'])) {
throw new HTTPResponse_Exception("Please pass an ID in the form content", 400); throw new HTTPResponse_Exception("Please pass an ID in the form content", 400);
@ -1958,12 +1927,9 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
* *
* @see deletefromlive() * @see deletefromlive()
* *
* @param array $data
* @param Form $form
* @return HTTPResponse
* @throws HTTPResponse_Exception * @throws HTTPResponse_Exception
*/ */
public function delete($data, $form) public function delete(array $data, Form $form): HTTPResponse
{ {
$id = $data['ID']; $id = $data['ID'];
$record = SiteTree::get()->byID($id); $record = SiteTree::get()->byID($id);
@ -1993,12 +1959,9 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
/** /**
* Delete this page from both live and stage * Delete this page from both live and stage
* *
* @param array $data
* @param Form $form
* @return HTTPResponse
* @throws HTTPResponse_Exception * @throws HTTPResponse_Exception
*/ */
public function archive($data, $form) public function archive(array $data, Form $form): HTTPResponse
{ {
$id = $data['ID']; $id = $data['ID'];
/** @var SiteTree $record */ /** @var SiteTree $record */
@ -2026,14 +1989,14 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
return $this->getResponseNegotiator()->respond($this->getRequest()); return $this->getResponseNegotiator()->respond($this->getRequest());
} }
public function publish($data, $form) public function publish(array $data, Form $form): HTTPResponse
{ {
$data['publish'] = '1'; $data['publish'] = '1';
return $this->save($data, $form); return $this->save($data, $form);
} }
public function unpublish($data, $form) public function unpublish(array $data, Form $form): HTTPResponse
{ {
$className = $this->config()->get('tree_class'); $className = $this->config()->get('tree_class');
/** @var SiteTree $record */ /** @var SiteTree $record */
@ -2168,87 +2131,10 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
return $this->batchactions()->batchActionList(); return $this->batchactions()->batchActionList();
} }
/**
* @deprecated 4.12.0 Use custom logic instead
* @param $request
* @return HTTPResponse|string|void
*/
public function publishall($request)
{
Deprecation::notice('4.12.0', 'Use custom logic instead');
if (!Permission::check('ADMIN')) {
return Security::permissionFailure($this);
}
Environment::increaseTimeLimitTo();
Environment::increaseMemoryLimitTo();
$response = "";
if (isset($this->requestParams['confirm'])) {
// Protect against CSRF on destructive action
if (!SecurityToken::inst()->checkRequest($request)) {
return $this->httpError(400);
}
$start = 0;
$pages = SiteTree::get()->limit("$start,30");
$count = 0;
while ($pages) {
/** @var SiteTree $page */
foreach ($pages as $page) {
if ($page && !$page->canPublish()) {
return Security::permissionFailure($this);
}
$page->publishRecursive();
$page->destroy();
unset($page);
$count++;
$response .= "<li>$count</li>";
}
if ($pages->count() > 29) {
$start += 30;
$pages = SiteTree::get()->limit("$start,30");
} else {
break;
}
}
$response .= _t(__CLASS__ . '.PUBPAGES', "Done: Published {count} pages", ['count' => $count]);
} else {
$token = SecurityToken::inst();
$fields = new FieldList();
$token->updateFieldSet($fields);
$tokenField = $fields->first();
$tokenHtml = ($tokenField) ? $tokenField->FieldHolder() : '';
$publishAllDescription = _t(
__CLASS__ . '.PUBALLFUN2',
'Pressing this button will do the equivalent of going to every page and pressing "publish". '
. 'It\'s intended to be used after there have been massive edits of the content, such as when '
. 'the site was first built. '
. 'For large websites, this task might not be able to run through to completion. '
. 'In this case, we recommend talking to your developers to create a custom task'
);
$response .= '<h1>' . _t(__CLASS__ . '.PUBALLFUN', '"Publish All" functionality') . '</h1>
<p>' . $publishAllDescription . '</p>
<form method="post" action="publishall">
<input type="submit" name="confirm" value="'
. _t(__CLASS__ . '.PUBALLCONFIRM', "Please publish every page in the site, copying content stage to live", 'Confirmation button') .'" />'
. $tokenHtml .
'</form>';
}
return $response;
}
/** /**
* Restore a completely deleted page from the SiteTree_versions table. * Restore a completely deleted page from the SiteTree_versions table.
*
* @param array $data
* @param Form $form
* @return HTTPResponse
*/ */
public function restore($data, $form) public function restore(array $data, Form $form): HTTPResponse
{ {
if (!isset($data['ID']) || !is_numeric($data['ID'])) { if (!isset($data['ID']) || !is_numeric($data['ID'])) {
return new HTTPResponse("Please pass an ID in the form content", 400); return new HTTPResponse("Please pass an ID in the form content", 400);
@ -2275,7 +2161,7 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
return $this->getResponseNegotiator()->respond($this->getRequest()); return $this->getResponseNegotiator()->respond($this->getRequest());
} }
public function duplicate($request) public function duplicate(HTTPRequest $request): HTTPResponse
{ {
// Protect against CSRF on destructive action // Protect against CSRF on destructive action
if (!SecurityToken::inst()->checkRequest($request)) { if (!SecurityToken::inst()->checkRequest($request)) {
@ -2319,11 +2205,11 @@ class CMSMain extends LeftAndMain implements CurrentPageIdentifier, PermissionPr
return new HTTPResponse("CMSMain::duplicate() Bad ID: '$id'", 400); return new HTTPResponse("CMSMain::duplicate() Bad ID: '$id'", 400);
} }
public function duplicatewithchildren($request) public function duplicatewithchildren(HTTPRequest $request): HTTPResponse
{ {
// Protect against CSRF on destructive action // Protect against CSRF on destructive action
if (!SecurityToken::inst()->checkRequest($request)) { if (!SecurityToken::inst()->checkRequest($request)) {
return $this->httpError(400); $this->httpError(400);
} }
Environment::increaseTimeLimitTo(); Environment::increaseTimeLimitTo();
if (($id = $this->urlParams['ID']) && is_numeric($id)) { if (($id = $this->urlParams['ID']) && is_numeric($id)) {

View File

@ -132,10 +132,6 @@ class CMSPageAddController extends CMSPageEditController
]); ]);
}); });
// TODO Re-enable search once it allows for HTML title display,
// see http://open.silverstripe.org/ticket/7455
// $parentField->setShowSearch(true);
$parentModeField->addExtraClass('parent-mode'); $parentModeField->addExtraClass('parent-mode');
// CMSMain->currentPageID() automatically sets the homepage, // CMSMain->currentPageID() automatically sets the homepage,
@ -192,12 +188,7 @@ class CMSPageAddController extends CMSPageEditController
return $form; return $form;
} }
/** public function doAdd(array $data, Form $form): HTTPResponse
* @param array $data
* @param Form $form
* @return HTTPResponse
*/
public function doAdd($data, $form)
{ {
$className = isset($data['PageType']) ? $data['PageType'] : "Page"; $className = isset($data['PageType']) ? $data['PageType'] : "Page";
$parentID = isset($data['ParentID']) ? (int)$data['ParentID'] : 0; $parentID = isset($data['ParentID']) ? (int)$data['ParentID'] : 0;
@ -241,7 +232,7 @@ class CMSPageAddController extends CMSPageEditController
return $this->redirect(Controller::join_links($editController->Link('show'), $record->ID)); return $this->redirect(Controller::join_links($editController->Link('show'), $record->ID));
} }
public function doCancel($data, $form) public function doCancel(array $data, Form $form): HTTPResponse
{ {
return $this->redirect(CMSMain::singleton()->Link()); return $this->redirect(CMSMain::singleton()->Link());
} }

View File

@ -53,30 +53,27 @@ class CMSPageEditController extends CMSMain
/** /**
* Action handler for adding pages to a campaign * Action handler for adding pages to a campaign
*
* @param array $data
* @param Form $form
* @return DBHTMLText|HTTPResponse
*/ */
public function addtocampaign($data, $form) public function addtocampaign(array $data, Form $form): HTTPResponse
{ {
$id = $data['ID']; $id = $data['ID'];
$record = \Page::get()->byID($id); $record = \Page::get()->byID($id);
$handler = AddToCampaignHandler::create($this, $record); $handler = AddToCampaignHandler::create($this, $record);
$results = $handler->addToCampaign($record, $data); $response = $handler->addToCampaign($record, $data);
if (is_null($results)) { $message = $response->getBody();
return null; if (empty($message)) {
return $response;
} }
if ($this->getSchemaRequested()) { if ($this->getSchemaRequested()) {
// Send extra "message" data with schema response // Send extra "message" data with schema response
$extraData = ['message' => $results]; $extraData = ['message' => $message];
$schemaId = Controller::join_links($this->Link('schema/AddToCampaignForm'), $id); $schemaId = Controller::join_links($this->Link('schema/AddToCampaignForm'), $id);
return $this->getSchemaResponse($schemaId, $form, null, $extraData); return $this->getSchemaResponse($schemaId, $form, null, $extraData);
} }
return $results; return $response;
} }
/** /**

View File

@ -1,480 +0,0 @@
<?php
namespace SilverStripe\CMS\Controllers;
use SilverStripe\Dev\Deprecation;
use SilverStripe\Admin\LeftAndMainFormRequestHandler;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Control\Controller;
use SilverStripe\Control\HTTPRequest;
use SilverStripe\Control\HTTPResponse;
use SilverStripe\Forms\CheckboxField;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\Form;
use SilverStripe\Forms\FormAction;
use SilverStripe\Forms\HiddenField;
use SilverStripe\Forms\HTMLReadonlyField;
use SilverStripe\Forms\LiteralField;
use SilverStripe\Forms\Tab;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\Versioned\Versioned;
use SilverStripe\Security\Security;
use SilverStripe\View\ArrayData;
use SilverStripe\View\ViewableData;
/**
* Legacy CMS History controller. This functionality has been moved to the `silverstripe/versioned-admin` module and
* this class will be removed completly in SilverStripe 5.0.0.
* @deprecated 4.3.0 Use silverstripe/versioned-admin instead
*/
class CMSPageHistoryController extends CMSMain
{
private static $url_segment = 'pages/history';
private static $url_rule = '/$Action/$ID/$VersionID/$OtherVersionID';
private static $url_priority = 42;
private static $menu_title = 'History';
private static $required_permission_codes = 'CMS_ACCESS_CMSMain';
private static $allowed_actions = [
'EditForm',
'VersionsForm',
'CompareVersionsForm',
'show',
'compare'
];
private static $url_handlers = [
'$Action/$ID/$VersionID/$OtherVersionID' => 'handleAction',
'EditForm/$ID/$VersionID' => 'EditForm',
];
/**
* Current version ID for this request. Can be 0 for latest version
*
* @var int
*/
protected $versionID = null;
public function __construct()
{
parent::__construct();
Deprecation::withNoReplacement(function () {
Deprecation::notice('4.3.0', 'Use silverstripe/versioned-admin instead', Deprecation::SCOPE_CLASS);
});
}
public function getResponseNegotiator()
{
$negotiator = parent::getResponseNegotiator();
$negotiator->setCallback('CurrentForm', function () {
$form = $this->getEditForm();
if ($form) {
return $form->forTemplate();
}
return $this->renderWith($this->getTemplatesWithSuffix('_Content'));
});
$negotiator->setCallback('default', function () {
return $this->renderWith($this->getViewer('show'));
});
return $negotiator;
}
/**
* @param HTTPRequest $request
* @return HTTPResponse
*/
public function show($request)
{
// Record id and version for this request
$id = $request->param('ID');
$this->setCurrentPageID($id);
$versionID = $request->param('VersionID');
$this->setVersionID($versionID);
// Show id
$form = $this->getEditForm();
$negotiator = $this->getResponseNegotiator();
$negotiator->setCallback('CurrentForm', function () use ($form) {
return $form
? $form->forTemplate()
: $this->renderWith($this->getTemplatesWithSuffix('_Content'));
});
$negotiator->setCallback('default', function () use ($form) {
return $this
->customise(['EditForm' => $form])
->renderWith($this->getViewer('show'));
});
return $negotiator->respond($request);
}
/**
* @param HTTPRequest $request
* @return HTTPResponse
*/
public function compare($request)
{
$form = $this->CompareVersionsForm(
$request->param('VersionID'),
$request->param('OtherVersionID')
);
$negotiator = $this->getResponseNegotiator();
$negotiator->setCallback('CurrentForm', function () use ($form) {
return $form ? $form->forTemplate() : $this->renderWith($this->getTemplatesWithSuffix('_Content'));
});
$negotiator->setCallback('default', function () use ($form) {
return $this->customise(['EditForm' => $form])->renderWith($this->getViewer('show'));
});
return $negotiator->respond($request);
}
public function getSilverStripeNavigator()
{
$record = $this->getRecord($this->currentPageID(), $this->getRequest()->param('VersionID'));
if ($record) {
$navigator = new SilverStripeNavigator($record);
return $navigator->renderWith($this->getTemplatesWithSuffix('_SilverStripeNavigator'));
} else {
return false;
}
}
/**
* @param HTTPRequest $request
* @return Form
*/
public function EditForm($request = null)
{
if ($request) {
// Validate VersionID is present
$versionID = $request->param('VersionID');
if (!isset($versionID)) {
$this->httpError(400);
return null;
}
$this->setVersionID($versionID);
}
return parent::EditForm($request);
}
/**
* Returns the read only version of the edit form. Detaches all {@link FormAction}
* instances attached since only action relates to revert.
*
* Permission checking is done at the {@link CMSMain::getEditForm()} level.
*
* @param int $id ID of the record to show
* @param array $fields optional
* @param int $versionID
* @param int $compareID Compare mode
*
* @return Form
*/
public function getEditForm($id = null, $fields = null, $versionID = null, $compareID = null)
{
if (!$id) {
$id = $this->currentPageID();
}
if (!$versionID) {
$versionID = $this->getVersionID();
}
$record = $this->getRecord($id, $versionID);
if (!$record) {
return $this->EmptyForm();
}
// Refresh version ID
$versionID = $record->Version;
$this->setVersionID($versionID);
// Get edit form
$form = parent::getEditForm($record, $record->getCMSFields());
// Respect permission failures from parent implementation
if (!($form instanceof Form)) {
return $form;
}
// TODO: move to the SilverStripeNavigator structure so the new preview can pick it up.
//$nav = new SilverStripeNavigatorItem_ArchiveLink($record);
$actions = new FieldList(
$revert = FormAction::create(
'doRollback',
_t('SilverStripe\\CMS\\Controllers\\CMSPageHistoryController.REVERTTOTHISVERSION', 'Revert to this version')
)
->setUseButtonTag(true)
->addExtraClass('btn-warning font-icon-back-in-time')
);
$actions->setForm($form);
$form->setActions($actions);
$fields = $form->Fields();
$fields->removeByName("Status");
$fields->push(new HiddenField("ID"));
$fields->push(new HiddenField("Version"));
$fields = $fields->makeReadonly();
if ($compareID) {
$link = Controller::join_links(
$this->Link('show'),
$id
);
$view = _t(__CLASS__ . '.VIEW', "view");
$message = _t(
__CLASS__ . '.COMPARINGVERSION',
"Comparing versions {version1} and {version2}.",
[
'version1' => sprintf('%s (<a href="%s">%s</a>)', $versionID, Controller::join_links($link, $versionID), $view),
'version2' => sprintf('%s (<a href="%s">%s</a>)', $compareID, Controller::join_links($link, $compareID), $view)
]
);
$revert->setReadonly(true);
} else {
if ($record->isLatestVersion()) {
$message = _t(__CLASS__ . '.VIEWINGLATEST', 'Currently viewing the latest version.');
} else {
$message = _t(
__CLASS__ . '.VIEWINGVERSION',
"Currently viewing version {version}.",
['version' => $versionID]
);
}
}
/** @var Tab $mainTab */
$mainTab = $fields->fieldByName('Root.Main');
$mainTab->unshift(
LiteralField::create('CurrentlyViewingMessage', ArrayData::create([
'Content' => DBField::create_field('HTMLFragment', $message),
'Classes' => 'alert alert-info'
])->renderWith($this->getTemplatesWithSuffix('_notice')))
);
$form->setFields($fields->makeReadonly());
$form->loadDataFrom([
"ID" => $id,
"Version" => $versionID,
]);
if ($record->isLatestVersion()) {
$revert->setReadonly(true);
}
$form->removeExtraClass('cms-content');
// History form has both ID and VersionID as suffixes
$form->setRequestHandler(
LeftAndMainFormRequestHandler::create($form, [$id, $versionID])
);
return $form;
}
/**
* Version select form. Main interface between selecting versions to view
* and comparing multiple versions.
*
* Because we can reload the page directly to a compare view (history/compare/1/2/3)
* this form has to adapt to those parameters as well.
*
* @return Form
*/
public function VersionsForm()
{
$id = $this->currentPageID();
$page = $this->getRecord($id);
$versionsHtml = '';
$action = $this->getRequest()->param('Action');
$versionID = $this->getRequest()->param('VersionID');
$otherVersionID = $this->getRequest()->param('OtherVersionID');
$showUnpublishedChecked = 0;
$compareModeChecked = ($action == "compare");
if ($page) {
$versions = $page->Versions();
$versionID = (!$versionID) ? $page->Version : $versionID;
if ($versions) {
foreach ($versions as $k => $version) {
$active = false;
if ($version->Version == $versionID || $version->Version == $otherVersionID) {
$active = true;
if (!$version->WasPublished) {
$showUnpublishedChecked = 1;
}
}
$version->Active = ($active);
}
}
$vd = new ViewableData();
$versionsHtml = $vd->customise([
'Versions' => $versions
])->renderWith($this->getTemplatesWithSuffix('_versions'));
}
$fields = new FieldList(
new CheckboxField(
'ShowUnpublished',
_t('SilverStripe\\CMS\\Controllers\\CMSPageHistoryController.SHOWUNPUBLISHED', 'Show unpublished versions'),
$showUnpublishedChecked
),
new CheckboxField(
'CompareMode',
_t('SilverStripe\\CMS\\Controllers\\CMSPageHistoryController.COMPAREMODE', 'Compare mode (select two)'),
$compareModeChecked
),
new LiteralField('VersionsHtml', $versionsHtml),
$hiddenID = new HiddenField('ID', false, "")
);
$form = Form::create(
$this,
'VersionsForm',
$fields,
new FieldList()
)->setHTMLID('Form_VersionsForm');
$form->loadDataFrom($this->getRequest()->requestVars());
$hiddenID->setValue($id);
$form->unsetValidator();
$form
->addExtraClass('cms-versions-form') // placeholder, necessary for $.metadata() to work
->setAttribute('data-link-tmpl-compare', Controller::join_links($this->Link('compare'), '%s', '%s', '%s'))
->setAttribute('data-link-tmpl-show', Controller::join_links($this->Link('show'), '%s', '%s'));
return $form;
}
/**
* @param int $versionID
* @param int $otherVersionID
* @return mixed
*/
public function CompareVersionsForm($versionID, $otherVersionID)
{
if ($versionID > $otherVersionID) {
$toVersion = $versionID;
$fromVersion = $otherVersionID;
} else {
$toVersion = $otherVersionID;
$fromVersion = $versionID;
}
if (!$toVersion || !$fromVersion) {
return null;
}
$id = $this->currentPageID();
/** @var SiteTree $page */
$page = SiteTree::get()->byID($id);
$record = null;
if ($page && $page->exists()) {
if (!$page->canView()) {
return Security::permissionFailure($this);
}
$record = $page->compareVersions($fromVersion, $toVersion);
}
$fromVersionRecord = Versioned::get_version(SiteTree::class, $id, $fromVersion);
$toVersionRecord = Versioned::get_version(SiteTree::class, $id, $toVersion);
if (!$fromVersionRecord) {
throw new \Exception("Can't find version $fromVersion of page $id");
}
if (!$toVersionRecord) {
throw new \Exception("Can't find version $toVersion of page $id");
}
if (!$record) {
return null;
}
$form = $this->getEditForm($id, null, $fromVersion, $toVersion);
$form->setActions(new FieldList());
$form->addExtraClass('compare');
$form->loadDataFrom($record);
$form->loadDataFrom([
"ID" => $id,
"Version" => $fromVersion,
]);
// Comparison views shouldn't be editable.
// As the comparison output is HTML and not valid values for the various field types
$readonlyFields = $this->transformReadonly($form->Fields());
$form->setFields($readonlyFields);
return $form;
}
/**
* Replace all data fields with HTML readonly fields to display diff
*
* @param FieldList $fields
* @return FieldList
*/
public function transformReadonly(FieldList $fields)
{
foreach ($fields->dataFields() as $field) {
if ($field instanceof HiddenField) {
continue;
}
$newField = $field->castedCopy(HTMLReadonlyField::class);
$fields->replaceField($field->getName(), $newField);
}
return $fields;
}
/**
* Set current version ID
*
* @param int $versionID
* @return $this
*/
public function setVersionID($versionID)
{
$this->versionID = $versionID;
return $this;
}
/**
* Get current version ID
*
* @return int
*/
public function getVersionID()
{
return $this->versionID;
}
public function getTabIdentifier()
{
return 'history';
}
}

View File

@ -2,6 +2,7 @@
namespace SilverStripe\CMS\Controllers; namespace SilverStripe\CMS\Controllers;
use SilverStripe\Admin\Navigator\SilverStripeNavigator;
use SilverStripe\CMS\Model\SiteTree; use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Control\Controller; use SilverStripe\Control\Controller;
use SilverStripe\Control\Director; use SilverStripe\Control\Director;
@ -29,7 +30,6 @@ use SilverStripe\View\ArrayData;
use SilverStripe\View\Parsers\URLSegmentFilter; use SilverStripe\View\Parsers\URLSegmentFilter;
use SilverStripe\View\Requirements; use SilverStripe\View\Requirements;
use SilverStripe\View\SSViewer; use SilverStripe\View\SSViewer;
use Translatable;
/** /**
* The most common kind of controller; effectively a controller linked to a {@link DataObject}. * The most common kind of controller; effectively a controller linked to a {@link DataObject}.
@ -45,7 +45,6 @@ use Translatable;
* Subclasses of ContentController are generally instantiated by ModelAsController; this will create * Subclasses of ContentController are generally instantiated by ModelAsController; this will create
* a controller based on the URLSegment action variable, by looking in the SiteTree table. * a controller based on the URLSegment action variable, by looking in the SiteTree table.
* *
* @todo Can this be used for anything other than SiteTree controllers?
*/ */
class ContentController extends Controller class ContentController extends Controller
{ {
@ -175,7 +174,6 @@ class ContentController extends Controller
} }
// Check page permissions // Check page permissions
/** @skipUpgrade */
if ($this->dataRecord && $this->URLSegment != 'Security' && !$this->dataRecord->canView()) { if ($this->dataRecord && $this->URLSegment != 'Security' && !$this->dataRecord->canView()) {
Security::permissionFailure($this); Security::permissionFailure($this);
return; return;
@ -186,11 +184,9 @@ class ContentController extends Controller
* This acts the same as {@link Controller::handleRequest()}, but if an action cannot be found this will attempt to * This acts the same as {@link Controller::handleRequest()}, but if an action cannot be found this will attempt to
* fall over to a child controller in order to provide functionality for nested URLs. * fall over to a child controller in order to provide functionality for nested URLs.
* *
* @param HTTPRequest $request
* @return HTTPResponse
* @throws HTTPResponse_Exception * @throws HTTPResponse_Exception
*/ */
public function handleRequest(HTTPRequest $request) public function handleRequest(HTTPRequest $request): HTTPResponse
{ {
/** @var SiteTree $child */ /** @var SiteTree $child */
$child = null; $child = null;
@ -200,11 +196,6 @@ class ContentController extends Controller
// control to a child controller. This allows for the creation of chains of controllers which correspond to a // control to a child controller. This allows for the creation of chains of controllers which correspond to a
// nested URL. // nested URL.
if ($action && SiteTree::config()->nested_urls && !$this->hasAction($action)) { if ($action && SiteTree::config()->nested_urls && !$this->hasAction($action)) {
// See ModelAdController->getNestedController() for similar logic
if (class_exists('Translatable')) {
Translatable::disable_locale_filter();
}
$filter = URLSegmentFilter::create(); $filter = URLSegmentFilter::create();
// look for a page with this URLSegment // look for a page with this URLSegment
@ -213,10 +204,6 @@ class ContentController extends Controller
// url encode unless it's multibyte (already pre-encoded in the database) // url encode unless it's multibyte (already pre-encoded in the database)
'URLSegment' => $filter->getAllowMultibyte() ? $action : rawurlencode($action), 'URLSegment' => $filter->getAllowMultibyte() ? $action : rawurlencode($action),
])->first(); ])->first();
if (class_exists('Translatable')) {
Translatable::enable_locale_filter();
}
} }
// we found a page with this URLSegment. // we found a page with this URLSegment.
@ -226,25 +213,6 @@ class ContentController extends Controller
$response = ModelAsController::controller_for($child)->handleRequest($request); $response = ModelAsController::controller_for($child)->handleRequest($request);
} else { } else {
// If a specific locale is requested, and it doesn't match the page found by URLSegment,
// look for a translation and redirect (see #5001). Only happens on the last child in
// a potentially nested URL chain.
if (class_exists('Translatable')) {
$locale = $request->getVar('locale');
if ($locale
&& i18n::getData()->validate($locale)
&& $this->dataRecord
&& $this->dataRecord->Locale != $locale
) {
$translation = $this->dataRecord->getTranslation($locale);
if ($translation) {
$response = new HTTPResponse();
$response->redirect($translation->Link(), 301);
throw new HTTPResponse_Exception($response);
}
}
}
Director::set_current_page($this->data()); Director::set_current_page($this->data());
try { try {
@ -334,8 +302,6 @@ class ContentController extends Controller
/** /**
* Returns the default log-in form. * Returns the default log-in form.
* *
* @todo Check if here should be returned just the default log-in form or
* all available log-in forms (also OpenID...)
* @return \SilverStripe\Security\MemberAuthenticator\MemberLoginForm * @return \SilverStripe\Security\MemberAuthenticator\MemberLoginForm
*/ */
public function LoginForm() public function LoginForm()
@ -415,9 +381,6 @@ HTML;
/** /**
* Returns an RFC1766 compliant locale string, e.g. 'fr-CA'. * Returns an RFC1766 compliant locale string, e.g. 'fr-CA'.
* Inspects the associated {@link dataRecord} for a {@link SiteTree->Locale} value if present,
* and falls back to {@link Translatable::get_current_locale()} or {@link i18n::default_locale()},
* depending if Translatable is enabled.
* *
* Suitable for insertion into lang= and xml:lang= * Suitable for insertion into lang= and xml:lang=
* attributes in HTML or XHTML output. * attributes in HTML or XHTML output.
@ -426,14 +389,7 @@ HTML;
*/ */
public function ContentLocale() public function ContentLocale()
{ {
if ($this->dataRecord && $this->dataRecord->hasExtension('Translatable')) {
$locale = $this->dataRecord->Locale;
} elseif (class_exists('Translatable') && SiteTree::has_extension('Translatable')) {
$locale = Translatable::get_current_locale();
} else {
$locale = i18n::get_locale(); $locale = i18n::get_locale();
}
return i18n::convert_rfc1766($locale); return i18n::convert_rfc1766($locale);
} }
@ -490,7 +446,6 @@ HTML;
$this->httpError(410); $this->httpError(410);
} }
// TODO Allow this to work when allow_url_fopen=0
if (isset($_SESSION['StatsID']) && $_SESSION['StatsID']) { if (isset($_SESSION['StatsID']) && $_SESSION['StatsID']) {
$url = 'http://ss2stat.silverstripe.com/Installation/installed?ID=' . $_SESSION['StatsID']; $url = 'http://ss2stat.silverstripe.com/Installation/installed?ID=' . $_SESSION['StatsID'];
@file_get_contents($url ?? ''); @file_get_contents($url ?? '');

View File

@ -17,7 +17,6 @@ use SilverStripe\Dev\Debug;
use SilverStripe\ORM\DataObject; use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DB; use SilverStripe\ORM\DB;
use SilverStripe\View\Parsers\URLSegmentFilter; use SilverStripe\View\Parsers\URLSegmentFilter;
use Translatable;
/** /**
* ModelAsController deals with mapping the initial request to the first {@link SiteTree}/{@link ContentController} * ModelAsController deals with mapping the initial request to the first {@link SiteTree}/{@link ContentController}
@ -33,11 +32,9 @@ class ModelAsController extends Controller implements NestedController
* Get the appropriate {@link ContentController} for handling a {@link SiteTree} object, link it to the object and * Get the appropriate {@link ContentController} for handling a {@link SiteTree} object, link it to the object and
* return it. * return it.
* *
* @param SiteTree $sitetree
* @param string $action * @param string $action
* @return ContentController
*/ */
public static function controller_for(SiteTree $sitetree, $action = null) public static function controller_for(SiteTree $sitetree, $action = null): ContentController
{ {
$controller = $sitetree->getControllerName(); $controller = $sitetree->getControllerName();
@ -58,7 +55,6 @@ class ModelAsController extends Controller implements NestedController
{ {
parent::beforeHandleRequest($request); parent::beforeHandleRequest($request);
// If the database has not yet been created, redirect to the build page. // If the database has not yet been created, redirect to the build page.
/** @skipUpgrade */
if (!DB::is_active() || !ClassInfo::hasTable('SiteTree')) { if (!DB::is_active() || !ClassInfo::hasTable('SiteTree')) {
$this->getResponse()->redirect(Controller::join_links( $this->getResponse()->redirect(Controller::join_links(
Director::absoluteBaseURL(), Director::absoluteBaseURL(),
@ -72,10 +68,8 @@ class ModelAsController extends Controller implements NestedController
/** /**
* @uses ModelAsController::getNestedController() * @uses ModelAsController::getNestedController()
* @param HTTPRequest $request
* @return HTTPResponse
*/ */
public function handleRequest(HTTPRequest $request) public function handleRequest(HTTPRequest $request): HTTPResponse
{ {
$this->beforeHandleRequest($request); $this->beforeHandleRequest($request);
@ -86,23 +80,16 @@ class ModelAsController extends Controller implements NestedController
} }
// If the database has not yet been created, redirect to the build page. // If the database has not yet been created, redirect to the build page.
/** @skipUpgrade */
if (!DB::is_active() || !ClassInfo::hasTable('SiteTree')) { if (!DB::is_active() || !ClassInfo::hasTable('SiteTree')) {
$this->getResponse()->redirect(Director::absoluteBaseURL() . 'dev/build?returnURL=' . (isset($_GET['url']) ? urlencode($_GET['url']) : null)); $this->getResponse()->redirect(Controller::join_links(Director::absoluteBaseURL(), 'dev/build?returnURL=' . (isset($_GET['url']) ? urlencode($_GET['url']) : null)));
$this->popCurrent(); $this->popCurrent();
return $this->getResponse(); return $this->getResponse();
} }
try { try {
$result = $this->getNestedController(); $result = $this->getNestedController()->handleRequest($this->getRequest());
$result = $result;
if ($result instanceof RequestHandler) {
$result = $result->handleRequest($this->getRequest());
} elseif (!($result instanceof HTTPResponse)) {
user_error("ModelAsController::getNestedController() returned bad object type '" .
get_class($result)."'", E_USER_WARNING);
}
} catch (HTTPResponse_Exception $responseException) { } catch (HTTPResponse_Exception $responseException) {
$result = $responseException->getResponse(); $result = $responseException->getResponse();
} }
@ -112,10 +99,9 @@ class ModelAsController extends Controller implements NestedController
} }
/** /**
* @return ContentController
* @throws Exception If URLSegment not passed in as a request parameter. * @throws Exception If URLSegment not passed in as a request parameter.
*/ */
public function getNestedController() public function getNestedController(): ContentController
{ {
$request = $this->getRequest(); $request = $this->getRequest();
$urlSegment = $request->param('URLSegment'); $urlSegment = $request->param('URLSegment');
@ -124,11 +110,6 @@ class ModelAsController extends Controller implements NestedController
throw new Exception('ModelAsController->getNestedController(): was not passed a URLSegment value.'); throw new Exception('ModelAsController->getNestedController(): was not passed a URLSegment value.');
} }
// Find page by link, regardless of current locale settings
if (class_exists('Translatable')) {
Translatable::disable_locale_filter();
}
// url encode unless it's multibyte (already pre-encoded in the database) // url encode unless it's multibyte (already pre-encoded in the database)
$filter = URLSegmentFilter::create(); $filter = URLSegmentFilter::create();
@ -145,21 +126,10 @@ class ModelAsController extends Controller implements NestedController
/** @var SiteTree $sitetree */ /** @var SiteTree $sitetree */
$sitetree = DataObject::get_one(SiteTree::class, $conditions); $sitetree = DataObject::get_one(SiteTree::class, $conditions);
// Check translation module
// @todo Refactor out module specific code
if (class_exists('Translatable')) {
Translatable::enable_locale_filter();
}
if (!$sitetree) { if (!$sitetree) {
$this->httpError(404, 'The requested page could not be found.'); $this->httpError(404, 'The requested page could not be found.');
} }
// Enforce current locale setting to the loaded SiteTree object
if (class_exists('Translatable') && $sitetree->Locale) {
Translatable::set_current_locale($sitetree->Locale);
}
if (isset($_REQUEST['debug'])) { if (isset($_REQUEST['debug'])) {
Debug::message("Using record #$sitetree->ID of type " . get_class($sitetree) . " with link {$sitetree->Link()}"); Debug::message("Using record #$sitetree->ID of type " . get_class($sitetree) . " with link {$sitetree->Link()}");
} }

View File

@ -17,10 +17,9 @@ class OldPageRedirector extends Extension
* On every URL that generates a 404, we'll capture it here and see if we can * On every URL that generates a 404, we'll capture it here and see if we can
* find an old URL that it should be redirecting to. * find an old URL that it should be redirecting to.
* *
* @param HTTPRequest $request The request object
* @throws HTTPResponse_Exception * @throws HTTPResponse_Exception
*/ */
public function onBeforeHTTPError404($request) public function onBeforeHTTPError404(HTTPRequest $request)
{ {
// We need to get the URL ourselves because $request->allParams() only has a max of 4 params // We need to get the URL ourselves because $request->allParams() only has a max of 4 params
$params = preg_split('|/+|', $request->getURL() ?? ''); $params = preg_split('|/+|', $request->getURL() ?? '');
@ -103,7 +102,7 @@ class OldPageRedirector extends Extension
// No valid page found. // No valid page found.
if ($redirect) { if ($redirect) {
// If we had some redirect to be done, lets do it. imagine /foo/action -> /bar/action, we still want this redirect to happen if action isn't a page // If we had some redirect to be done, lets do it. imagine /foo/action -> /bar/action, we still want this redirect to happen if action isn't a page
return $page->Link() . implode('/', $params); return Controller::join_links($page->Link(), implode('/', $params));
} }
} }
} else { } else {

View File

@ -73,7 +73,6 @@ class RootURLController extends Controller implements Resettable
self::$is_at_root = true; self::$is_at_root = true;
/** @skipUpgrade */
if (!DB::is_active() || !ClassInfo::hasTable('SiteTree')) { if (!DB::is_active() || !ClassInfo::hasTable('SiteTree')) {
$this->getResponse()->redirect(Controller::join_links( $this->getResponse()->redirect(Controller::join_links(
Director::absoluteBaseURL(), Director::absoluteBaseURL(),
@ -85,17 +84,12 @@ class RootURLController extends Controller implements Resettable
} }
} }
/** public function handleRequest(HTTPRequest $request): HTTPResponse
* @param HTTPRequest $request
* @return HTTPResponse
*/
public function handleRequest(HTTPRequest $request)
{ {
self::$is_at_root = true; self::$is_at_root = true;
$this->beforeHandleRequest($request); $this->beforeHandleRequest($request);
if (!$this->getResponse()->isFinished()) { if (!$this->getResponse()->isFinished()) {
/** @skipUpgrade */
if (!DB::is_active() || !ClassInfo::hasTable('SiteTree')) { if (!DB::is_active() || !ClassInfo::hasTable('SiteTree')) {
$this->getResponse()->redirect(Director::absoluteBaseURL() . 'dev/build?returnURL=' . (isset($_GET['url']) ? urlencode($_GET['url']) : null)); $this->getResponse()->redirect(Director::absoluteBaseURL() . 'dev/build?returnURL=' . (isset($_GET['url']) ? urlencode($_GET['url']) : null));
return $this->getResponse(); return $this->getResponse();

View File

@ -1,118 +0,0 @@
<?php
namespace SilverStripe\CMS\Controllers;
use SilverStripe\ORM\CMSPreviewable;
use SilverStripe\Core\ClassInfo;
use SilverStripe\Dev\Deprecation;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\SS_List;
use SilverStripe\View\ViewableData;
/**
* Utility class representing links to different views of a record
* for CMS authors, usually for {@link SiteTree} objects with "stage" and "live" links.
* Useful both in the CMS and alongside the page template (for logged in authors).
* The class can be used for any {@link DataObject} subclass implementing the {@link CMSPreviewable} interface.
*
* New item types can be defined by extending the {@link SilverStripeNavigatorItem} class,
* for example the "cmsworkflow" module defines a new "future state" item with a date selector
* to view embargoed data at a future point in time. So the item doesn't always have to be a simple link.
*
* Class will be moved from `silverstripe/cms` to `silverstripe/admin`
* @deprecated 4.13.0 Will be renamed SilverStripe\Admin\Navigator\SilverStripeNavigator
*/
class SilverStripeNavigator extends ViewableData
{
/**
* @var DataObject|\SilverStripe\ORM\CMSPreviewable
*/
protected $record;
/**
* @param DataObject|\SilverStripe\ORM\CMSPreviewable $record
*/
public function __construct(CMSPreviewable $record)
{
Deprecation::withNoReplacement(function () {
Deprecation::notice(
'4.13.0',
'Will be renamed SilverStripe\Admin\Navigator\SilverStripeNavigator',
Deprecation::SCOPE_CLASS
);
});
parent::__construct();
$this->record = $record;
}
/**
* @return SS_List of SilverStripeNavigatorItem
*/
public function getItems()
{
$items = [];
$classes = ClassInfo::subclassesFor(SilverStripeNavigatorItem::class);
array_shift($classes);
// Sort menu items according to priority
foreach ($classes as $class) {
/** @var SilverStripeNavigatorItem $item */
$item = new $class($this->record);
if (!$item->canView()) {
continue;
}
// This funny litle formula ensures that the first item added with the same priority will be left-most.
$priority = $item->getPriority() * 100 - 1;
// Ensure that we can have duplicates with the same (default) priority
while (isset($items[$priority])) {
$priority++;
}
$items[$priority] = $item;
}
ksort($items);
// Drop the keys and let the ArrayList handle the numbering, so $IsFirst, $IsLast and others work properly.
return new ArrayList(array_values($items ?? []));
}
/**
* @return DataObject|\SilverStripe\ORM\CMSPreviewable
*/
public function getRecord()
{
return $this->record;
}
/**
* @param DataObject|CMSPreviewable $record
* @return array template data
*/
public static function get_for_record($record)
{
$html = '';
$message = '';
$navigator = new SilverStripeNavigator($record);
$items = $navigator->getItems();
foreach ($items as $item) {
$text = $item->getHTML();
if ($text) {
$html .= $text;
}
$newMessage = $item->getMessage();
if ($newMessage && $item->isActive()) {
$message = $newMessage;
}
}
return [
'items' => $html,
'message' => $message
];
}
}

View File

@ -1,155 +0,0 @@
<?php
namespace SilverStripe\CMS\Controllers;
use SilverStripe\Dev\Deprecation;
use SilverStripe\ORM\CMSPreviewable;
use SilverStripe\ORM\DataObject;
use SilverStripe\Versioned\Versioned;
use SilverStripe\Security\Member;
use SilverStripe\View\ViewableData;
/**
* Navigator items are links that appear in the $SilverStripeNavigator bar.
* To add an item, extend this class - it will be automatically picked up.
* When instanciating items manually, please ensure to call {@link canView()}.
*
* Class have been moved from `silverstripe/cms` to `silverstripe/admin` and renamed.
* @deprecated Will be renamed SilverStripe\Admin\Navigator\SilverStripeNavigatorItem
*/
abstract class SilverStripeNavigatorItem extends ViewableData
{
/**
* @param DataObject|CMSPreviewable
*/
protected $record;
/** @var string */
protected $recordLink;
public function __construct(CMSPreviewable $record)
{
Deprecation::withNoReplacement(function () {
switch (static::class) {
// These classes have their own deprecation notice
case 'SilverStripe\CMS\Controllers\SilverStripeNavigatorItem_ArchiveLink':
case 'SilverStripe\CMS\Controllers\SilverStripeNavigatorItem_LiveLink':
case 'SilverStripe\CMS\Controllers\SilverStripeNavigatorItem_StageLink':
case 'SilverStripe\CMS\Controllers\SilverStripeNavigatorItem_Unversioned':
// This class is not deprecated and doesn't have a deprecation notice
case 'SilverStripe\CMS\Controllers\SilverStripeNavigatorItem_CMSLink':
break;
default:
Deprecation::notice(
'4.13.0',
'Will be renamed SilverStripe\Admin\Navigator\SilverStripeNavigatorItem',
Deprecation::SCOPE_CLASS
);
}
});
parent::__construct();
$this->record = $record;
}
/**
* @return string HTML, mostly a link - but can be more complex as well.
* For example, a "future state" item might show a date selector.
*/
abstract public function getHTML();
/**
* @return string
* Get the Title of an item
*/
abstract public function getTitle();
/**
* Machine-friendly name.
*
* @return string
*/
public function getName()
{
return substr(static::class, strpos(static::class, '_') + 1);
}
/**
* Optional link to a specific view of this record.
* Not all items are simple links, please use {@link getHTML()}
* to represent an item in markup unless you know what you're doing.
*
* @return string
*/
public function getLink()
{
return null;
}
/**
* @return string
*/
public function getMessage()
{
return null;
}
/**
* @return DataObject
*/
public function getRecord()
{
return $this->record;
}
/**
* @return int
*/
public function getPriority()
{
return $this->config()->get('priority');
}
/**
* As items might convey different record states like a "stage" or "live" table,
* an item can be active (showing the record in this state).
*
* @return boolean
*/
public function isActive()
{
return false;
}
/**
* Filters items based on member permissions or other criteria,
* such as if a state is generally available for the current record.
*
* @param Member $member
* @return Boolean
*/
public function canView($member = null)
{
return true;
}
/**
* Counts as "archived" if the current record is a different version from both live and draft.
*
* @return boolean
*/
public function isArchived()
{
/** @var Versioned|DataObject $record */
$record = $this->record;
if (!$record->hasExtension(Versioned::class) || !$record->hasStages()) {
return false;
}
if (!isset($record->_cached_isArchived)) {
$record->_cached_isArchived = $record->isArchived();
}
return $record->_cached_isArchived;
}
}

View File

@ -1,92 +0,0 @@
<?php
namespace SilverStripe\CMS\Controllers;
use SilverStripe\CMS\Model\RedirectorPage;
use SilverStripe\Control\Controller;
use SilverStripe\Core\Convert;
use SilverStripe\Dev\Deprecation;
use SilverStripe\ORM\CMSPreviewable;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\Versioned\Versioned;
/**
* Class will be moved from `silverstripe/cms` to `silverstripe/admin`
* @deprecated 4.13.0 Will be renamed SilverStripe\VersionedAdmin\Navigator\SilverStripeNavigatorItem_ArchiveLink
*/
class SilverStripeNavigatorItem_ArchiveLink extends SilverStripeNavigatorItem
{
/**
* @param DataObject|CMSPreviewable $record
*/
public function __construct(CMSPreviewable $record)
{
Deprecation::withNoReplacement(function () {
Deprecation::notice(
'4.13.0',
'Will be renamed SilverStripe\VersionedAdmin\Navigator\SilverStripeNavigatorItem_ArchiveLink',
Deprecation::SCOPE_CLASS
);
});
parent::__construct($record);
}
/** @config */
private static $priority = 40;
public function getHTML()
{
$linkClass = $this->isActive() ? 'ss-ui-button current' : 'ss-ui-button';
$linkTitle = _t('SilverStripe\\CMS\\Controllers\\ContentController.ARCHIVEDSITE', 'Preview version');
$recordLink = Convert::raw2att(Controller::join_links(
$this->record->AbsoluteLink(),
'?archiveDate=' . urlencode($this->record->LastEdited ?? '')
));
return "<a class=\"{$linkClass}\" href=\"$recordLink\" target=\"_blank\">$linkTitle</a>";
}
public function getTitle()
{
return _t('SilverStripe\\CMS\\Controllers\\SilverStripeNavigator.ARCHIVED', 'Archived');
}
public function getMessage()
{
$date = Versioned::current_archived_date();
if (empty($date)) {
return null;
}
/** @var DBDatetime $dateObj */
$dateObj = DBField::create_field('Datetime', $date);
$title = _t('SilverStripe\\CMS\\Controllers\\ContentController.NOTEWONTBESHOWN', 'Note: this message will not be shown to your visitors');
return "<div id=\"SilverStripeNavigatorMessage\" title=\"{$title}\">"
. _t('SilverStripe\\CMS\\Controllers\\ContentController.ARCHIVEDSITEFROM', 'Archived site from')
. "<br />" . $dateObj->Nice() . "</div>";
}
public function getLink()
{
$link = $this->record->PreviewLink();
return $link ? Controller::join_links($link, '?archiveDate=' . urlencode($this->record->LastEdited ?? '')) : '';
}
public function canView($member = null)
{
/** @var Versioned|DataObject $record */
$record = $this->record;
return (
$record->hasExtension(Versioned::class)
&& $record->hasStages()
&& $this->isArchived()
// Don't follow redirects in preview, they break the CMS editing form
&& !($record instanceof RedirectorPage)
&& $this->getLink()
);
}
public function isActive()
{
return $this->isArchived();
}
}

View File

@ -3,6 +3,7 @@
namespace SilverStripe\CMS\Controllers; namespace SilverStripe\CMS\Controllers;
use SilverStripe\Admin\LeftAndMain; use SilverStripe\Admin\LeftAndMain;
use SilverStripe\Admin\Navigator\SilverStripeNavigatorItem;
use SilverStripe\CMS\Model\RedirectorPage; use SilverStripe\CMS\Model\RedirectorPage;
use SilverStripe\Control\Controller; use SilverStripe\Control\Controller;

View File

@ -1,106 +0,0 @@
<?php
namespace SilverStripe\CMS\Controllers;
use SilverStripe\Control\Controller;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Convert;
use SilverStripe\Dev\Deprecation;
use SilverStripe\ORM\CMSPreviewable;
use SilverStripe\ORM\DataObject;
use SilverStripe\Versioned\Versioned;
/**
* Class will be moved from `silverstripe/cms` to `silverstripe/admin`.
* @deprecated 4.13.0 Will be renamed SilverStripe\VersionedAdmin\Navigator\SilverStripeNavigatorItem_LiveLink
*/
class SilverStripeNavigatorItem_LiveLink extends SilverStripeNavigatorItem
{
public function __construct(CMSPreviewable $record)
{
Deprecation::withNoReplacement(function () {
Deprecation::notice(
'4.13.0',
'Will be renamed SilverStripe\VersionedAdmin\Navigator\SilverStripeNavigatorItem_LiveLink',
Deprecation::SCOPE_CLASS
);
});
parent::__construct($record);
}
/** @config */
private static $priority = 30;
public function getHTML()
{
$livePage = $this->getLivePage();
if (!$livePage) {
return null;
}
$linkClass = $this->isActive() ? 'class="current" ' : '';
$linkTitle = _t('SilverStripe\\CMS\\Controllers\\ContentController.PUBLISHEDSITE', 'Published Site');
$recordLink = Convert::raw2att(Controller::join_links($livePage->AbsoluteLink(), "?stage=Live"));
return "<a {$linkClass} href=\"$recordLink\">$linkTitle</a>";
}
public function getTitle()
{
return _t(
'SilverStripe\\CMS\\Controllers\\ContentController.PUBLISHED',
'Published',
'Used for the Switch between draft and published view mode. Needs to be a short label'
);
}
public function getMessage()
{
return "<div id=\"SilverStripeNavigatorMessage\" title=\"" . _t(
'SilverStripe\\CMS\\Controllers\\ContentController.NOTEWONTBESHOWN',
'Note: this message will not be shown to your visitors'
) . "\">" . _t(
'SilverStripe\\CMS\\Controllers\\ContentController.PUBLISHEDSITE',
'Published Site'
) . "</div>";
}
public function getLink()
{
$link = $this->getLivePage()->PreviewLink();
return $link ? Controller::join_links($link, '?stage=Live') : '';
}
public function canView($member = null)
{
/** @var Versioned|DataObject $record */
$record = $this->record;
return (
$record->hasExtension(Versioned::class)
&& $this->showLiveLink()
&& $record->hasStages()
&& $this->getLivePage()
&& $this->getLink()
);
}
/**
* @return bool
*/
public function showLiveLink()
{
return (bool)Config::inst()->get(get_class($this->record), 'show_live_link');
}
public function isActive()
{
return (
(!Versioned::get_stage() || Versioned::get_stage() == 'Live')
&& !$this->isArchived()
);
}
protected function getLivePage()
{
$baseClass = $this->record->baseClass();
return Versioned::get_by_stage($baseClass, Versioned::LIVE)->byID($this->record->ID);
}
}

View File

@ -1,115 +0,0 @@
<?php
namespace SilverStripe\CMS\Controllers;
use SilverStripe\Control\Controller;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Convert;
use SilverStripe\Dev\Deprecation;
use SilverStripe\ORM\CMSPreviewable;
use SilverStripe\ORM\DataObject;
use SilverStripe\Versioned\Versioned;
use SiteTreeFutureState;
/**
* Class will be moved from `silverstripe/cms` to `silverstripe/admin`.
* @deprecated 4.13.0 Will be renamed SilverStripe\VersionedAdmin\Navigator\SilverStripeNavigatorItem_StageLink
*/
class SilverStripeNavigatorItem_StageLink extends SilverStripeNavigatorItem
{
public function __construct(CMSPreviewable $record)
{
Deprecation::withNoReplacement(function () {
Deprecation::notice(
'4.13.0',
'Will be renamed SilverStripe\VersionedAdmin\Navigator\SilverStripeNavigatorItem_StageLink',
Deprecation::SCOPE_CLASS
);
});
parent::__construct($record);
}
/** @config */
private static $priority = 20;
public function getHTML()
{
$draftPage = $this->getDraftPage();
if (!$draftPage) {
return null;
}
$linkClass = $this->isActive() ? 'class="current" ' : '';
$linkTitle = _t('SilverStripe\\CMS\\Controllers\\ContentController.DRAFTSITE', 'Draft Site');
$recordLink = Convert::raw2att(Controller::join_links($draftPage->AbsoluteLink(), "?stage=Stage"));
return "<a {$linkClass} href=\"$recordLink\">$linkTitle</a>";
}
public function getTitle()
{
return _t(
'SilverStripe\\CMS\\Controllers\\ContentController.DRAFT',
'Draft',
'Used for the Switch between draft and published view mode. Needs to be a short label'
);
}
public function getMessage()
{
return "<div id=\"SilverStripeNavigatorMessage\" title=\"" . _t(
'SilverStripe\\CMS\\Controllers\\ContentController.NOTEWONTBESHOWN',
'Note: this message will not be shown to your visitors'
) . "\">" . _t(
'SilverStripe\\CMS\\Controllers\\ContentController.DRAFTSITE',
'Draft Site'
) . "</div>";
}
public function getLink()
{
$date = Versioned::current_archived_date();
$link = $this->record->PreviewLink();
if (!$link) {
return '';
}
return Controller::join_links(
$link,
'?stage=Stage',
$date ? '?archiveDate=' . $date : null
);
}
public function canView($member = null)
{
/** @var Versioned|DataObject $record */
$record = $this->record;
return (
$record->hasExtension(Versioned::class)
&& $this->showStageLink()
&& $record->hasStages()
&& $this->getDraftPage()
&& $this->getLink()
);
}
/**
* @return bool
*/
public function showStageLink()
{
return (bool)Config::inst()->get(get_class($this->record), 'show_stage_link');
}
public function isActive()
{
return (
Versioned::get_stage() == 'Stage'
&& !(ClassInfo::exists('SiteTreeFutureState') && SiteTreeFutureState::get_future_datetime())
&& !$this->isArchived()
);
}
protected function getDraftPage()
{
$baseClass = $this->record->baseClass();
return Versioned::get_by_stage($baseClass, Versioned::DRAFT)->byID($this->record->ID);
}
}

View File

@ -1,98 +0,0 @@
<?php
namespace SilverStripe\CMS\Controllers;
use SilverStripe\CMS\Controllers\SilverStripeNavigatorItem;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Convert;
use SilverStripe\Dev\Deprecation;
use SilverStripe\ORM\CMSPreviewable;
use SilverStripe\Security\Member;
use SilverStripe\Versioned\Versioned;
/**
* Class will be moved from `silverstripe/cms` to `silverstripe/admin`.
* @deprecated 4.13.0 Will be renamed SilverStripe\Admin\Navigator\SilverStripeNavigatorItem_Unversioned
*/
class SilverStripeNavigatorItem_Unversioned extends SilverStripeNavigatorItem
{
public function __construct(CMSPreviewable $record)
{
Deprecation::withNoReplacement(function () {
Deprecation::notice(
'4.13.0',
'Will be renamed SilverStripe\Admin\Navigator\SilverStripeNavigatorItem_Unversioned',
Deprecation::SCOPE_CLASS
);
});
parent::__construct($record);
}
public function getHTML()
{
$recordLink = Convert::raw2att($this->getLink());
$linkTitle = _t('SilverStripe\\CMS\\Controllers\\ContentController.UNVERSIONEDPREVIEW', 'Preview');
return "<a class=\"current\" href=\"$recordLink\">$linkTitle</a>";
}
public function getLink()
{
return $this->getRecord()->PreviewLink() ?? '';
}
public function getTitle()
{
return _t(
'SilverStripe\\CMS\\Controllers\\ContentController.UNVERSIONEDPREVIEW',
'Preview',
'Used for the Switch between states (if any other other states are added). Needs to be a short label'
);
}
/**
* True if the record doesn't have the Versioned extension and is configured to display this item.
*
* @param Member $member
* @return bool
*/
public function canView($member = null)
{
return (
$this->recordIsUnversioned()
&& $this->showUnversionedLink()
&& $this->getLink()
);
}
private function recordIsUnversioned(): bool
{
$record = $this->getRecord();
// If the record has the Versioned extension, it can be considered unversioned
// for the purposes of this class if it has no stages and is not archived.
if ($record->hasExtension(Versioned::class)) {
return (!$record->hasStages()) && !$this->isArchived();
}
// Completely unversioned.
return true;
}
/**
* True if the record is configured to display this item.
*
* @return bool
*/
public function showUnversionedLink(): bool
{
return (bool) Config::inst()->get(get_class($this->record), 'show_unversioned_preview_link');
}
/**
* This item is always active, as there are unlikely to be other preview states available for the record.
*
* @return bool
*/
public function isActive()
{
return true;
}
}

View File

@ -134,7 +134,7 @@ class SiteTreeURLSegmentField extends TextField
*/ */
public function getURLPrefix() public function getURLPrefix()
{ {
return $this->urlPrefix; return rtrim($this->urlPrefix ?? '', '/') . '/';
} }
public function getURLSuffix() public function getURLSuffix()

View File

@ -18,8 +18,8 @@ use SilverStripe\Versioned\Versioned;
* @property string $RedirectionType Either 'Internal','External' or 'File' * @property string $RedirectionType Either 'Internal','External' or 'File'
* @property string $ExternalURL URL to redirect to if $RedirectionType is 'External' * @property string $ExternalURL URL to redirect to if $RedirectionType is 'External'
* @property int $LinkToID * @property int $LinkToID
* @method SiteTree LinkTo() Page to link to if $RedirectionType is 'Internal' * @method SiteTree LinkTo()
* @method File LinkToFile() File to link to if $RedirectionType is 'File' * @method File LinkToFile()
*/ */
class RedirectorPage extends Page class RedirectorPage extends Page
{ {
@ -164,7 +164,6 @@ class RedirectorPage extends Page
$this->HasBrokenLink = true; $this->HasBrokenLink = true;
} }
} else { } else {
// TODO implement checking of a remote site
$this->HasBrokenLink = false; $this->HasBrokenLink = false;
} }
} }

View File

@ -25,7 +25,6 @@ use SilverStripe\Core\Manifest\ModuleResource;
use SilverStripe\Core\Manifest\ModuleResourceLoader; use SilverStripe\Core\Manifest\ModuleResourceLoader;
use SilverStripe\Core\Manifest\VersionProvider; use SilverStripe\Core\Manifest\VersionProvider;
use SilverStripe\Core\Resettable; use SilverStripe\Core\Resettable;
use SilverStripe\Dev\Deprecation;
use SilverStripe\Forms\CheckboxField; use SilverStripe\Forms\CheckboxField;
use SilverStripe\Forms\CompositeField; use SilverStripe\Forms\CompositeField;
use SilverStripe\Forms\DropdownField; use SilverStripe\Forms\DropdownField;
@ -36,6 +35,7 @@ use SilverStripe\Forms\GridField\GridField;
use SilverStripe\Forms\GridField\GridFieldDataColumns; use SilverStripe\Forms\GridField\GridFieldDataColumns;
use SilverStripe\Forms\GridField\GridFieldLazyLoader; use SilverStripe\Forms\GridField\GridFieldLazyLoader;
use SilverStripe\Forms\HTMLEditor\HTMLEditorField; use SilverStripe\Forms\HTMLEditor\HTMLEditorField;
use SilverStripe\Forms\ListboxField;
use SilverStripe\Forms\LiteralField; use SilverStripe\Forms\LiteralField;
use SilverStripe\Forms\OptionsetField; use SilverStripe\Forms\OptionsetField;
use SilverStripe\Forms\Tab; use SilverStripe\Forms\Tab;
@ -102,17 +102,14 @@ use SilverStripe\View\SSViewer;
* @property bool $HasBrokenFile True if this page has a broken file shortcode * @property bool $HasBrokenFile True if this page has a broken file shortcode
* @property bool $HasBrokenLink True if this page has a broken page shortcode * @property bool $HasBrokenLink True if this page has a broken page shortcode
* *
* @method ManyManyList ViewerGroups() List of groups that can view this object.
* @method ManyManyList EditorGroups() List of groups that can edit this object.
* @method SiteTree Parent()
* @method HasManyList|SiteTreeLink[] BackLinks() List of SiteTreeLink objects attached to this page
*
* @mixin Hierarchy * @mixin Hierarchy
* @mixin Versioned * @mixin Versioned
* @mixin RecursivePublishable * @mixin RecursivePublishable
* @mixin SiteTreeLinkTracking Added via linktracking.yml to DataObject directly * @mixin SiteTreeLinkTracking Added via linktracking.yml to DataObject directly
* @mixin FileLinkTracking Added via filetracking.yml in silverstripe/assets * @mixin FileLinkTracking Added via filetracking.yml in silverstripe/assets
* @mixin InheritedPermissionsExtension * @mixin InheritedPermissionsExtension
* @method HasManyList<SiteTreeLink> BackLinks()
* @method HasManyList<VirtualPage> VirtualPages()
*/ */
class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvider, CMSPreviewable, Resettable, Flushable, MemberCacheFlusher class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvider, CMSPreviewable, Resettable, Flushable, MemberCacheFlusher
{ {
@ -639,7 +636,7 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi
if ($this->hasMethod('alternateAbsoluteLink')) { if ($this->hasMethod('alternateAbsoluteLink')) {
return $this->alternateAbsoluteLink($action); return $this->alternateAbsoluteLink($action);
} else { } else {
return Director::absoluteURL($this->Link($action)); return Director::absoluteURL((string) $this->Link($action));
} }
} }
@ -652,13 +649,6 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi
*/ */
public function PreviewLink($action = null) public function PreviewLink($action = null)
{ {
if ($this->hasMethod('alternatePreviewLink')) {
Deprecation::withNoReplacement(function () use ($action) {
Deprecation::notice('5.0', 'Use updatePreviewLink or override PreviewLink method');
return $this->alternatePreviewLink($action);
});
}
$link = $this->AbsoluteLink($action); $link = $this->AbsoluteLink($action);
$this->extend('updatePreviewLink', $link, $action); $this->extend('updatePreviewLink', $link, $action);
return $link; return $link;
@ -699,15 +689,17 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi
$base = $this->URLSegment; $base = $this->URLSegment;
} }
$this->extend('updateRelativeLink', $base, $action);
// Legacy support: If $action === true, retain URLSegment for homepages, // Legacy support: If $action === true, retain URLSegment for homepages,
// but don't append any action // but don't append any action
if ($action === true) { if ($action === true) {
$action = null; $action = null;
} }
return Controller::join_links($base, '/', $action); $link = Controller::join_links($base, $action);
$this->extend('updateRelativeLink', $link, $base, $action);
return $link;
} }
/** /**
@ -1193,6 +1185,14 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi
return true; return true;
} }
// check for specific users
if ($this->CanViewType === InheritedPermissions::ONLY_THESE_MEMBERS
&& $member
&& $this->ViewerMembers()->filter('ID', $member->ID)->count() > 0
) {
return true;
}
return false; return false;
} }
@ -1960,7 +1960,6 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi
*/ */
public function BackLinkTracking() public function BackLinkTracking()
{ {
// @todo - Implement PolymorphicManyManyList to replace this
$list = ArrayList::create(); $list = ArrayList::create();
$siteTreelinkTable = SiteTreeLink::singleton()->baseTable(); $siteTreelinkTable = SiteTreeLink::singleton()->baseTable();
@ -2250,6 +2249,16 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi
$viewAllGroupsMap = $mapFn(Permission::get_groups_by_permission(['SITETREE_VIEW_ALL', 'ADMIN'])); $viewAllGroupsMap = $mapFn(Permission::get_groups_by_permission(['SITETREE_VIEW_ALL', 'ADMIN']));
$editAllGroupsMap = $mapFn(Permission::get_groups_by_permission(['SITETREE_EDIT_ALL', 'ADMIN'])); $editAllGroupsMap = $mapFn(Permission::get_groups_by_permission(['SITETREE_EDIT_ALL', 'ADMIN']));
// $membersMap is limited to 100 records specifically so that it does not crash the front-end
// if the website has a large number of Members, which is likely to happen if the website also
// uses the Member table for non-cms public users
// This limit should be removed if the ListboxField front-end component is switched out or
// modified so that it does not load all users at once and instead uses XHR to fetch a subset
// of users based on what the user types in
$membersMap = Member::get()
->limit(100)
->map('ID', 'Name');
$fields = new FieldList( $fields = new FieldList(
$rootTab = new TabSet( $rootTab = new TabSet(
"Root", "Root",
@ -2280,6 +2289,11 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi
_t(__CLASS__.'.VIEWERGROUPS', "Viewer Groups"), _t(__CLASS__.'.VIEWERGROUPS', "Viewer Groups"),
Group::class Group::class
), ),
$viewerMembersField = ListboxField::create(
"ViewerMembers",
_t(__CLASS__.'.VIEWERMEMBERS', "Viewer Users"),
$membersMap,
),
$editorsOptionsField = new OptionsetField( $editorsOptionsField = new OptionsetField(
"CanEditType", "CanEditType",
_t(__CLASS__.'.EDITHEADER', "Who can edit this page?") _t(__CLASS__.'.EDITHEADER', "Who can edit this page?")
@ -2288,6 +2302,11 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi
"EditorGroups", "EditorGroups",
_t(__CLASS__.'.EDITORGROUPS', "Editor Groups"), _t(__CLASS__.'.EDITORGROUPS', "Editor Groups"),
Group::class Group::class
),
$editorMembersField = ListboxField::create(
"EditorMembers",
_t(__CLASS__.'.EDITORMEMBERS', "Editor Users"),
$membersMap
) )
) )
) )
@ -2328,6 +2347,10 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi
__CLASS__.'.ACCESSONLYTHESE', __CLASS__.'.ACCESSONLYTHESE',
"Only these groups (choose from list)" "Only these groups (choose from list)"
), ),
InheritedPermissions::ONLY_THESE_MEMBERS => _t(
__CLASS__.'.ACCESSONLYMEMBERS',
"Only these users (choose from list)"
),
]; ];
$viewersOptionsField->setSource($viewersOptionsSource); $viewersOptionsField->setSource($viewersOptionsSource);
@ -2354,17 +2377,27 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi
if (!Permission::check('SITETREE_GRANT_ACCESS')) { if (!Permission::check('SITETREE_GRANT_ACCESS')) {
$fields->makeFieldReadonly($viewersOptionsField); $fields->makeFieldReadonly($viewersOptionsField);
if ($this->CanEditType === InheritedPermissions::ONLY_THESE_USERS) { if ($this->CanViewType === InheritedPermissions::ONLY_THESE_USERS) {
$fields->makeFieldReadonly($viewerGroupsField); $fields->makeFieldReadonly($viewerGroupsField);
$fields->removeByName('ViewerMembers');
} elseif ($this->CanViewType === InheritedPermissions::ONLY_THESE_MEMBERS) {
$fields->makeFieldReadonly($viewerMembersField);
$fields->removeByName('ViewerGroups');
} else { } else {
$fields->removeByName('ViewerGroups'); $fields->removeByName('ViewerGroups');
$fields->removeByName('ViewerMembers');
} }
$fields->makeFieldReadonly($editorsOptionsField); $fields->makeFieldReadonly($editorsOptionsField);
if ($this->CanEditType === InheritedPermissions::ONLY_THESE_USERS) { if ($this->CanEditType === InheritedPermissions::ONLY_THESE_USERS) {
$fields->makeFieldReadonly($editorGroupsField); $fields->makeFieldReadonly($editorGroupsField);
$fields->removeByName('EditorMembers');
} elseif ($this->CanEditType === InheritedPermissions::ONLY_THESE_MEMBERS) {
$fields->makeFieldReadonly($editorMembersField);
$fields->removeByName('EditorGroups');
} else { } else {
$fields->removeByName('EditorGroups'); $fields->removeByName('EditorGroups');
$fields->removeByName('EditorMembers');
} }
} }
@ -2473,7 +2506,6 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi
// "readonly"/viewing version that isn't the current version of the record // "readonly"/viewing version that isn't the current version of the record
/** @var SiteTree $stageRecord */ /** @var SiteTree $stageRecord */
$stageRecord = Versioned::get_by_stage(static::class, Versioned::DRAFT)->byID($this->ID); $stageRecord = Versioned::get_by_stage(static::class, Versioned::DRAFT)->byID($this->ID);
/** @skipUpgrade */
if ($stageRecord && $stageRecord->Version != $this->Version) { if ($stageRecord && $stageRecord->Version != $this->Version) {
$moreOptions->push(FormAction::create('email', _t('SilverStripe\\CMS\\Controllers\\CMSMain.EMAIL', 'Email'))); $moreOptions->push(FormAction::create('email', _t('SilverStripe\\CMS\\Controllers\\CMSMain.EMAIL', 'Email')));
$moreOptions->push(FormAction::create('rollback', _t('SilverStripe\\CMS\\Controllers\\CMSMain.ROLLBACK', 'Roll back to this version'))); $moreOptions->push(FormAction::create('rollback', _t('SilverStripe\\CMS\\Controllers\\CMSMain.ROLLBACK', 'Roll back to this version')));
@ -2518,7 +2550,7 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi
// Note: It would be nice to have a canRestore() permission at some point // Note: It would be nice to have a canRestore() permission at some point
if ($canEdit && !$isOnDraft && !$isPublished) { if ($canEdit && !$isOnDraft && !$isPublished) {
// Determine if we should force a restore to root (where once it was a subpage) // Determine if we should force a restore to root (where once it was a subpage)
$restoreToRoot = $this->isParentArchived(); $restoreToRoot = $this->isParentArchived() && $this->config()->get('can_be_root');
// "restore" // "restore"
$title = $restoreToRoot $title = $restoreToRoot
@ -2527,6 +2559,7 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi
$description = $restoreToRoot $description = $restoreToRoot
? _t('SilverStripe\\CMS\\Controllers\\CMSMain.RESTORE_TO_ROOT_DESC', 'Restore the archived version to draft as a top level page') ? _t('SilverStripe\\CMS\\Controllers\\CMSMain.RESTORE_TO_ROOT_DESC', 'Restore the archived version to draft as a top level page')
: _t('SilverStripe\\CMS\\Controllers\\CMSMain.RESTORE_DESC', 'Restore the archived version to draft'); : _t('SilverStripe\\CMS\\Controllers\\CMSMain.RESTORE_DESC', 'Restore the archived version to draft');
if (!$this->isParentArchived() || $restoreToRoot) {
$majorActions->push( $majorActions->push(
FormAction::create('restore', $title) FormAction::create('restore', $title)
->setDescription($description) ->setDescription($description)
@ -2535,6 +2568,7 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi
->setUseButtonTag(true) ->setUseButtonTag(true)
); );
} }
}
// If a page is on any stage it can be archived // If a page is on any stage it can be archived
if (($isOnDraft || $isPublished) && $this->canArchive()) { if (($isOnDraft || $isPublished) && $this->canArchive()) {
@ -2795,35 +2829,6 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi
return $allowedChildren; return $allowedChildren;
} }
/**
* @deprecated 4.12.0 Use creatableChildPages() instead
*
* Gets a list of the page types that can be created under this specific page
*
* @return array
*/
public function creatableChildren()
{
Deprecation::notice('4.12.0', 'Use creatableChildPages() instead');
// Build the list of candidate children
$cache = SiteTree::singleton()->getCreatableChildrenCache();
$cacheKey = $this->generateChildrenCacheKey(Security::getCurrentUser() ? Security::getCurrentUser()->ID : 0);
$children = $cache->get($cacheKey, []);
if (!$children || !isset($children[$this->ID])) {
$children[$this->ID] = [];
$candidates = static::page_type_classes();
foreach ($candidates as $childClass) {
$child = singleton($childClass);
if ($child->canCreate(null, ['Parent' => $this])) {
$children[$this->ID][$childClass] = $child->i18n_singular_name();
}
}
$cache->set($cacheKey, $children);
}
return $children[$this->ID];
}
/** /**
* *
* Gets a list of the page types that can be created under this specific page, including font icons * Gets a list of the page types that can be created under this specific page, including font icons
@ -3072,14 +3077,6 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi
// If we have a class of "{$ClassName}Controller" then we found our controller // If we have a class of "{$ClassName}Controller" then we found our controller
if (class_exists($candidate = sprintf('%sController', $class))) { if (class_exists($candidate = sprintf('%sController', $class))) {
return $candidate; return $candidate;
} elseif (class_exists($candidate = sprintf('%s_Controller', $class))) {
// Support the legacy underscored filename, but raise a deprecation notice
Deprecation::notice(
'5.0',
'Underscored controller class names are deprecated. Use "MyController" instead of "My_Controller".',
Deprecation::SCOPE_GLOBAL
);
return $candidate;
} elseif (is_array($namespaceMap)) { } elseif (is_array($namespaceMap)) {
foreach ($namespaceMap as $pageNamespace => $controllerNamespace) { foreach ($namespaceMap as $pageNamespace => $controllerNamespace) {
if (strpos($class, $pageNamespace) !== 0) { if (strpos($class, $pageNamespace) !== 0) {
@ -3343,7 +3340,7 @@ class SiteTree extends DataObject implements PermissionProvider, i18nEntityProvi
} }
/** /**
* Cache key for creatableChildren() method * Cache key for creatableChildPages() method
* *
* @param int $memberID * @param int $memberID
* @return string * @return string

View File

@ -75,13 +75,15 @@ abstract class SiteTreeExtension extends DataExtension
* before {@link SiteTree::RelativeLink()} calls {@link Controller::join_links()} * before {@link SiteTree::RelativeLink()} calls {@link Controller::join_links()}
* on the $base and $action * on the $base and $action
* *
* @param string &$base The URL of this page relative to siteroot, not including * @param string &$link The URL of this page relative to siteroot including
* the action * the action
* @param string|boolean &$action The action or subpage called on this page. * @param string $base The URL of this page relative to siteroot, not including
* the action
* @param string|boolean $action The action or subpage called on this page.
* (Legacy support) If this is true, then do not reduce the 'home' urlsegment * (Legacy support) If this is true, then do not reduce the 'home' urlsegment
* to an empty link * to an empty link
*/ */
public function updateRelativeLink(&$base, &$action) public function updateRelativeLink(&$link, $base, $action)
{ {
} }
} }

View File

@ -1,35 +0,0 @@
<?php
namespace SilverStripe\CMS\Model;
use SilverStripe\Dev\Deprecation;
use SilverStripe\Assets\File;
use SilverStripe\ORM\DataExtension;
use SilverStripe\View\SSViewer;
/**
* @deprecated 4.2.0 Use FileLinkTracking instead
* @property File $owner
*/
class SiteTreeFileExtension extends DataExtension
{
private static $casting = [
'BackLinkHTMLList' => 'HTMLFragment'
];
/**
* Generate an HTML list which provides links to where a file is used.
*
* @return string
*/
public function __construct()
{
Deprecation::notice('4.2.0', 'Use FileLinkTracking instead', Deprecation::SCOPE_CLASS);
}
public function BackLinkHTMLList()
{
$viewer = SSViewer::create(['type' => 'Includes', self::class . '_description']);
return $viewer->process($this->owner);
}
}

View File

@ -1,50 +0,0 @@
<?php
namespace SilverStripe\CMS\Model;
use SilverStripe\Assets\File;
use SilverStripe\Dev\Deprecation;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\Tab;
use SilverStripe\Forms\TabSet;
use SilverStripe\ORM\DataExtension;
use SilverStripe\Admin\Forms\UsedOnTable;
use SilverStripe\Versioned\RecursivePublishable;
/**
* @deprecated 4.12.0 Use UsedOnTable instead
*
* Extension applied to {@see FileFormFactory} to decorate with a "Used on:" information area.
* Uses tracking provided by {@see SiteTreeFileExtension} to generate this.
*
* @property File $owner
* @deprecated 4.12.0 Use UsedOnTable instead
*/
class SiteTreeFileFormFactoryExtension extends DataExtension
{
public function __construct()
{
Deprecation::notice('4.12.0', 'Use UsedOnTable instead', Deprecation::SCOPE_CLASS);
}
/**
* @deprecated 4.12.0 Use UsedOnTable instead
*/
public function updateFormFields(FieldList $fields, $controller, $formName, $context)
{
Deprecation::notice('4.12.0', 'Use UsedOnTable instead');
/** @var TabSet $tabset */
$tabset = $fields->fieldByName('Editor');
if (!$tabset) {
return;
}
$usedOnField = UsedOnTable::create('UsedOnTableReplacement');
$usedOnField->setRecord($context['Record']);
// Add field to new tab
/** @var Tab $tab */
$tab = Tab::create('Usage', _t(__CLASS__ . '.USAGE', 'Usage'), $usedOnField);
$tabset->push($tab);
}
}

View File

@ -1,88 +0,0 @@
<?php
namespace SilverStripe\CMS\Model;
use SilverStripe\Assets\File;
use SilverStripe\Assets\Folder;
use SilverStripe\Assets\Shortcodes\FileLink;
use SilverStripe\Core\ClassInfo;
use SilverStripe\Core\Config\Config;
use SilverStripe\Core\Convert;
use SilverStripe\Dev\Deprecation;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\DataExtension;
use SilverStripe\ORM\DataList;
use SilverStripe\ORM\DataObject;
/**
* @deprecated 4.2.0 Will be removed without equivalent functionality to replace it
*/
class SiteTreeFolderExtension extends DataExtension
{
public function __construct()
{
Deprecation::notice('4.2.0', 'Will be removed without equivalent functionality to replace it', Deprecation::SCOPE_CLASS);
parent::__construct();
}
/**
* Looks for files used in system and create where clause which contains all ID's of files.
*
* @deprecated 4.2.0 Will be removed without equivalent functionality to replace it
* @returns string where clause which will work as filter.
*/
public function getUnusedFilesListFilter()
{
Deprecation::notice('4.2.0', 'Will be removed without equivalent functionality to replace it');
// Add all records in link tracking
$usedFiles = FileLink::get()->column('LinkedID');
// Get all classes that aren't folder
$fileClasses = array_diff_key(
ClassInfo::subclassesFor(File::class) ?? [],
ClassInfo::subclassesFor(Folder::class)
);
// Search on a class-by-class basis
$classes = ClassInfo::subclassesFor(SiteTree::class);
$schema = DataObject::getSchema();
foreach ($classes as $className) {
// Build query based on all direct has_ones on this class
$hasOnes = Config::inst()->get($className, 'has_one', Config::UNINHERITED);
if (empty($hasOnes)) {
continue;
}
$where = [];
$columns = [];
foreach ($hasOnes as $relName => $joinClass) {
if (in_array($joinClass, $fileClasses ?? [])) {
$column = $relName . 'ID';
$columns[] = $column;
$quotedColumn = $schema->sqlColumnForField($className, $column);
$where[] = "{$quotedColumn} > 0";
}
}
// Get all records with any file ID in the searched columns
$recordsArray = DataList::create($className)->whereAny($where)->toArray();
$records = ArrayList::create($recordsArray);
foreach ($columns as $column) {
$usedFiles = array_unique(array_merge($usedFiles, $records->column($column)));
}
}
// Create filter based on class and id
$classFilter = sprintf(
"(\"File\".\"ClassName\" IN (%s))",
implode(", ", Convert::raw2sql($fileClasses, true))
);
if ($usedFiles) {
return "\"File\".\"ID\" NOT IN (" . implode(', ', $usedFiles) . ") AND $classFilter";
} else {
return $classFilter;
}
}
}

View File

@ -7,10 +7,8 @@ use SilverStripe\ORM\DataObject;
/** /**
* Represents a link between a dataobject parent and a page in a HTML content area * Represents a link between a dataobject parent and a page in a HTML content area
* *
* @method DataObject Parent() Parent object * @method SiteTree Linked()
* @method SiteTree Linked() Page being linked to * @method DataObject Parent()
*
* Run `MigrateSiteTreeLinkingTask` to migrate from old table to this.
*/ */
class SiteTreeLink extends DataObject class SiteTreeLink extends DataObject
{ {

View File

@ -27,7 +27,7 @@ use SilverStripe\View\Parsers\HTMLValue;
* field to your `db` config and this extension will ensure it's flagged appropriately. * field to your `db` config and this extension will ensure it's flagged appropriately.
* *
* @property DataObject|SiteTreeLinkTracking $owner * @property DataObject|SiteTreeLinkTracking $owner
* @method ManyManyThroughList LinkTracking() List of site pages linked on this dataobject * @method ManyManyThroughList<SiteTree> LinkTracking()
*/ */
class SiteTreeLinkTracking extends DataExtension class SiteTreeLinkTracking extends DataExtension
{ {

View File

@ -4,7 +4,6 @@ namespace SilverStripe\CMS\Model;
use Page; use Page;
use SilverStripe\Core\Convert; use SilverStripe\Core\Convert;
use SilverStripe\Dev\Deprecation;
use SilverStripe\Forms\FieldList; use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\LiteralField; use SilverStripe\Forms\LiteralField;
use SilverStripe\Forms\ReadonlyTransformation; use SilverStripe\Forms\ReadonlyTransformation;
@ -22,8 +21,8 @@ use SilverStripe\View\HTML;
* *
* Note: This Only duplicates $db fields and not the $has_one etc.. * Note: This Only duplicates $db fields and not the $has_one etc..
* *
* @method SiteTree CopyContentFrom()
* @property int $CopyContentFromID * @property int $CopyContentFromID
* @method SiteTree CopyContentFrom()
*/ */
class VirtualPage extends Page class VirtualPage extends Page
{ {
@ -360,30 +359,6 @@ class VirtualPage extends Page
return $result; return $result;
} }
/**
* @deprecated 4.2.0 Will be removed without equivalent functionality to replace it
*/
public function updateImageTracking()
{
Deprecation::notice('4.2.0', 'Will be removed without equivalent functionality to replace it');
// Doesn't work on unsaved records
if (!$this->isInDB()) {
return;
}
// Remove CopyContentFrom() from the cache
unset($this->components['CopyContentFrom']);
// Update ImageTracking
$copyContentFrom = $this->CopyContentFrom();
if (!$copyContentFrom || !$copyContentFrom->isInDB()) {
return;
}
$this->FileTracking()->setByIDList($copyContentFrom->FileTracking()->column('ID'));
}
public function CMSTreeClasses() public function CMSTreeClasses()
{ {
$parentClass = sprintf( $parentClass = sprintf(

View File

@ -46,7 +46,7 @@ class BrokenFilesReport extends Report
{ {
return [ return [
"Title" => [ "Title" => [
"title" => "Title", // todo: use NestedTitle(2) "title" => "Title",
"link" => true, "link" => true,
], ],
]; ];

View File

@ -39,7 +39,7 @@ class BrokenRedirectorPagesReport extends Report
{ {
return [ return [
"Title" => [ "Title" => [
"title" => "Title", // todo: use NestedTitle(2) "title" => "Title",
"link" => true, "link" => true,
], ],
]; ];

View File

@ -39,7 +39,7 @@ class BrokenVirtualPagesReport extends Report
{ {
return [ return [
"Title" => [ "Title" => [
"title" => "Title", // todo: use NestedTitle(2) "title" => "Title",
"link" => true, "link" => true,
], ],
]; ];

View File

@ -43,7 +43,7 @@ class EmptyPagesReport extends Report
{ {
return [ return [
"Title" => [ "Title" => [
"title" => "Title", // todo: use NestedTitle(2) "title" => "Title",
"link" => true, "link" => true,
], ],
]; ];

View File

@ -31,14 +31,14 @@ class RecentlyEditedReport extends Report
$threshold = strtotime('-14 days', DBDatetime::now()->getTimestamp()); $threshold = strtotime('-14 days', DBDatetime::now()->getTimestamp());
return SiteTree::get() return SiteTree::get()
->filter('LastEdited:GreaterThan', date("Y-m-d H:i:s", $threshold)) ->filter('LastEdited:GreaterThan', date("Y-m-d H:i:s", $threshold))
->sort("\"$tableName\".\"LastEdited\" DESC"); ->orderBy("\"$tableName\".\"LastEdited\" DESC");
} }
public function columns() public function columns()
{ {
return [ return [
"Title" => [ "Title" => [
"title" => "Title", // todo: use NestedTitle(2) "title" => "Title",
"link" => true, "link" => true,
], ],
]; ];

View File

@ -39,7 +39,6 @@ class ContentControllerSearchExtension extends Extension
$actions = FieldList::create( $actions = FieldList::create(
FormAction::create('results', _t('SilverStripe\\CMS\\Search\\SearchForm.GO', 'Go')) FormAction::create('results', _t('SilverStripe\\CMS\\Search\\SearchForm.GO', 'Go'))
); );
/** @skipUpgrade */
$form = SearchForm::create($this->owner, 'SearchForm', $fields, $actions); $form = SearchForm::create($this->owner, 'SearchForm', $fields, $actions);
$form->classesToSearch(FulltextSearchable::get_searchable_classes()); $form->classesToSearch(FulltextSearchable::get_searchable_classes());
return $form; return $form;

View File

@ -13,17 +13,11 @@ use SilverStripe\Forms\HiddenField;
use SilverStripe\Forms\TextField; use SilverStripe\Forms\TextField;
use SilverStripe\ORM\DB; use SilverStripe\ORM\DB;
use SilverStripe\ORM\SS_List; use SilverStripe\ORM\SS_List;
use Translatable;
/** /**
* Standard basic search form which conducts a fulltext search on all {@link SiteTree} * Standard basic search form which conducts a fulltext search on all {@link SiteTree}
* objects. * objects.
* *
* If multilingual content is enabled through the {@link Translatable} extension,
* only pages the currently set language on the holder for this searchform are found.
* The language is set through a hidden field in the form, which is prepoluated
* with {@link Translatable::get_current_locale()} when then form is constructed.
*
* @see Use ModelController and SearchContext for a more generic search implementation based around DataObject * @see Use ModelController and SearchContext for a more generic search implementation based around DataObject
*/ */
class SearchForm extends Form class SearchForm extends Form
@ -51,7 +45,6 @@ class SearchForm extends Form
]; ];
/** /**
* @skipUpgrade
* @param RequestHandler $controller * @param RequestHandler $controller
* @param string $name The name of the form (used in URL addressing) * @param string $name The name of the form (used in URL addressing)
* @param FieldList $fields Optional, defaults to a single field named "Search". Search logic needs to be customized * @param FieldList $fields Optional, defaults to a single field named "Search". Search logic needs to be customized
@ -70,12 +63,6 @@ class SearchForm extends Form
); );
} }
if (class_exists('Translatable')
&& SiteTree::singleton()->hasExtension('Translatable')
) {
$fields->push(new HiddenField('searchlocale', 'searchlocale', Translatable::get_current_locale()));
}
if (!$actions) { if (!$actions) {
$actions = new FieldList( $actions = new FieldList(
new FormAction("results", _t(__CLASS__.'.GO', 'Go')) new FormAction("results", _t(__CLASS__.'.GO', 'Go'))
@ -130,22 +117,6 @@ class SearchForm extends Form
// Get request data from request handler // Get request data from request handler
$request = $this->getRequestHandler()->getRequest(); $request = $this->getRequestHandler()->getRequest();
// set language (if present)
$locale = null;
$origLocale = null;
if (class_exists('Translatable')) {
$locale = $request->requestVar('searchlocale');
if (SiteTree::singleton()->hasExtension('Translatable') && $locale) {
if ($locale === "ALL") {
Translatable::disable_locale_filter();
} else {
$origLocale = Translatable::get_current_locale();
Translatable::set_current_locale($locale);
}
}
}
$keywords = $request->requestVar('Search'); $keywords = $request->requestVar('Search');
$andProcessor = function ($matches) { $andProcessor = function ($matches) {
@ -181,17 +152,6 @@ class SearchForm extends Form
} }
} }
// reset locale
if (class_exists('Translatable')) {
if (SiteTree::singleton()->hasExtension('Translatable') && $locale) {
if ($locale == "ALL") {
Translatable::enable_locale_filter();
} else {
Translatable::set_current_locale($origLocale);
}
}
}
return $results; return $results;
} }

View File

@ -1,70 +0,0 @@
<?php
namespace SilverStripe\CMS\Tasks;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Dev\BuildTask;
use SilverStripe\Dev\Debug;
use SilverStripe\Dev\Deprecation;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DB;
use SilverStripe\Versioned\Versioned;
/**
* Updates legacy SiteTree link tracking into new polymorphic many_many relation.
* This should be done for any site upgrading to 4.2.0
*
* @deprecated 4.13.0 Will be removed without equivalent functionality to replace it
*/
class MigrateSiteTreeLinkingTask extends BuildTask
{
private static $segment = 'MigrateSiteTreeLinkingTask';
protected $title = 'Migrate SiteTree Linking Task';
protected $description = 'Updates legacy SiteTree link tracking into new polymorphic many_many relation';
public function __construct()
{
Deprecation::notice(
'4.13.0',
'Will be removed without equivalent functionality to replace it',
Deprecation::SCOPE_CLASS
);
}
public function run($request)
{
// Ensure legacy table exists
$exists = DB::get_conn()->getSchemaManager()->hasTable('SiteTree_LinkTracking');
if (!$exists) {
DB::alteration_message("Table SiteTree_LinkTracking has already been migrated, or doesn't exist");
return;
}
$pages = 0;
// Ensure sync occurs on draft
Versioned::withVersionedMode(function () use (&$pages) {
Versioned::set_stage(Versioned::DRAFT);
$sitetreeTbl = DataObject::singleton(SiteTree::class)->baseTable();
/** @var SiteTree[] $linkedPages */
$linkedPages = SiteTree::get()
->innerJoin(
'SiteTree_LinkTracking',
"\"SiteTree_LinkTracking\".\"SiteTreeID\" = \"$sitetreeTbl\".\"ID\""
);
foreach ($linkedPages as $page) {
// Command page to update symlink tracking
$page->syncLinkTracking();
$pages++;
}
});
DB::alteration_message("Migrated page links on " . SiteTree::singleton()->i18n_pluralise($pages));
// Disable table to prevent double-migration
DB::dont_require_table('SiteTree_LinkTracking');
}
}

View File

@ -1,388 +0,0 @@
<?php
namespace SilverStripe\CMS\Tasks;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Control\Controller;
use SilverStripe\Forms\CheckboxSetField;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\Form;
use SilverStripe\Forms\FormAction;
use SilverStripe\Forms\HeaderField;
use SilverStripe\Forms\LiteralField;
use SilverStripe\Forms\OptionsetField;
use SilverStripe\ORM\ArrayList;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\SS_List;
use SilverStripe\Versioned\Versioned;
use SilverStripe\Security\Permission;
use SilverStripe\Security\Security;
use SilverStripe\View\Requirements;
use SilverStripe\Dev\Deprecation;
/**
* Identify "orphaned" pages which point to a parent
* that no longer exists in a specific stage.
* Shows the pages to an administrator, who can then
* decide which pages to remove by ticking a checkbox
* and manually executing the removal.
*
* Caution: Pages also count as orphans if they don't
* have parents in this stage, even if the parent has a representation
* in the other stage:
* - A live child is orphaned if its parent was deleted from live, but still exists on stage
* - A stage child is orphaned if its parent was deleted from stage, but still exists on live
*
* See {@link RemoveOrphanedPagesTaskTest} for an example sitetree
* before and after orphan removal.
*
* @author Ingo Schommer (<firstname>@silverstripe.com), SilverStripe Ltd.
*
* @deprecated 4.13.0 Will be removed without equivalent functionality to replace it
*/
class RemoveOrphanedPagesTask extends Controller
{
private static $allowed_actions = [
'index' => 'ADMIN',
'Form' => 'ADMIN',
'run' => 'ADMIN',
'handleAction' => 'ADMIN',
];
protected $title = 'Removed orphaned pages without existing parents from both stage and live';
protected $description = "
<p>
Identify 'orphaned' pages which point to a parent
that no longer exists in a specific stage.
</p>
<p>
Caution: Pages also count as orphans if they don't
have parents in this stage, even if the parent has a representation
in the other stage:<br />
- A live child is orphaned if its parent was deleted from live, but still exists on stage<br />
- A stage child is orphaned if its parent was deleted from stage, but still exists on live
</p>
";
protected $orphanedSearchClass = SiteTree::class;
public function __construct()
{
Deprecation::notice(
'4.13.0',
'Will be removed without equivalent functionality to replace it',
Deprecation::SCOPE_CLASS
);
}
protected function init()
{
parent::init();
if (!Permission::check('ADMIN')) {
Security::permissionFailure($this);
}
}
public function Link($action = null)
{
/** @skipUpgrade */
return Controller::join_links('RemoveOrphanedPagesTask', $action, '/');
}
public function index()
{
Requirements::javascript('http://code.jquery.com/jquery-1.7.2.min.js');
Requirements::customCSS('#OrphanIDs .middleColumn {width: auto;}');
Requirements::customCSS('#OrphanIDs label {display: inline;}');
return $this->renderWith('BlankPage');
}
public function Form()
{
$fields = new FieldList();
$source = [];
$fields->push(new HeaderField(
'Header',
_t(__CLASS__ . '.HEADER', 'Remove all orphaned pages task')
));
$fields->push(new LiteralField(
'Description',
$this->description
));
$orphans = $this->getOrphanedPages($this->orphanedSearchClass);
if ($orphans) {
foreach ($orphans as $orphan) {
/** @var SiteTree $latestVersion */
$latestVersion = Versioned::get_latest_version($this->orphanedSearchClass, $orphan->ID);
$latestAuthor = DataObject::get_by_id('SilverStripe\\Security\\Member', $latestVersion->AuthorID);
$orphanBaseTable = DataObject::getSchema()->baseDataTable($this->orphanedSearchClass);
$liveRecord = Versioned::get_one_by_stage(
$this->orphanedSearchClass,
'Live',
["\"$orphanBaseTable\".\"ID\"" => $orphan->ID]
);
$label = sprintf(
'<a href="admin/pages/edit/show/%d">%s</a> <small>(#%d, Last Modified Date: %s, Last Modifier: %s, %s)</small>',
$orphan->ID,
$orphan->Title,
$orphan->ID,
$orphan->dbObject('LastEdited')->Nice(),
($latestAuthor) ? $latestAuthor->Title : 'unknown',
($liveRecord) ? 'is published' : 'not published'
);
$source[$orphan->ID] = $label;
}
}
if ($orphans && $orphans->count()) {
$fields->push(new CheckboxSetField('OrphanIDs', false, $source));
$fields->push(new LiteralField(
'SelectAllLiteral',
sprintf(
'<p><a href="#" onclick="javascript:jQuery(\'#Form_Form_OrphanIDs :checkbox\').attr(\'checked\', \'checked\'); return false;">%s</a>&nbsp;',
_t(__CLASS__ . '.SELECTALL', 'select all')
)
));
$fields->push(new LiteralField(
'UnselectAllLiteral',
sprintf(
'<a href="#" onclick="javascript:jQuery(\'#Form_Form_OrphanIDs :checkbox\').attr(\'checked\', \'\'); return false;">%s</a></p>',
_t(__CLASS__ . '.UNSELECTALL', 'unselect all')
)
));
$fields->push(new OptionsetField(
'OrphanOperation',
_t('SilverStripe\\CMS\\Tasks\\RemoveOrphanedPagesTask.CHOOSEOPERATION', 'Choose operation:'),
[
'rebase' => _t(
__CLASS__ . '.OPERATION_REBASE',
sprintf(
'Rebase selected to a new holder page "%s" and unpublish. None of these pages will show up for website visitors.',
$this->rebaseHolderTitle()
)
),
'remove' => _t(__CLASS__ . '.OPERATION_REMOVE', 'Remove selected from all stages (WARNING: Will destroy all selected pages from both stage and live)'),
],
'rebase'
));
$fields->push(new LiteralField(
'Warning',
sprintf(
'<p class="message">%s</p>',
_t(
__CLASS__ . '.DELETEWARNING',
'Warning: These operations are not reversible. Please handle with care.'
)
)
));
} else {
$fields->push(new LiteralField(
'NotFoundLabel',
sprintf(
'<p class="message">%s</p>',
_t(__CLASS__ . '.NONEFOUND', 'No orphans found')
)
));
}
$form = new Form(
$this,
'SilverStripe\\Forms\\Form',
$fields,
new FieldList(
new FormAction('doSubmit', _t(__CLASS__ . '.BUTTONRUN', 'Run'))
)
);
if (!$orphans || !$orphans->count()) {
$form->makeReadonly();
}
return $form;
}
public function run($request)
{
// @todo Merge with BuildTask functionality
}
public function doSubmit($data, $form)
{
set_time_limit(60*10); // 10 minutes
if (!isset($data['OrphanIDs']) || !isset($data['OrphanOperation'])) {
return false;
}
$successIDs = null;
switch ($data['OrphanOperation']) {
case 'remove':
$successIDs = $this->removeOrphans($data['OrphanIDs']);
break;
case 'rebase':
$successIDs = $this->rebaseOrphans($data['OrphanIDs']);
break;
default:
throw new \InvalidArgumentException(sprintf("Unknown operation: '%s'", $data['OrphanOperation']));
}
$content = '';
if ($successIDs) {
$content .= "<ul>";
foreach ($successIDs as $id => $label) {
$content .= sprintf('<li>%s</li>', $label);
}
$content .= "</ul>";
} else {
$content = _t(__CLASS__ . '.NONEREMOVED', 'None removed');
}
return $this->customise([
'Content' => $content,
'Form' => ' '
])->renderWith('BlankPage');
}
protected function removeOrphans($orphanIDs)
{
$removedOrphans = [];
$orphanBaseTable = DataObject::getSchema()->baseDataTable($this->orphanedSearchClass);
foreach ($orphanIDs as $id) {
/** @var SiteTree $stageRecord */
$stageRecord = Versioned::get_one_by_stage(
$this->orphanedSearchClass,
Versioned::DRAFT,
["\"$orphanBaseTable\".\"ID\"" => $id]
);
if ($stageRecord) {
$removedOrphans[$stageRecord->ID] = sprintf('Removed %s (#%d) from Stage', $stageRecord->Title, $stageRecord->ID);
$stageRecord->delete();
$stageRecord->destroy();
unset($stageRecord);
}
/** @var SiteTree $liveRecord */
$liveRecord = Versioned::get_one_by_stage(
$this->orphanedSearchClass,
Versioned::LIVE,
["\"$orphanBaseTable\".\"ID\"" => $id]
);
if ($liveRecord) {
$removedOrphans[$liveRecord->ID] = sprintf('Removed %s (#%d) from Live', $liveRecord->Title, $liveRecord->ID);
$liveRecord->doUnpublish();
$liveRecord->destroy();
unset($liveRecord);
}
}
return $removedOrphans;
}
protected function rebaseHolderTitle()
{
return sprintf('Rebased Orphans (%s)', date('d/m/Y g:ia', time()));
}
protected function rebaseOrphans($orphanIDs)
{
$holder = new SiteTree();
$holder->ShowInMenus = 0;
$holder->ShowInSearch = 0;
$holder->ParentID = 0;
$holder->Title = $this->rebaseHolderTitle();
$holder->write();
$removedOrphans = [];
$orphanBaseTable = DataObject::getSchema()->baseDataTable($this->orphanedSearchClass);
foreach ($orphanIDs as $id) {
/** @var SiteTree $stageRecord */
$stageRecord = Versioned::get_one_by_stage(
$this->orphanedSearchClass,
'Stage',
["\"$orphanBaseTable\".\"ID\"" => $id]
);
if ($stageRecord) {
$removedOrphans[$stageRecord->ID] = sprintf('Rebased %s (#%d)', $stageRecord->Title, $stageRecord->ID);
$stageRecord->ParentID = $holder->ID;
$stageRecord->ShowInMenus = 0;
$stageRecord->ShowInSearch = 0;
$stageRecord->write();
$stageRecord->doUnpublish();
$stageRecord->destroy();
//unset($stageRecord);
}
/** @var SiteTree $liveRecord */
$liveRecord = Versioned::get_one_by_stage(
$this->orphanedSearchClass,
'Live',
["\"$orphanBaseTable\".\"ID\"" => $id]
);
if ($liveRecord) {
$removedOrphans[$liveRecord->ID] = sprintf('Rebased %s (#%d)', $liveRecord->Title, $liveRecord->ID);
$liveRecord->ParentID = $holder->ID;
$liveRecord->ShowInMenus = 0;
$liveRecord->ShowInSearch = 0;
$liveRecord->write();
if (!$stageRecord) {
$liveRecord->doRestoreToStage();
}
$liveRecord->doUnpublish();
$liveRecord->destroy();
unset($liveRecord);
}
if ($stageRecord) {
unset($stageRecord);
}
}
return $removedOrphans;
}
/**
* Gets all orphans from "Stage" and "Live" stages.
*
* @param string $class
* @param array $filter
* @param string $sort
* @param string $join
* @param int|array $limit
* @return SS_List
*/
public function getOrphanedPages($class = SiteTree::class, $filter = [], $sort = null, $join = null, $limit = null)
{
// Alter condition
$table = DataObject::getSchema()->tableName($class);
if (empty($filter)) {
$where = [];
} elseif (is_array($filter)) {
$where = $filter;
} else {
$where = [$filter];
}
$where[] = ["\"{$table}\".\"ParentID\" != ?" => 0];
$where[] = '"Parents"."ID" IS NULL';
$orphans = new ArrayList();
foreach ([Versioned::DRAFT, Versioned::LIVE] as $stage) {
$table .= ($stage == Versioned::LIVE) ? '_Live' : '';
$stageOrphans = Versioned::get_by_stage(
$class,
$stage,
$where,
$sort,
null,
$limit
)->leftJoin($table, "\"$table\".\"ParentID\" = \"Parents\".\"ID\"", "Parents");
$orphans->merge($stageOrphans);
}
$orphans->removeDuplicates();
return $orphans;
}
}

View File

@ -1,61 +0,0 @@
<?php
namespace SilverStripe\CMS\Tasks;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Control\Controller;
use SilverStripe\ORM\DB;
use SilverStripe\ORM\DataObject;
use SilverStripe\Dev\Deprecation;
/**
* @deprecated 4.13.0 Will be removed without equivalent functionality to replace it
*/
class SiteTreeMaintenanceTask extends Controller
{
private static $allowed_actions = [
'*' => 'ADMIN'
];
public function __construct()
{
Deprecation::notice(
'4.13.0',
'Will be removed without equivalent functionality to replace it',
Deprecation::SCOPE_CLASS
);
}
public function makelinksunique()
{
$table = DataObject::singleton(SiteTree::class)->baseTable();
$badURLs = "'" . implode("', '", DB::query("SELECT \"URLSegment\", count(*) FROM \"$table\" GROUP BY \"URLSegment\" HAVING count(*) > 1")->column()) . "'";
$pages = DataObject::get(SiteTree::class, "\"$table\".\"URLSegment\" IN ($badURLs)");
foreach ($pages as $page) {
echo "<li>$page->Title: ";
$urlSegment = $page->URLSegment;
$page->write();
if ($urlSegment != $page->URLSegment) {
echo _t(
'SilverStripe\\CMS\\Model\\SiteTree.LINKSCHANGEDTO',
" changed {url1} -> {url2}",
['url1' => $urlSegment, 'url2' => $page->URLSegment]
);
} else {
echo _t(
'SilverStripe\\CMS\\Model\\SiteTree.LINKSALREADYUNIQUE',
" {url} is already unique",
['url' => $urlSegment]
);
}
die();
}
}
public function Link($action = null)
{
/** @skipUpgrade */
return Controller::join_links('SiteTreeMaintenanceTask', $action, '/');
}
}

View File

@ -19,19 +19,19 @@
} }
], ],
"require": { "require": {
"silverstripe/admin": "^1.13.20", "php": "^8.1",
"silverstripe/campaign-admin": "^1.7@dev", "silverstripe/admin": "^2",
"silverstripe/framework": "^4.11", "silverstripe/campaign-admin": "^2",
"silverstripe/reports": "^4.7@dev", "silverstripe/framework": "^5.1",
"silverstripe/siteconfig": "^4.7@dev", "silverstripe/reports": "^5",
"silverstripe/versioned": "^1.7@dev", "silverstripe/siteconfig": "^5",
"silverstripe/versioned-admin": "^1.7@dev", "silverstripe/versioned": "^2",
"silverstripe/vendor-plugin": "^1.0", "silverstripe/versioned-admin": "^2",
"php": "^7.4 || ^8.0" "silverstripe/vendor-plugin": "^2"
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^9.5", "phpunit/phpunit": "^9.6",
"squizlabs/php_codesniffer": "^3" "squizlabs/php_codesniffer": "^3.7"
}, },
"extra": { "extra": {
"expose": [ "expose": [

View File

@ -25,6 +25,8 @@ az:
ANCHORVALUE: Ankor ANCHORVALUE: Ankor
SilverStripe\CMS\Forms\InternalLinkFormFactory: SilverStripe\CMS\Forms\InternalLinkFormFactory:
LINKDESCR: 'Link təsviri' LINKDESCR: 'Link təsviri'
SilverStripe\CMS\Forms\SiteTreeURLSegmentField:
Edit: Edit
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
FILE: Fayl FILE: Fayl
HEADER: 'Bu səhifə istifadəçiləri başqa səhifəyə yönləndirəcək' HEADER: 'Bu səhifə istifadəçiləri başqa səhifəyə yönləndirəcək'

View File

@ -145,6 +145,7 @@ bg:
Cancel: Отказ Cancel: Отказ
Edit: Редактирай Edit: Редактирай
HelpChars: 'Специалните символи са автоматично конвертирани или изтрити.' HelpChars: 'Специалните символи са автоматично конвертирани или изтрити.'
OK: OK
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
DESCRIPTION: 'Пренасочва към страница от сайта или външен URL адрес' DESCRIPTION: 'Пренасочва към страница от сайта или външен URL адрес'
FILE: Файл FILE: Файл
@ -259,6 +260,7 @@ bg:
many_many_ImageTracking: 'Следене на снимките' many_many_ImageTracking: 'Следене на снимките'
many_many_LinkTracking: 'Следене на връзките' many_many_LinkTracking: 'Следене на връзките'
SilverStripe\CMS\Model\SiteTreeFileExtension: SilverStripe\CMS\Model\SiteTreeFileExtension:
TITLE_INDEX: '#'
TITLE_TYPE: Тип TITLE_TYPE: Тип
TITLE_USED_ON: 'Използвано в' TITLE_USED_ON: 'Използвано в'
SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension: SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension:

View File

@ -15,6 +15,8 @@ bs:
ROLLBACK: 'Vrati na ovo izdanje' ROLLBACK: 'Vrati na ovo izdanje'
SAVEDRAFT: Snimi SAVEDRAFT: Snimi
TabContent: Sadržaj TabContent: Sadržaj
SilverStripe\CMS\Controllers\CMSPagesController:
FILTER: Filter
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
Email: E-mail Email: E-mail
Password: Šifra Password: Šifra
@ -22,6 +24,8 @@ bs:
ANCHORVALUE: Sidro ANCHORVALUE: Sidro
SilverStripe\CMS\Forms\InternalLinkFormFactory: SilverStripe\CMS\Forms\InternalLinkFormFactory:
LINKDESCR: 'Opis linka' LINKDESCR: 'Opis linka'
SilverStripe\CMS\Forms\SiteTreeURLSegmentField:
Edit: Edit
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
FILE: Datoteka FILE: Datoteka
HEADER: 'Ova stranica će preusmjeriti korisnike na drugu stranicu' HEADER: 'Ova stranica će preusmjeriti korisnike na drugu stranicu'

View File

@ -29,6 +29,8 @@ ca:
ANCHORVALUE: Ancla ANCHORVALUE: Ancla
SilverStripe\CMS\Forms\InternalLinkFormFactory: SilverStripe\CMS\Forms\InternalLinkFormFactory:
LINKDESCR: 'Descripció de l''enllaç' LINKDESCR: 'Descripció de l''enllaç'
SilverStripe\CMS\Forms\SiteTreeURLSegmentField:
Edit: Edit
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
FILE: Fitxer FILE: Fitxer
HEADER: 'Aquesta pàgina redirigirà usuaris a una altra pàgina' HEADER: 'Aquesta pàgina redirigirà usuaris a una altra pàgina'

View File

@ -114,6 +114,7 @@ cs:
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
ARCHIVEDSITE: 'Náhled verze' ARCHIVEDSITE: 'Náhled verze'
ARCHIVEDSITEFROM: 'Archivován web z' ARCHIVEDSITEFROM: 'Archivován web z'
CMS: CMS
DRAFT: Koncept DRAFT: Koncept
DRAFTSITE: 'Koncept webu' DRAFTSITE: 'Koncept webu'
Email: E-mail Email: E-mail
@ -144,6 +145,7 @@ cs:
Cancel: Storno Cancel: Storno
Edit: Editovat Edit: Editovat
HelpChars: 'Zvláštní znaky jsou automaticky zkonvertovány nebo odstraněny' HelpChars: 'Zvláštní znaky jsou automaticky zkonvertovány nebo odstraněny'
OK: OK
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
DESCRIPTION: 'Přesměruje na interní stránku nebo na externí URL' DESCRIPTION: 'Přesměruje na interní stránku nebo na externí URL'
FILE: Soubor FILE: Soubor
@ -207,6 +209,7 @@ cs:
METAEXTRA: 'Vlastní meta tagy' METAEXTRA: 'Vlastní meta tagy'
MODIFIEDONDRAFTHELP: 'Stránka má nezveřejněné změny' MODIFIEDONDRAFTHELP: 'Stránka má nezveřejněné změny'
MODIFIEDONDRAFTSHORT: Upraveno MODIFIEDONDRAFTSHORT: Upraveno
MetadataToggle: Metadata
MoreOptions: 'Více voleb' MoreOptions: 'Více voleb'
NOTPUBLISHED: Nezveřejněno NOTPUBLISHED: Nezveřejněno
OBSOLETECLASS: 'Tato stránka je zastaralého typu {type}. Uložení zpúsobí zrušení svého typu a múžete tak ztratit data' OBSOLETECLASS: 'Tato stránka je zastaralého typu {type}. Uložení zpúsobí zrušení svého typu a múžete tak ztratit data'
@ -250,6 +253,7 @@ cs:
many_many_ImageTracking: 'Stopování obrázku' many_many_ImageTracking: 'Stopování obrázku'
many_many_LinkTracking: 'Stopování odkazu' many_many_LinkTracking: 'Stopování odkazu'
SilverStripe\CMS\Model\SiteTreeFileExtension: SilverStripe\CMS\Model\SiteTreeFileExtension:
TITLE_INDEX: '#'
TITLE_TYPE: Typ TITLE_TYPE: Typ
TITLE_USED_ON: 'Použito na' TITLE_USED_ON: 'Použito na'
SilverStripe\CMS\Model\VirtualPage: SilverStripe\CMS\Model\VirtualPage:
@ -274,6 +278,7 @@ cs:
ColumnDateLastModified: 'Datum poslední změny' ColumnDateLastModified: 'Datum poslední změny'
ColumnDateLastPublished: 'Datum posledního zveřejnění' ColumnDateLastPublished: 'Datum posledního zveřejnění'
ColumnProblemType: 'Problém typu' ColumnProblemType: 'Problém typu'
ColumnURL: URL
HasBrokenFile: 'porušen soubor' HasBrokenFile: 'porušen soubor'
HasBrokenLink: 'porušen odkaz' HasBrokenLink: 'porušen odkaz'
HasBrokenLinkAndFile: 'porušen odkaz a soubor' HasBrokenLinkAndFile: 'porušen odkaz a soubor'

View File

@ -30,6 +30,7 @@ da:
Create: Opret Create: Opret
DUPLICATED: 'Dublerede ''{title}'' med succes' DUPLICATED: 'Dublerede ''{title}'' med succes'
DUPLICATEDWITHCHILDREN: 'Dublerede ''{title}'' og undersider med succes' DUPLICATEDWITHCHILDREN: 'Dublerede ''{title}'' og undersider med succes'
EMAIL: Email
NEWPAGE: 'Ny {pagetype}' NEWPAGE: 'Ny {pagetype}'
PAGENOTEXISTS: 'Denne side eksisterer ikke' PAGENOTEXISTS: 'Denne side eksisterer ikke'
PAGES: 'Side status' PAGES: 'Side status'
@ -94,6 +95,7 @@ da:
SilverStripe\CMS\Controllers\CMSPageSettingsController: SilverStripe\CMS\Controllers\CMSPageSettingsController:
MENUTITLE: 'Rediger side' MENUTITLE: 'Rediger side'
SilverStripe\CMS\Controllers\CMSPagesController: SilverStripe\CMS\Controllers\CMSPagesController:
FILTER: Filter
ListView: Listevisning ListView: Listevisning
MENUTITLE: Sider MENUTITLE: Sider
TreeView: Trævisning TreeView: Trævisning
@ -112,9 +114,12 @@ da:
SilverStripe\CMS\Controllers\CMSSiteTreeFilter_StatusRemovedFromDraftPages: SilverStripe\CMS\Controllers\CMSSiteTreeFilter_StatusRemovedFromDraftPages:
Title: 'Udgivet men slettet fra kladde' Title: 'Udgivet men slettet fra kladde'
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
ARCHIVEDSITE: 'Preview version'
ARCHIVEDSITEFROM: 'Arkiveret side fra' ARCHIVEDSITEFROM: 'Arkiveret side fra'
CMS: CMS
DRAFT: Kladde DRAFT: Kladde
DRAFTSITE: Kladdeside DRAFTSITE: Kladdeside
Email: Email
INSTALL_SUCCESS: 'Installation gennemført succesfuldt' INSTALL_SUCCESS: 'Installation gennemført succesfuldt'
InstallFilesDeleted: 'Installationsfiler slettet succesfuldt.' InstallFilesDeleted: 'Installationsfiler slettet succesfuldt.'
InstallSecurityWarning: 'Af sikkerhedmæssige årsager bør du slette installationsfilerne, medmindre du planlægger at installere igen på et senere tidspunkt (<em>kræver admin login, se det ovenstående</em>). Webserveren behøver også kun skriverettigheder til mappen "assets", du kan fjerne skriverettigheder til alle de andre mapper. <a href="{link}" style="text-align: center;">Klik her for at slette installationsfilerne.</a>' InstallSecurityWarning: 'Af sikkerhedmæssige årsager bør du slette installationsfilerne, medmindre du planlægger at installere igen på et senere tidspunkt (<em>kræver admin login, se det ovenstående</em>). Webserveren behøver også kun skriverettigheder til mappen "assets", du kan fjerne skriverettigheder til alle de andre mapper. <a href="{link}" style="text-align: center;">Klik her for at slette installationsfilerne.</a>'
@ -146,6 +151,7 @@ da:
EMPTY: 'Indtast en URL eller klik annuller' EMPTY: 'Indtast en URL eller klik annuller'
Edit: Rediger Edit: Rediger
HelpChars: 'Specialkarakterer bliver automatisk konverteret eller fjernet.' HelpChars: 'Specialkarakterer bliver automatisk konverteret eller fjernet.'
OK: OK
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
DESCRIPTION: 'Omdirigerer til en side eller en ekstern URL' DESCRIPTION: 'Omdirigerer til en side eller en ekstern URL'
HEADER: 'Denne side omdirigerer besøgende til en anden side' HEADER: 'Denne side omdirigerer besøgende til en anden side'
@ -212,6 +218,7 @@ da:
METAEXTRA: 'Brugerdefinerede Meta Tags' METAEXTRA: 'Brugerdefinerede Meta Tags'
MODIFIEDONDRAFTHELP: 'Siden har ikke-udgivne ændringer' MODIFIEDONDRAFTHELP: 'Siden har ikke-udgivne ændringer'
MODIFIEDONDRAFTSHORT: Ændret MODIFIEDONDRAFTSHORT: Ændret
MetadataToggle: Metadata
MoreOptions: 'Flere muligheder' MoreOptions: 'Flere muligheder'
NOTPUBLISHED: 'Ikke udgivet' NOTPUBLISHED: 'Ikke udgivet'
OBSOLETECLASS: 'Denne side er af den udgåede sidetype {type}. Gemmer du bliver sidetypen nulstillet og du kan tabe data.' OBSOLETECLASS: 'Denne side er af den udgåede sidetype {type}. Gemmer du bliver sidetypen nulstillet og du kan tabe data.'
@ -264,6 +271,8 @@ da:
many_many_ImageTracking: 'Sporing af billeder' many_many_ImageTracking: 'Sporing af billeder'
many_many_LinkTracking: 'Sporing af links' many_many_LinkTracking: 'Sporing af links'
SilverStripe\CMS\Model\SiteTreeFileExtension: SilverStripe\CMS\Model\SiteTreeFileExtension:
TITLE_INDEX: '#'
TITLE_TYPE: Type
TITLE_USED_ON: 'Brugt på' TITLE_USED_ON: 'Brugt på'
SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension: SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension:
USAGE: Brug USAGE: Brug
@ -298,6 +307,7 @@ da:
ColumnDateLastModified: 'Dato for seneste ændring' ColumnDateLastModified: 'Dato for seneste ændring'
ColumnDateLastPublished: 'Dato for seneste udgivelse' ColumnDateLastPublished: 'Dato for seneste udgivelse'
ColumnProblemType: Problemtype ColumnProblemType: Problemtype
ColumnURL: URL
HasBrokenFile: 'har en ødelagt fil' HasBrokenFile: 'har en ødelagt fil'
HasBrokenLink: 'har et dårligt link' HasBrokenLink: 'har et dårligt link'
HasBrokenLinkAndFile: 'har et dårligt link og en ødelagt fil' HasBrokenLinkAndFile: 'har et dårligt link og en ødelagt fil'

View File

@ -96,6 +96,7 @@ de:
SilverStripe\CMS\Controllers\CMSPageSettingsController: SilverStripe\CMS\Controllers\CMSPageSettingsController:
MENUTITLE: 'Seite bearbeiten' MENUTITLE: 'Seite bearbeiten'
SilverStripe\CMS\Controllers\CMSPagesController: SilverStripe\CMS\Controllers\CMSPagesController:
FILTER: Filter
ListView: Listenansicht ListView: Listenansicht
MENUTITLE: Seiten MENUTITLE: Seiten
TreeView: Baumansicht TreeView: Baumansicht
@ -116,6 +117,7 @@ de:
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
ARCHIVEDSITE: Vorschauversion ARCHIVEDSITE: Vorschauversion
ARCHIVEDSITEFROM: 'Site archiviert von' ARCHIVEDSITEFROM: 'Site archiviert von'
CMS: CMS
DRAFT: Entwurf DRAFT: Entwurf
DRAFTSITE: Vorschau-Site DRAFTSITE: Vorschau-Site
Email: E-Mail Email: E-Mail
@ -150,6 +152,7 @@ de:
EMPTY: 'Bitte geben Sie ein URL-Segment ein oder drücken Sie auf Abbrechen' EMPTY: 'Bitte geben Sie ein URL-Segment ein oder drücken Sie auf Abbrechen'
Edit: Bearbeiten Edit: Bearbeiten
HelpChars: 'Sonderzeichen werden automatisch umgewandelt oder entfernt.' HelpChars: 'Sonderzeichen werden automatisch umgewandelt oder entfernt.'
OK: OK
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
DESCRIPTION: 'Leitet zu einer anderen internen oder externen Seite weiter' DESCRIPTION: 'Leitet zu einer anderen internen oder externen Seite weiter'
FILE: Datei FILE: Datei
@ -273,6 +276,7 @@ de:
many_many_ImageTracking: Bild-Verfolgung many_many_ImageTracking: Bild-Verfolgung
many_many_LinkTracking: Link-Verfolgung many_many_LinkTracking: Link-Verfolgung
SilverStripe\CMS\Model\SiteTreeFileExtension: SilverStripe\CMS\Model\SiteTreeFileExtension:
TITLE_INDEX: '#'
TITLE_TYPE: Typ TITLE_TYPE: Typ
TITLE_USED_ON: 'Verwendet auf' TITLE_USED_ON: 'Verwendet auf'
SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension: SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension:
@ -309,6 +313,7 @@ de:
ColumnDateLastModified: 'Zuletzt geändert' ColumnDateLastModified: 'Zuletzt geändert'
ColumnDateLastPublished: 'Zuletzt veröffentlicht' ColumnDateLastPublished: 'Zuletzt veröffentlicht'
ColumnProblemType: Problemtyp ColumnProblemType: Problemtyp
ColumnURL: URL
HasBrokenFile: 'Defekter Dateilink' HasBrokenFile: 'Defekter Dateilink'
HasBrokenLink: 'Defekter Link' HasBrokenLink: 'Defekter Link'
HasBrokenLinkAndFile: 'Defekter Link und defekter Dateilink' HasBrokenLinkAndFile: 'Defekter Link und defekter Dateilink'

View File

@ -23,6 +23,7 @@ de_DE:
UNKNOWN: Unbekannt UNKNOWN: Unbekannt
WHEN: Wann WHEN: Wann
SilverStripe\CMS\Controllers\CMSPagesController: SilverStripe\CMS\Controllers\CMSPagesController:
FILTER: Filter
MENUTITLE: Seiten MENUTITLE: Seiten
SilverStripe\CMS\Controllers\CMSSiteTreeFilter_ChangedPages: SilverStripe\CMS\Controllers\CMSSiteTreeFilter_ChangedPages:
Title: 'Bearbeitete Seiten' Title: 'Bearbeitete Seiten'

View File

@ -10,6 +10,7 @@ el:
Cancel: Άκυρο Cancel: Άκυρο
ChoosePageType: 'Επιλέξτε τύπο σελίδας' ChoosePageType: 'Επιλέξτε τύπο σελίδας'
Create: Δημιουργία Create: Δημιουργία
EMAIL: Email
NEWPAGE: 'Νέο {pagetype}' NEWPAGE: 'Νέο {pagetype}'
PAGENOTEXISTS: 'Αυτή η σελίδα δεν υπάρχει' PAGENOTEXISTS: 'Αυτή η σελίδα δεν υπάρχει'
PAGESALLOPT: 'Όλες οι σελίδες' PAGESALLOPT: 'Όλες οι σελίδες'
@ -50,6 +51,7 @@ el:
Title: 'Όλες οι σελίδες' Title: 'Όλες οι σελίδες'
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
ARCHIVEDSITE: Προεπισκόπιση ARCHIVEDSITE: Προεπισκόπιση
Email: Email
INSTALL_SUCCESS: 'Η Εγκατάσταση ήταν επιτυχής!' INSTALL_SUCCESS: 'Η Εγκατάσταση ήταν επιτυχής!'
LOGGEDINAS: 'Συνδεδεμένος ως' LOGGEDINAS: 'Συνδεδεμένος ως'
LOGIN: Σύνδεση LOGIN: Σύνδεση
@ -64,6 +66,7 @@ el:
ARCHIVED: Αρχειοθετημένο ARCHIVED: Αρχειοθετημένο
SilverStripe\CMS\Forms\SiteTreeURLSegmentField: SilverStripe\CMS\Forms\SiteTreeURLSegmentField:
Cancel: Άκυρο Cancel: Άκυρο
Edit: Edit
OK: ΟΚ OK: ΟΚ
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
HEADER: 'Αυτή η σελίδα θα ανακατευθύνει τους χρήστες σε μια άλλη σελίδα' HEADER: 'Αυτή η σελίδα θα ανακατευθύνει τους χρήστες σε μια άλλη σελίδα'
@ -133,6 +136,7 @@ el:
ColumnDateLastModified: 'Ημερομηνία τελευταίας τροποποίησης' ColumnDateLastModified: 'Ημερομηνία τελευταίας τροποποίησης'
ColumnDateLastPublished: 'Ημερομηνία τελευταίας δημοσιεύσης' ColumnDateLastPublished: 'Ημερομηνία τελευταίας δημοσιεύσης'
ColumnProblemType: 'Τύπος προβλήματος' ColumnProblemType: 'Τύπος προβλήματος'
ColumnURL: URL
HasBrokenFile: 'έχει ανενεργό αρχείο' HasBrokenFile: 'έχει ανενεργό αρχείο'
HasBrokenLink: 'έχει ανενεργό σύνδεσμο ' HasBrokenLink: 'έχει ανενεργό σύνδεσμο '
HasBrokenLinkAndFile: 'έχει ανενεργό σύνδεσμο και αρχείο' HasBrokenLinkAndFile: 'έχει ανενεργό σύνδεσμο και αρχείο'

View File

@ -12,10 +12,10 @@ en:
UNPUBLISHED_PAGES: 'Unpublished %d pages' UNPUBLISHED_PAGES: 'Unpublished %d pages'
UNPUBLISH_PAGES: Unpublish UNPUBLISH_PAGES: Unpublish
SilverStripe\CMS\Controllers\CMSMain: SilverStripe\CMS\Controllers\CMSMain:
ACCESS: 'Access to ''{title}'' section' ACCESS: "Access to '{title}' section"
ACCESS_HELP: 'Allow viewing of the section containing page tree and content. View and edit permissions can be handled through page specific dropdowns, as well as the separate "Content permissions".' ACCESS_HELP: 'Allow viewing of the section containing page tree and content. View and edit permissions can be handled through page specific dropdowns, as well as the separate "Content permissions".'
ARCHIVE: Archive ARCHIVE: Archive
ARCHIVEDPAGE: 'Archived page ''{title}''' ARCHIVEDPAGE: "Archived page '{title}'"
AddNew: 'Add new page' AddNew: 'Add new page'
AddNewButton: 'Add new' AddNewButton: 'Add new'
AddPageRestriction: 'Note: Some page types are not allowed for this selection' AddPageRestriction: 'Note: Some page types are not allowed for this selection'
@ -28,35 +28,35 @@ en:
ChoosePageParentMode: 'Choose where to create this page' ChoosePageParentMode: 'Choose where to create this page'
ChoosePageType: 'Choose page type' ChoosePageType: 'Choose page type'
Create: Create Create: Create
DUPLICATED: 'Duplicated ''{title}'' successfully' DUPLICATED: "Duplicated '{title}' successfully"
DUPLICATEDWITHCHILDREN: 'Duplicated ''{title}'' and children successfully' DUPLICATEDWITHCHILDREN: "Duplicated '{title}' and children successfully"
EMAIL: Email EMAIL: Email
NEWPAGE: 'New {pagetype}' NEWPAGE: 'New {pagetype}'
PAGENOTEXISTS: 'This page doesn''t exist' PAGENOTEXISTS: "This page doesn't exist"
PAGES: 'Page status' PAGES: 'Page status'
PAGESALLOPT: 'All pages' PAGESALLOPT: 'All pages'
PAGETYPEANYOPT: Any PAGETYPEANYOPT: Any
PAGETYPEOPT: 'Page type' PAGETYPEOPT: 'Page type'
PAGETYPE_TITLE: '(Page type: {type}) {title}' PAGETYPE_TITLE: '(Page type: {type}) {title}'
PLEASESAVE: 'Please Save Page: This page could not be updated because it hasn''t been saved yet.' PLEASESAVE: "Please Save Page: This page could not be updated because it hasn't been saved yet."
PUBALLCONFIRM: 'Please publish every page in the site, copying content stage to live' PUBALLCONFIRM: 'Please publish every page in the site, copying content stage to live'
PUBALLFUN: '"Publish All" functionality' PUBALLFUN: '"Publish All" functionality'
PUBALLFUN2: 'Pressing this button will do the equivalent of going to every page and pressing "publish". It''s intended to be used after there have been massive edits of the content, such as when the site was first built. For large websites, this task might not be able to run through to completion. In this case, we recommend talking to your developers to create a custom task' PUBALLFUN2: 'Pressing this button will do the equivalent of going to every page and pressing "publish". It''s intended to be used after there have been massive edits of the content, such as when the site was first built. For large websites, this task might not be able to run through to completion. In this case, we recommend talking to your developers to create a custom task'
PUBLISHED: 'Published ''{title}'' successfully.' PUBLISHED: "Published '{title}' successfully."
PUBPAGES: 'Done: Published {count} pages' PUBPAGES: 'Done: Published {count} pages'
PageAdded: 'Successfully created page' PageAdded: 'Successfully created page'
REMOVEDPAGE: 'Removed ''{title}'' from the published site' REMOVEDPAGE: "Removed '{title}' from the published site"
REMOVEDPAGEFROMDRAFT: 'Removed ''{title}'' from the draft site' REMOVEDPAGEFROMDRAFT: "Removed '{title}' from the draft site"
REORGANISATIONSUCCESSFUL: 'Reorganised the site tree successfully.' REORGANISATIONSUCCESSFUL: 'Reorganised the site tree successfully.'
RESTORE: 'Restore draft' RESTORE: 'Restore draft'
RESTORED: 'Restored ''{title}'' successfully' RESTORED: "Restored '{title}' successfully"
RESTORE_DESC: 'Restore the archived version to draft' RESTORE_DESC: 'Restore the archived version to draft'
RESTORE_TO_ROOT: 'Restore draft at top level' RESTORE_TO_ROOT: 'Restore draft at top level'
RESTORE_TO_ROOT_DESC: 'Restore the archived version to draft as a top level page' RESTORE_TO_ROOT_DESC: 'Restore the archived version to draft as a top level page'
ROLLBACK: 'Roll back to this version' ROLLBACK: 'Roll back to this version'
ROLLEDBACKPUBv2: 'Rolled back to published version.' ROLLEDBACKPUBv2: 'Rolled back to published version.'
ROLLEDBACKVERSIONv2: 'Rolled back to version #{version}.' ROLLEDBACKVERSIONv2: 'Rolled back to version #{version}.'
SAVED: 'Saved ''{title}'' successfully.' SAVED: "Saved '{title}' successfully."
SAVEDRAFT: Save SAVEDRAFT: Save
SEARCHRESULTS: 'Search results' SEARCHRESULTS: 'Search results'
SHOW_AS_LIST: 'show as list' SHOW_AS_LIST: 'show as list'
@ -73,8 +73,8 @@ en:
ParentMode_top: 'Top level' ParentMode_top: 'Top level'
Title: 'Add page' Title: 'Add page'
SilverStripe\CMS\Controllers\CMSPageEditController: SilverStripe\CMS\Controllers\CMSPageEditController:
ErrorItemPermissionDenied: 'It seems you don''t have the necessary permissions to add {ObjectTitle} to a campaign' ErrorItemPermissionDenied: "It seems you don't have the necessary permissions to add {ObjectTitle} to a campaign"
ErrorNotFound: 'That {Type} couldn''t be found' ErrorNotFound: "That {Type} couldn't be found"
MENUTITLE: 'Edit Page' MENUTITLE: 'Edit Page'
SilverStripe\CMS\Controllers\CMSPageHistoryController: SilverStripe\CMS\Controllers\CMSPageHistoryController:
AUTHOR: Author AUTHOR: Author
@ -114,7 +114,6 @@ en:
SilverStripe\CMS\Controllers\CMSSiteTreeFilter_StatusRemovedFromDraftPages: SilverStripe\CMS\Controllers\CMSSiteTreeFilter_StatusRemovedFromDraftPages:
Title: 'Live but removed from draft' Title: 'Live but removed from draft'
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
ARCHIVEDSITE: 'Preview version'
ARCHIVEDSITEFROM: 'Archived site from' ARCHIVEDSITEFROM: 'Archived site from'
CMS: CMS CMS: CMS
DRAFT: Draft DRAFT: Draft
@ -134,11 +133,8 @@ en:
Password: Password Password: Password
PostInstallTutorialIntro: 'This website is a simplistic version of a SilverStripe 3 site. To extend this, please take a look at {link}.' PostInstallTutorialIntro: 'This website is a simplistic version of a SilverStripe 3 site. To extend this, please take a look at {link}.'
StartEditing: 'You can start editing your content by opening <a href="{link}">the CMS</a>.' StartEditing: 'You can start editing your content by opening <a href="{link}">the CMS</a>.'
UNVERSIONEDPREVIEW: Preview
UnableDeleteInstall: 'Unable to delete installation files. Please delete the files below manually' UnableDeleteInstall: 'Unable to delete installation files. Please delete the files below manually'
VIEWPAGEIN: 'View Page in:' VIEWPAGEIN: 'View Page in:'
SilverStripe\CMS\Controllers\SilverStripeNavigator:
ARCHIVED: Archived
SilverStripe\CMS\Forms\AnchorLinkFormFactory: SilverStripe\CMS\Forms\AnchorLinkFormFactory:
ANCHORVALUE: Anchor ANCHORVALUE: Anchor
SilverStripe\CMS\Forms\InternalLinkFormFactory: SilverStripe\CMS\Forms\InternalLinkFormFactory:
@ -218,7 +214,7 @@ en:
LASTPUBLISHED: 'Last published' LASTPUBLISHED: 'Last published'
LASTSAVED: 'Last saved' LASTSAVED: 'Last saved'
LASTUPDATED: 'Last Updated' LASTUPDATED: 'Last Updated'
LINKCHANGENOTE: 'Changing this page''s link will also affect the links of all child pages.' LINKCHANGENOTE: "Changing this page's link will also affect the links of all child pages."
LINKSALREADYUNIQUE: ' {url} is already unique' LINKSALREADYUNIQUE: ' {url} is already unique'
LINKSCHANGEDTO: ' changed {url1} -> {url2}' LINKSCHANGEDTO: ' changed {url1} -> {url2}'
MENUTITLE: 'Navigation label' MENUTITLE: 'Navigation label'

View File

@ -117,6 +117,7 @@ eo:
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
ARCHIVEDSITE: 'Antaŭvida versio' ARCHIVEDSITE: 'Antaŭvida versio'
ARCHIVEDSITEFROM: 'Enarkivigita retejo el' ARCHIVEDSITEFROM: 'Enarkivigita retejo el'
CMS: CMS
DRAFT: Malneta DRAFT: Malneta
DRAFTSITE: 'Malneta retejo' DRAFTSITE: 'Malneta retejo'
Email: Retpoŝto Email: Retpoŝto
@ -177,7 +178,6 @@ eo:
ACCESSANYONE: Iu ACCESSANYONE: Iu
ACCESSHEADER: 'Kiuj povas vidi ĉi tiun paĝon?' ACCESSHEADER: 'Kiuj povas vidi ĉi tiun paĝon?'
ACCESSLOGGEDIN: 'Ensalutintaj uzantoj' ACCESSLOGGEDIN: 'Ensalutintaj uzantoj'
ACCESSONLYMEMBERS: 'Nur ĉi tiuj homoj (elektu el listo)'
ACCESSONLYTHESE: 'Nur ĉi tiuj homoj (elektu el listo)' ACCESSONLYTHESE: 'Nur ĉi tiuj homoj (elektu el listo)'
ADDEDTODRAFTHELP: 'Paĝo ankoraŭ estas ne publikigita' ADDEDTODRAFTHELP: 'Paĝo ankoraŭ estas ne publikigita'
ADDEDTODRAFTSHORT: Malneto ADDEDTODRAFTSHORT: Malneto
@ -205,7 +205,6 @@ eo:
DependtPageColumnLinkType: 'Ligila tipo' DependtPageColumnLinkType: 'Ligila tipo'
EDITHEADER: 'Kiuj povas redakti ĉi tiun paĝon?' EDITHEADER: 'Kiuj povas redakti ĉi tiun paĝon?'
EDITORGROUPS: 'Grupoj de redaktantoj' EDITORGROUPS: 'Grupoj de redaktantoj'
EDITORMEMBERS: 'Redaktantaj membroj'
EDITOR_GROUPS_FIELD_DESC: 'Grupoj kun ĉieaj permesoj: {groupList}' EDITOR_GROUPS_FIELD_DESC: 'Grupoj kun ĉieaj permesoj: {groupList}'
EDIT_ALL_DESCRIPTION: 'Redakti ajnan paĝon' EDIT_ALL_DESCRIPTION: 'Redakti ajnan paĝon'
EDIT_ALL_HELP: 'Eblo redakti ajnan paĝon en la retejo, senkonsidere de la agordoj en la langeto Aliro. Necesas la permeso "Aliro al sekcio ''Paĝoj'' "' EDIT_ALL_HELP: 'Eblo redakti ajnan paĝon en la retejo, senkonsidere de la agordoj en la langeto Aliro. Necesas la permeso "Aliro al sekcio ''Paĝoj'' "'
@ -263,7 +262,6 @@ eo:
URLSegment: URL-segmento URLSegment: URL-segmento
UntitledDependentObject: 'Sentitola {instanceType}' UntitledDependentObject: 'Sentitola {instanceType}'
VIEWERGROUPS: 'Grupoj de vidantoj' VIEWERGROUPS: 'Grupoj de vidantoj'
VIEWERMEMBERS: 'Vidantaj membroj'
VIEWER_GROUPS_FIELD_DESC: 'Grupoj kun ĉieaj vidigaj permesoj: {groupList}' VIEWER_GROUPS_FIELD_DESC: 'Grupoj kun ĉieaj vidigaj permesoj: {groupList}'
VIEW_ALL_DESCRIPTION: 'Vidigi ajnan paĝon' VIEW_ALL_DESCRIPTION: 'Vidigi ajnan paĝon'
VIEW_ALL_HELP: 'Povo vidigi ajnan paĝon en la retejo, senkonsidere la agordaĵojn en la langeto Aliro. Bezonatas la permeso "Aliro al sekcio ''Paĝoj''"' VIEW_ALL_HELP: 'Povo vidigi ajnan paĝon en la retejo, senkonsidere la agordaĵojn en la langeto Aliro. Bezonatas la permeso "Aliro al sekcio ''Paĝoj''"'
@ -312,12 +310,11 @@ eo:
many_many_BackLinkTracking: 'Spuri retroligilojn' many_many_BackLinkTracking: 'Spuri retroligilojn'
many_many_CrossSubsiteLinkTracking: 'Trans-subreteja ligspurado' many_many_CrossSubsiteLinkTracking: 'Trans-subreteja ligspurado'
many_many_EditorGroups: 'Grupoj de redaktantoj' many_many_EditorGroups: 'Grupoj de redaktantoj'
many_many_EditorMembers: 'Redaktantaj membroj'
many_many_ImageTracking: 'Spuri Bildojn' many_many_ImageTracking: 'Spuri Bildojn'
many_many_LinkTracking: 'Spuri Ligilojn' many_many_LinkTracking: 'Spuri Ligilojn'
many_many_ViewerGroups: 'Grupoj de vidantoj' many_many_ViewerGroups: 'Grupoj de vidantoj'
many_many_ViewerMembers: 'Vidantaj membroj'
SilverStripe\CMS\Model\SiteTreeFileExtension: SilverStripe\CMS\Model\SiteTreeFileExtension:
TITLE_INDEX: '#'
TITLE_TYPE: Tipo TITLE_TYPE: Tipo
TITLE_USED_ON: 'Uzita je' TITLE_USED_ON: 'Uzita je'
SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension: SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension:
@ -359,6 +356,7 @@ eo:
ColumnDateLastModified: 'Dato de lasta modifo' ColumnDateLastModified: 'Dato de lasta modifo'
ColumnDateLastPublished: 'Dato de lasta publikigo' ColumnDateLastPublished: 'Dato de lasta publikigo'
ColumnProblemType: Problemtipo ColumnProblemType: Problemtipo
ColumnURL: URL
HasBrokenFile: 'havas rompitan dosieron' HasBrokenFile: 'havas rompitan dosieron'
HasBrokenLink: 'havas rompitan ligilon' HasBrokenLink: 'havas rompitan ligilon'
HasBrokenLinkAndFile: 'havas rompitan ligilon kaj dosieron' HasBrokenLinkAndFile: 'havas rompitan ligilon kaj dosieron'

View File

@ -110,6 +110,7 @@ es:
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
ARCHIVEDSITE: 'Vista previa de la versión' ARCHIVEDSITE: 'Vista previa de la versión'
ARCHIVEDSITEFROM: 'Sitio archivado desde' ARCHIVEDSITEFROM: 'Sitio archivado desde'
CMS: CMS
DRAFT: Borrador DRAFT: Borrador
DRAFTSITE: 'Sitio en Borrador' DRAFTSITE: 'Sitio en Borrador'
Email: 'Correo electrónico' Email: 'Correo electrónico'
@ -210,6 +211,7 @@ es:
METAEXTRA: 'Meta Tags Personalizadas' METAEXTRA: 'Meta Tags Personalizadas'
MODIFIEDONDRAFTHELP: 'La página tiene cambios sin publicar' MODIFIEDONDRAFTHELP: 'La página tiene cambios sin publicar'
MODIFIEDONDRAFTSHORT: Modificado MODIFIEDONDRAFTSHORT: Modificado
MetadataToggle: Metadata
MoreOptions: 'Más opciones' MoreOptions: 'Más opciones'
NOTPUBLISHED: 'No publicado' NOTPUBLISHED: 'No publicado'
OBSOLETECLASS: 'Clase obsoleta' OBSOLETECLASS: 'Clase obsoleta'
@ -258,6 +260,7 @@ es:
many_many_ImageTracking: 'Rastreo de Imágenes' many_many_ImageTracking: 'Rastreo de Imágenes'
many_many_LinkTracking: 'Rastreo de Enlaces' many_many_LinkTracking: 'Rastreo de Enlaces'
SilverStripe\CMS\Model\SiteTreeFileExtension: SilverStripe\CMS\Model\SiteTreeFileExtension:
TITLE_INDEX: '#'
TITLE_TYPE: Tipo TITLE_TYPE: Tipo
TITLE_USED_ON: 'Usado en' TITLE_USED_ON: 'Usado en'
SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension: SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension:
@ -291,6 +294,7 @@ es:
ColumnDateLastModified: 'Fecha de última modificación' ColumnDateLastModified: 'Fecha de última modificación'
ColumnDateLastPublished: 'Fecha de última publicación' ColumnDateLastPublished: 'Fecha de última publicación'
ColumnProblemType: 'Tipo de problema' ColumnProblemType: 'Tipo de problema'
ColumnURL: URL
HasBrokenFile: 'tiene un archivo roto' HasBrokenFile: 'tiene un archivo roto'
HasBrokenLink: 'tiene un enlace roto' HasBrokenLink: 'tiene un enlace roto'
HasBrokenLinkAndFile: 'tiene un enlace y archivo roto' HasBrokenLinkAndFile: 'tiene un enlace y archivo roto'

View File

@ -41,6 +41,8 @@ es_AR:
ANCHORVALUE: Anclar ANCHORVALUE: Anclar
SilverStripe\CMS\Forms\InternalLinkFormFactory: SilverStripe\CMS\Forms\InternalLinkFormFactory:
LINKDESCR: 'Descripción del enlace' LINKDESCR: 'Descripción del enlace'
SilverStripe\CMS\Forms\SiteTreeURLSegmentField:
Edit: Edit
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
FILE: Archivo FILE: Archivo
HEADER: 'Esta página dirigirá al usuarios a otra página' HEADER: 'Esta página dirigirá al usuarios a otra página'

View File

@ -30,6 +30,7 @@ es_MX:
Create: Crear Create: Crear
DUPLICATED: '''{title}'' se ha duplicado con éxito' DUPLICATED: '''{title}'' se ha duplicado con éxito'
DUPLICATEDWITHCHILDREN: '''{title}'' y sub páginas se han duplicado con éxito' DUPLICATEDWITHCHILDREN: '''{title}'' y sub páginas se han duplicado con éxito'
EMAIL: Email
NEWPAGE: 'Nueva {pagetype}' NEWPAGE: 'Nueva {pagetype}'
PAGENOTEXISTS: 'Esta página no existe' PAGENOTEXISTS: 'Esta página no existe'
PAGES: 'Estado de página' PAGES: 'Estado de página'
@ -111,8 +112,10 @@ es_MX:
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
ARCHIVEDSITE: 'Versión de vista previa' ARCHIVEDSITE: 'Versión de vista previa'
ARCHIVEDSITEFROM: 'Sito archivado de' ARCHIVEDSITEFROM: 'Sito archivado de'
CMS: CMS
DRAFT: Borrador DRAFT: Borrador
DRAFTSITE: 'Proyecto del Sitio' DRAFTSITE: 'Proyecto del Sitio'
Email: Email
INSTALL_SUCCESS: 'Instalación exitosa!' INSTALL_SUCCESS: 'Instalación exitosa!'
InstallFilesDeleted: 'Los archivos de instalación han sido eliminados con éxito.' InstallFilesDeleted: 'Los archivos de instalación han sido eliminados con éxito.'
InstallSecurityWarning: 'Por razones de seguridad debes eliminar los archivos de instalación, a menos que tengas planeado reinstalar luego (<em>requiere ingresar como administrador</em>). Además, el servidor web ahora solo requiere permisos de escritura sobre el directorio "assets", puedes remover el acceso de escritura a los demás directorios. <a href="{link}" style="text-align: center;">Haz click aquí para eliminar los archivos de instalación.</a>' InstallSecurityWarning: 'Por razones de seguridad debes eliminar los archivos de instalación, a menos que tengas planeado reinstalar luego (<em>requiere ingresar como administrador</em>). Además, el servidor web ahora solo requiere permisos de escritura sobre el directorio "assets", puedes remover el acceso de escritura a los demás directorios. <a href="{link}" style="text-align: center;">Haz click aquí para eliminar los archivos de instalación.</a>'
@ -143,6 +146,7 @@ es_MX:
Cancel: Cancelar Cancel: Cancelar
Edit: Editar Edit: Editar
HelpChars: 'Carácteres especiales son automáticamente convertidos o eliminados.' HelpChars: 'Carácteres especiales son automáticamente convertidos o eliminados.'
OK: OK
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
DESCRIPTION: 'Redirecciona a una página interna o a una URL externa' DESCRIPTION: 'Redirecciona a una página interna o a una URL externa'
FILE: Archivo FILE: Archivo
@ -233,6 +237,7 @@ es_MX:
many_many_ImageTracking: 'Seguir la Imagen' many_many_ImageTracking: 'Seguir la Imagen'
many_many_LinkTracking: 'Seguir el Enlace' many_many_LinkTracking: 'Seguir el Enlace'
SilverStripe\CMS\Model\SiteTreeFileExtension: SilverStripe\CMS\Model\SiteTreeFileExtension:
TITLE_INDEX: '#'
TITLE_TYPE: Tipo TITLE_TYPE: Tipo
TITLE_USED_ON: 'Usado en' TITLE_USED_ON: 'Usado en'
SilverStripe\CMS\Model\VirtualPage: SilverStripe\CMS\Model\VirtualPage:
@ -258,6 +263,7 @@ es_MX:
ColumnDateLastModified: 'Fecha de última modificación' ColumnDateLastModified: 'Fecha de última modificación'
ColumnDateLastPublished: 'Fecha de última publicación' ColumnDateLastPublished: 'Fecha de última publicación'
ColumnProblemType: 'Tipo de problema' ColumnProblemType: 'Tipo de problema'
ColumnURL: URL
HasBrokenFile: 'tiene un archivo defectuoso' HasBrokenFile: 'tiene un archivo defectuoso'
HasBrokenLink: 'tiene un enlace roto' HasBrokenLink: 'tiene un enlace roto'
HasBrokenLinkAndFile: 'tiene un enlace roto y un archivo defectuoso' HasBrokenLinkAndFile: 'tiene un enlace roto y un archivo defectuoso'

View File

@ -17,6 +17,7 @@ et_EE:
ChoosePageParentMode: 'Valige, kuhu see leht luua' ChoosePageParentMode: 'Valige, kuhu see leht luua'
ChoosePageType: 'Valige lehe tüüp' ChoosePageType: 'Valige lehe tüüp'
Create: Loo Create: Loo
EMAIL: Email
NEWPAGE: 'Uus {pagetype}' NEWPAGE: 'Uus {pagetype}'
PAGENOTEXISTS: 'Antud lehekülge ei eksisteeri' PAGENOTEXISTS: 'Antud lehekülge ei eksisteeri'
PAGESALLOPT: 'Kõik lehed' PAGESALLOPT: 'Kõik lehed'
@ -58,6 +59,7 @@ et_EE:
UNKNOWN: Tundmatu UNKNOWN: Tundmatu
VIEW: vaade VIEW: vaade
VIEWINGVERSION: 'Hetkel kuvatud versioon {version}.' VIEWINGVERSION: 'Hetkel kuvatud versioon {version}.'
WHEN: When
SilverStripe\CMS\Controllers\CMSPageSettingsController: SilverStripe\CMS\Controllers\CMSPageSettingsController:
MENUTITLE: 'Muuda lehte' MENUTITLE: 'Muuda lehte'
SilverStripe\CMS\Controllers\CMSPagesController: SilverStripe\CMS\Controllers\CMSPagesController:
@ -72,6 +74,7 @@ et_EE:
ARCHIVEDSITEFROM: 'Arhiveeritud sait asukohast' ARCHIVEDSITEFROM: 'Arhiveeritud sait asukohast'
DRAFT: Mustand DRAFT: Mustand
DRAFTSITE: 'Mustandi sait' DRAFTSITE: 'Mustandi sait'
Email: Email
INSTALL_SUCCESS: 'Paigaldus oli edukas!' INSTALL_SUCCESS: 'Paigaldus oli edukas!'
InstallFilesDeleted: 'Installifailid on edukalt kustutatud.' InstallFilesDeleted: 'Installifailid on edukalt kustutatud.'
InstallSecurityWarning: 'Turvalisuse põhjustel soovitame nüüd installifailid kustutada, juhul kui te ei plaani hiljem uuesti installida (<em>nõuab administraatorina sisselogimist, vt ülevalt</em>). Edaspidi vajab veebiserver juurdepääsu kirjutamiseks ainult kaustale "assets". Võite eemaldada kõigi teiste kaustade kirjutusõigused. <a href="{link}" style="text-align: center;">Klõpsake siin installifailide kustutamiseks.</a>' InstallSecurityWarning: 'Turvalisuse põhjustel soovitame nüüd installifailid kustutada, juhul kui te ei plaani hiljem uuesti installida (<em>nõuab administraatorina sisselogimist, vt ülevalt</em>). Edaspidi vajab veebiserver juurdepääsu kirjutamiseks ainult kaustale "assets". Võite eemaldada kõigi teiste kaustade kirjutusõigused. <a href="{link}" style="text-align: center;">Klõpsake siin installifailide kustutamiseks.</a>'
@ -209,6 +212,7 @@ et_EE:
ColumnDateLastModified: 'Viimane muutmiskuupäev' ColumnDateLastModified: 'Viimane muutmiskuupäev'
ColumnDateLastPublished: 'Viimane avaldamiskuupäev' ColumnDateLastPublished: 'Viimane avaldamiskuupäev'
ColumnProblemType: 'Probleemi tüüp' ColumnProblemType: 'Probleemi tüüp'
ColumnURL: URL
HasBrokenFile: 'sisaldab katkist faili' HasBrokenFile: 'sisaldab katkist faili'
HasBrokenLink: 'sisaldab katkist linki' HasBrokenLink: 'sisaldab katkist linki'
HasBrokenLinkAndFile: 'sisaldab katkist linki ja faili' HasBrokenLinkAndFile: 'sisaldab katkist linki ja faili'

View File

@ -106,6 +106,7 @@ fa_IR:
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
ARCHIVEDSITE: 'نسخه پیش‌نمایش' ARCHIVEDSITE: 'نسخه پیش‌نمایش'
ARCHIVEDSITEFROM: 'سایت بایگانی شده از' ARCHIVEDSITEFROM: 'سایت بایگانی شده از'
CMS: CMS
DRAFT: پیش‌نویس DRAFT: پیش‌نویس
DRAFTSITE: 'سایت پیش‌نویس' DRAFTSITE: 'سایت پیش‌نویس'
Email: ایمیل Email: ایمیل
@ -233,6 +234,7 @@ fa_IR:
many_many_ImageTracking: 'ردیابی تصویر' many_many_ImageTracking: 'ردیابی تصویر'
many_many_LinkTracking: 'ردیابی پیوند' many_many_LinkTracking: 'ردیابی پیوند'
SilverStripe\CMS\Model\SiteTreeFileExtension: SilverStripe\CMS\Model\SiteTreeFileExtension:
TITLE_INDEX: '#'
TITLE_TYPE: نوع TITLE_TYPE: نوع
TITLE_USED_ON: 'استفاده شده در' TITLE_USED_ON: 'استفاده شده در'
SilverStripe\CMS\Model\SiteTreeLink: SilverStripe\CMS\Model\SiteTreeLink:

View File

@ -115,6 +115,7 @@ fi:
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
ARCHIVEDSITE: 'Esikatselu versio' ARCHIVEDSITE: 'Esikatselu versio'
ARCHIVEDSITEFROM: 'Arkistoitu sivusto lähteestä:' ARCHIVEDSITEFROM: 'Arkistoitu sivusto lähteestä:'
CMS: CMS
DRAFT: Luonnos DRAFT: Luonnos
DRAFTSITE: Luonnossivusto DRAFTSITE: Luonnossivusto
Email: Sähköposti Email: Sähköposti
@ -149,6 +150,7 @@ fi:
EMPTY: 'Ole hyvä ja anna URL-osoitteen osio tai napsauta Peruuta' EMPTY: 'Ole hyvä ja anna URL-osoitteen osio tai napsauta Peruuta'
Edit: Muokkaa Edit: Muokkaa
HelpChars: 'Erikoismerkit muunnetaan tai poistetaan automaattisesti.' HelpChars: 'Erikoismerkit muunnetaan tai poistetaan automaattisesti.'
OK: OK
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
DESCRIPTION: 'Edelleenohjaa toiselle sisäiselle sivulle tai ulkoiseen URL-osoitteeseen' DESCRIPTION: 'Edelleenohjaa toiselle sisäiselle sivulle tai ulkoiseen URL-osoitteeseen'
FILE: Tiedosto FILE: Tiedosto
@ -272,6 +274,7 @@ fi:
many_many_ImageTracking: 'Kuvan seuranta' many_many_ImageTracking: 'Kuvan seuranta'
many_many_LinkTracking: 'Linkin seuranta' many_many_LinkTracking: 'Linkin seuranta'
SilverStripe\CMS\Model\SiteTreeFileExtension: SilverStripe\CMS\Model\SiteTreeFileExtension:
TITLE_INDEX: '#'
TITLE_TYPE: Tyyppi TITLE_TYPE: Tyyppi
TITLE_USED_ON: 'Käytössä:' TITLE_USED_ON: 'Käytössä:'
SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension: SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension:

View File

@ -114,6 +114,7 @@ fi_FI:
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
ARCHIVEDSITE: 'Esikatselu versio' ARCHIVEDSITE: 'Esikatselu versio'
ARCHIVEDSITEFROM: 'Arkistoitu sivusto lähteestä:' ARCHIVEDSITEFROM: 'Arkistoitu sivusto lähteestä:'
CMS: CMS
DRAFT: Luonnos DRAFT: Luonnos
DRAFTSITE: Luonnossivusto DRAFTSITE: Luonnossivusto
Email: Sähköposti Email: Sähköposti
@ -146,6 +147,7 @@ fi_FI:
Cancel: Peruuta Cancel: Peruuta
Edit: Muokkaa Edit: Muokkaa
HelpChars: 'Erikoismerkit muunnetaan tai poistetaan automaattisesti.' HelpChars: 'Erikoismerkit muunnetaan tai poistetaan automaattisesti.'
OK: OK
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
DESCRIPTION: 'Edelleenohjaa toiselle sisäiselle sivulle tai ulkoiseen URL-osoitteeseen' DESCRIPTION: 'Edelleenohjaa toiselle sisäiselle sivulle tai ulkoiseen URL-osoitteeseen'
HEADER: 'Tämä sivu ohjaa käyttäjän toiselle sivulle' HEADER: 'Tämä sivu ohjaa käyttäjän toiselle sivulle'
@ -260,6 +262,7 @@ fi_FI:
many_many_ImageTracking: 'Kuvan seuranta' many_many_ImageTracking: 'Kuvan seuranta'
many_many_LinkTracking: 'Linkin seuranta' many_many_LinkTracking: 'Linkin seuranta'
SilverStripe\CMS\Model\SiteTreeFileExtension: SilverStripe\CMS\Model\SiteTreeFileExtension:
TITLE_INDEX: '#'
TITLE_TYPE: Tyyppi TITLE_TYPE: Tyyppi
TITLE_USED_ON: 'Käytössä:' TITLE_USED_ON: 'Käytössä:'
SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension: SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension:

View File

@ -19,6 +19,8 @@ fo:
Password: Loyniorð Password: Loyniorð
SilverStripe\CMS\Forms\InternalLinkFormFactory: SilverStripe\CMS\Forms\InternalLinkFormFactory:
LINKDESCR: 'Leinku frágreiðing' LINKDESCR: 'Leinku frágreiðing'
SilverStripe\CMS\Forms\SiteTreeURLSegmentField:
Edit: Edit
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
FILE: Fíla FILE: Fíla
REDIRECTTO: 'Víðarisend til' REDIRECTTO: 'Víðarisend til'

View File

@ -14,6 +14,7 @@ fr:
SilverStripe\CMS\Controllers\CMSMain: SilverStripe\CMS\Controllers\CMSMain:
ACCESS: "Accès à la section «\_{title}\_»" ACCESS: "Accès à la section «\_{title}\_»"
ACCESS_HELP: 'Autoriser la visualisation de la section contenant l''arborescence et le contenu. Les autorisations de voir ou modifier le contenu peuvent être gérées dans les menus déroulants spécifiques à chaque page, ainsi que dans les "permissions de contenu".' ACCESS_HELP: 'Autoriser la visualisation de la section contenant l''arborescence et le contenu. Les autorisations de voir ou modifier le contenu peuvent être gérées dans les menus déroulants spécifiques à chaque page, ainsi que dans les "permissions de contenu".'
ARCHIVE: Archive
ARCHIVEDPAGE: 'Page ''{title}'' archivée' ARCHIVEDPAGE: 'Page ''{title}'' archivée'
AddNew: 'Ajouter une nouvelle page' AddNew: 'Ajouter une nouvelle page'
AddNewButton: Ajouter AddNewButton: Ajouter
@ -29,6 +30,7 @@ fr:
Create: Créer Create: Créer
DUPLICATED: '''{title}'' dupliqué avec succès' DUPLICATED: '''{title}'' dupliqué avec succès'
DUPLICATEDWITHCHILDREN: '''{title}'' et ses enfants dupliqués avec succès' DUPLICATEDWITHCHILDREN: '''{title}'' et ses enfants dupliqués avec succès'
EMAIL: Email
NEWPAGE: 'Nouveau {pagetype}' NEWPAGE: 'Nouveau {pagetype}'
PAGENOTEXISTS: 'Cette page n''existe pas' PAGENOTEXISTS: 'Cette page n''existe pas'
PAGES: 'Statut de la page' PAGES: 'Statut de la page'
@ -94,6 +96,7 @@ fr:
SilverStripe\CMS\Controllers\CMSPagesController: SilverStripe\CMS\Controllers\CMSPagesController:
FILTER: Filtrer FILTER: Filtrer
ListView: 'Affichage en liste' ListView: 'Affichage en liste'
MENUTITLE: Pages
TreeView: Arborescence TreeView: Arborescence
SilverStripe\CMS\Controllers\CMSSiteTreeFilter_ChangedPages: SilverStripe\CMS\Controllers\CMSSiteTreeFilter_ChangedPages:
Title: 'Page modifiées' Title: 'Page modifiées'
@ -112,8 +115,10 @@ fr:
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
ARCHIVEDSITE: 'Aperçu de cette version' ARCHIVEDSITE: 'Aperçu de cette version'
ARCHIVEDSITEFROM: 'Site archivé depuis' ARCHIVEDSITEFROM: 'Site archivé depuis'
CMS: CMS
DRAFT: Brouillon DRAFT: Brouillon
DRAFTSITE: 'Site Brouillon' DRAFTSITE: 'Site Brouillon'
Email: Email
INSTALL_SUCCESS: 'Installation terminée!' INSTALL_SUCCESS: 'Installation terminée!'
InstallFilesDeleted: 'Les fichiers d''installation ont été supprimés avec succès' InstallFilesDeleted: 'Les fichiers d''installation ont été supprimés avec succès'
InstallSecurityWarning: "Pour des raisons de sécurité vous devriez maintenant supprimer les fichiers dinstallation, à moins que vous nayez prévu de réinstaller le système ultérieurement (<em>ce qui nécessite de se connecter comme administrateur, voir plus haut</em>). Désormais, votre serveur naura besoin de droits d'accès en écriture que pour le dossier «\_assets\_», vous pouvez donc les révoquer pour tous les autres dossiers. <a href=\"{link}\" style=\"text-align: center;\">Cliquez ici pour supprimer les fichiers dinstallation.</a>" InstallSecurityWarning: "Pour des raisons de sécurité vous devriez maintenant supprimer les fichiers dinstallation, à moins que vous nayez prévu de réinstaller le système ultérieurement (<em>ce qui nécessite de se connecter comme administrateur, voir plus haut</em>). Désormais, votre serveur naura besoin de droits d'accès en écriture que pour le dossier «\_assets\_», vous pouvez donc les révoquer pour tous les autres dossiers. <a href=\"{link}\" style=\"text-align: center;\">Cliquez ici pour supprimer les fichiers dinstallation.</a>"
@ -145,11 +150,13 @@ fr:
EMPTY: 'Entrez un segment d''URL ou cliquez sur annuler' EMPTY: 'Entrez un segment d''URL ou cliquez sur annuler'
Edit: Editer Edit: Editer
HelpChars: 'Les caractères spéciaux sont automatiquement convertis ou supprimés.' HelpChars: 'Les caractères spéciaux sont automatiquement convertis ou supprimés.'
OK: OK
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
DESCRIPTION: 'Redirige vers une page interne ou une URL externe' DESCRIPTION: 'Redirige vers une page interne ou une URL externe'
FILE: Fichier FILE: Fichier
HEADER: 'Cette page va rediriger les utilisateurs vers une autre page' HEADER: 'Cette page va rediriger les utilisateurs vers une autre page'
OTHERURL: 'URL d''un autre site web' OTHERURL: 'URL d''un autre site web'
PLURALNAME: 'Base Pages'
PLURALS: PLURALS:
one: 'Une page de redirection' one: 'Une page de redirection'
other: '{count} pages de redirection' other: '{count} pages de redirection'
@ -206,6 +213,7 @@ fr:
LINKSALREADYUNIQUE: ' {url} est déjà unique' LINKSALREADYUNIQUE: ' {url} est déjà unique'
LINKSCHANGEDTO: '{url1} changée pour {url2}' LINKSCHANGEDTO: '{url1} changée pour {url2}'
MENUTITLE: 'Titre dans les menus' MENUTITLE: 'Titre dans les menus'
METADESC: 'Meta Description'
METADESCHELP: 'Les moteurs de recherche reprennent cette description dans leurs résultats (bien quelle nait pas dinfluence sur le classement).' METADESCHELP: 'Les moteurs de recherche reprennent cette description dans leurs résultats (bien quelle nait pas dinfluence sur le classement).'
METAEXTRA: 'Balises Méta personnalisées' METAEXTRA: 'Balises Méta personnalisées'
MODIFIEDONDRAFTHELP: 'Des changements effectués sur cette page n''''ont pas été publiés' MODIFIEDONDRAFTHELP: 'Des changements effectués sur cette page n''''ont pas été publiés'
@ -225,6 +233,7 @@ fr:
PARENTTYPE_SUBPAGE: 'Sous-page d''une page parente (choisir en-dessous) ' PARENTTYPE_SUBPAGE: 'Sous-page d''une page parente (choisir en-dessous) '
PERMISSION_GRANTACCESS_DESCRIPTION: 'Gérer les droits d''accès au contenu' PERMISSION_GRANTACCESS_DESCRIPTION: 'Gérer les droits d''accès au contenu'
PERMISSION_GRANTACCESS_HELP: 'Autoriser le réglage de restrictions spécifiques dans la section "Pages".' PERMISSION_GRANTACCESS_HELP: 'Autoriser le réglage de restrictions spécifiques dans la section "Pages".'
PLURALNAME: Pages
PLURALS: PLURALS:
many: '{count} pages' many: '{count} pages'
one: 'Une page' one: 'Une page'
@ -236,6 +245,7 @@ fr:
REORGANISE_HELP: 'Réorganiser les pages du site par glisser & déposer.' REORGANISE_HELP: 'Réorganiser les pages du site par glisser & déposer.'
SHOWINMENUS: 'Afficher dans les menus ?' SHOWINMENUS: 'Afficher dans les menus ?'
SHOWINSEARCH: 'Afficher dans les recherches ?' SHOWINSEARCH: 'Afficher dans les recherches ?'
SINGULARNAME: Page
TABBEHAVIOUR: Comportement TABBEHAVIOUR: Comportement
TABCONTENT: 'Contenu principal' TABCONTENT: 'Contenu principal'
TABDEPENDENT: 'Pages dépendantes' TABDEPENDENT: 'Pages dépendantes'
@ -257,21 +267,28 @@ fr:
db_Sort: Tri db_Sort: Tri
db_Title: Titre db_Title: Titre
db_URLSegment: 'Segment d''URL' db_URLSegment: 'Segment d''URL'
db_Version: Version
has_one_Parent: 'Page parente' has_one_Parent: 'Page parente'
many_many_BackLinkTracking: 'Suivi des liens retour' many_many_BackLinkTracking: 'Suivi des liens retour'
many_many_ImageTracking: 'Suivi des images' many_many_ImageTracking: 'Suivi des images'
many_many_LinkTracking: 'Suivi des Liens' many_many_LinkTracking: 'Suivi des Liens'
SilverStripe\CMS\Model\SiteTreeFileExtension: SilverStripe\CMS\Model\SiteTreeFileExtension:
TITLE_INDEX: '#'
TITLE_TYPE: Type
TITLE_USED_ON: 'Utilisé dans' TITLE_USED_ON: 'Utilisé dans'
SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension:
USAGE: Usage
SilverStripe\CMS\Model\SiteTreeLink: SilverStripe\CMS\Model\SiteTreeLink:
PLURALNAME: 'Liens Site Tree' PLURALNAME: 'Liens Site Tree'
SINGULARNAME: 'Lien Site Tree' SINGULARNAME: 'Lien Site Tree'
has_one_Parent: Parent
SilverStripe\CMS\Model\VirtualPage: SilverStripe\CMS\Model\VirtualPage:
CHOOSE: 'Page liée' CHOOSE: 'Page liée'
DESCRIPTION: 'Affiche le contenu d''une autre page' DESCRIPTION: 'Affiche le contenu d''une autre page'
EditLink: éditer EditLink: éditer
HEADER: 'Ceci est une page virtuelle' HEADER: 'Ceci est une page virtuelle'
HEADERWITHLINK: 'Ceci est une page virtuelle dupliquant le contenu de "{title}" ({link})' HEADERWITHLINK: 'Ceci est une page virtuelle dupliquant le contenu de "{title}" ({link})'
PLURALNAME: 'Base Pages'
PLURALS: PLURALS:
one: 'Une page virtuelle' one: 'Une page virtuelle'
other: '{count} pages virtuelles' other: '{count} pages virtuelles'
@ -290,6 +307,7 @@ fr:
ColumnDateLastModified: 'Date de la dernière modification' ColumnDateLastModified: 'Date de la dernière modification'
ColumnDateLastPublished: 'Date de la dernière publication' ColumnDateLastPublished: 'Date de la dernière publication'
ColumnProblemType: 'Type de problème' ColumnProblemType: 'Type de problème'
ColumnURL: URL
HasBrokenFile: 'comporte un fichier brisé' HasBrokenFile: 'comporte un fichier brisé'
HasBrokenLink: 'comporte un lien brisé' HasBrokenLink: 'comporte un lien brisé'
HasBrokenLinkAndFile: 'comporte un lien et un fichier brisés' HasBrokenLinkAndFile: 'comporte un lien et un fichier brisés'

View File

@ -70,6 +70,8 @@ gl_ES:
ANCHORVALUE: Áncora ANCHORVALUE: Áncora
SilverStripe\CMS\Forms\InternalLinkFormFactory: SilverStripe\CMS\Forms\InternalLinkFormFactory:
LINKDESCR: 'Descrición da ligazón' LINKDESCR: 'Descrición da ligazón'
SilverStripe\CMS\Forms\SiteTreeURLSegmentField:
Edit: Edit
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
FILE: Ficheiro FILE: Ficheiro
HEADER: 'Esta páxina redirixirá os usuarios a outra páxina' HEADER: 'Esta páxina redirixirá os usuarios a outra páxina'

View File

@ -87,6 +87,7 @@ he_IL:
SilverStripe\CMS\Forms\InternalLinkFormFactory: SilverStripe\CMS\Forms\InternalLinkFormFactory:
LINKDESCR: 'תאור הקישור' LINKDESCR: 'תאור הקישור'
SilverStripe\CMS\Forms\SiteTreeURLSegmentField: SilverStripe\CMS\Forms\SiteTreeURLSegmentField:
Edit: Edit
HelpChars: ' תווים מיוחדים מומרים אוטומטית או שהם מוסרים.' HelpChars: ' תווים מיוחדים מומרים אוטומטית או שהם מוסרים.'
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
FILE: קובץ FILE: קובץ

View File

@ -25,6 +25,7 @@ hr:
Create: Kreiraj Create: Kreiraj
DUPLICATED: 'Dupliciran ''{title}'' uspješno' DUPLICATED: 'Dupliciran ''{title}'' uspješno'
DUPLICATEDWITHCHILDREN: 'Dupliciran ''{title}'' i podstranice uspješno' DUPLICATEDWITHCHILDREN: 'Dupliciran ''{title}'' i podstranice uspješno'
EMAIL: Email
NEWPAGE: 'Novi {pagetype}' NEWPAGE: 'Novi {pagetype}'
PAGENOTEXISTS: 'Stranica ne postoji' PAGENOTEXISTS: 'Stranica ne postoji'
PAGES: 'Status stranice' PAGES: 'Status stranice'
@ -86,6 +87,7 @@ hr:
SilverStripe\CMS\Controllers\CMSPageSettingsController: SilverStripe\CMS\Controllers\CMSPageSettingsController:
MENUTITLE: 'Uredi stranicu' MENUTITLE: 'Uredi stranicu'
SilverStripe\CMS\Controllers\CMSPagesController: SilverStripe\CMS\Controllers\CMSPagesController:
FILTER: Filter
ListView: Lista ListView: Lista
MENUTITLE: Stranice MENUTITLE: Stranice
TreeView: Stablo TreeView: Stablo
@ -106,8 +108,10 @@ hr:
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
ARCHIVEDSITE: 'Pregledna verzija' ARCHIVEDSITE: 'Pregledna verzija'
ARCHIVEDSITEFROM: 'Arhivirana stranica iz' ARCHIVEDSITEFROM: 'Arhivirana stranica iz'
CMS: CMS
DRAFT: Predložak DRAFT: Predložak
DRAFTSITE: Predložak DRAFTSITE: Predložak
Email: Email
INSTALL_SUCCESS: 'Instalacija uspješna!' INSTALL_SUCCESS: 'Instalacija uspješna!'
InstallFilesDeleted: 'Instalacijske datoteke su uspješno obrisane.' InstallFilesDeleted: 'Instalacijske datoteke su uspješno obrisane.'
InstallSecurityWarning: 'Zbog sigurnosnih razloga trebali bi ste obrisati instalacijske datoteke, osima ako planirate reinstalaciju kasnije (<em>zahtjeva administracijsku prijavu, pogledaj iznad</em>). Web server sada treba samo dozvole pisanja na "assets" direktorij, pa možete maknuti pravo pisanja sa svih drugih direktorija. <a href="{link}" style="text-align: center;">kliknite ovjde za brisanje instalacijskih datoteka.</a>' InstallSecurityWarning: 'Zbog sigurnosnih razloga trebali bi ste obrisati instalacijske datoteke, osima ako planirate reinstalaciju kasnije (<em>zahtjeva administracijsku prijavu, pogledaj iznad</em>). Web server sada treba samo dozvole pisanja na "assets" direktorij, pa možete maknuti pravo pisanja sa svih drugih direktorija. <a href="{link}" style="text-align: center;">kliknite ovjde za brisanje instalacijskih datoteka.</a>'
@ -138,6 +142,7 @@ hr:
Cancel: Odustani Cancel: Odustani
Edit: Uredi Edit: Uredi
HelpChars: 'Posebni znakovi se automatski pretvaraju ili uklanjaju.' HelpChars: 'Posebni znakovi se automatski pretvaraju ili uklanjaju.'
OK: OK
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
DESCRIPTION: 'Preusmjerava na internu stranicu ili vanjski URL' DESCRIPTION: 'Preusmjerava na internu stranicu ili vanjski URL'
FILE: Datoteka FILE: Datoteka
@ -240,6 +245,7 @@ hr:
many_many_ImageTracking: 'Praćenje slika' many_many_ImageTracking: 'Praćenje slika'
many_many_LinkTracking: 'Praćenje linkova' many_many_LinkTracking: 'Praćenje linkova'
SilverStripe\CMS\Model\SiteTreeFileExtension: SilverStripe\CMS\Model\SiteTreeFileExtension:
TITLE_INDEX: '#'
TITLE_TYPE: Tip TITLE_TYPE: Tip
TITLE_USED_ON: 'Korišteno na' TITLE_USED_ON: 'Korišteno na'
SilverStripe\CMS\Model\SiteTreeLink: SilverStripe\CMS\Model\SiteTreeLink:

View File

@ -96,6 +96,7 @@ hu:
Cancel: Mégsem Cancel: Mégsem
Edit: Szerkeszt Edit: Szerkeszt
HelpChars: 'A speciális karakterek automatikusan konvertálódnak vagy törlődnek.' HelpChars: 'A speciális karakterek automatikusan konvertálódnak vagy törlődnek.'
OK: OK
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
FILE: Fájl FILE: Fájl
HEADER: 'Ez az oldal egy másik oldalra fogja írányítani a felhasználókat' HEADER: 'Ez az oldal egy másik oldalra fogja írányítani a felhasználókat'

View File

@ -19,6 +19,7 @@ id:
Create: Buat Create: Buat
DUPLICATED: '''{title}'' berhasil diduplikasi' DUPLICATED: '''{title}'' berhasil diduplikasi'
DUPLICATEDWITHCHILDREN: '''{title}'' dan turunannya berhasil diduplikasi' DUPLICATEDWITHCHILDREN: '''{title}'' dan turunannya berhasil diduplikasi'
EMAIL: Email
NEWPAGE: '{pagetype} baru' NEWPAGE: '{pagetype} baru'
PAGENOTEXISTS: 'Laman ini tidak ada' PAGENOTEXISTS: 'Laman ini tidak ada'
PAGESALLOPT: 'Semua laman' PAGESALLOPT: 'Semua laman'
@ -79,8 +80,10 @@ id:
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
ARCHIVEDSITE: 'Versi pratinjau' ARCHIVEDSITE: 'Versi pratinjau'
ARCHIVEDSITEFROM: 'Arsip dari' ARCHIVEDSITEFROM: 'Arsip dari'
CMS: CMS
DRAFT: Draf DRAFT: Draf
DRAFTSITE: 'Draf situs' DRAFTSITE: 'Draf situs'
Email: Email
INSTALL_SUCCESS: 'Penginstalan berhasil!' INSTALL_SUCCESS: 'Penginstalan berhasil!'
InstallFilesDeleted: 'Berkas penginstalan telah berhasil dihapus.' InstallFilesDeleted: 'Berkas penginstalan telah berhasil dihapus.'
InstallSecurityWarning: 'Untuk alasan keamanan, sekarang Anda perlu menghapus berkas-berkas penginstalan, kecuali Anda berencana untuk melakukan penginstalan ulang lagi (<em>memerlukan login admin, lihat di atas</em>). Selanjutnya server juga memerlukan akses tulis ke folder "assets", Anda dapat mencabut akses tulis dari folder lainnya. <a href="{link}" style="text-align: center;">Klik di sini untuk menghapus berkas-berkas penginstalan.</a>' InstallSecurityWarning: 'Untuk alasan keamanan, sekarang Anda perlu menghapus berkas-berkas penginstalan, kecuali Anda berencana untuk melakukan penginstalan ulang lagi (<em>memerlukan login admin, lihat di atas</em>). Selanjutnya server juga memerlukan akses tulis ke folder "assets", Anda dapat mencabut akses tulis dari folder lainnya. <a href="{link}" style="text-align: center;">Klik di sini untuk menghapus berkas-berkas penginstalan.</a>'
@ -106,7 +109,9 @@ id:
LINKDESCR: 'Deskripsi tautan' LINKDESCR: 'Deskripsi tautan'
SilverStripe\CMS\Forms\SiteTreeURLSegmentField: SilverStripe\CMS\Forms\SiteTreeURLSegmentField:
Cancel: Batal Cancel: Batal
Edit: Edit
HelpChars: 'Karakter khusus akan dikonversi secara otomatis atau dihapus.' HelpChars: 'Karakter khusus akan dikonversi secara otomatis atau dihapus.'
OK: OK
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
FILE: Berkas FILE: Berkas
HEADER: 'Laman ini akan mengarahkan pengguna ke laman lain' HEADER: 'Laman ini akan mengarahkan pengguna ke laman lain'
@ -161,6 +166,7 @@ id:
METAEXTRA: 'Penanda Meta' METAEXTRA: 'Penanda Meta'
MODIFIEDONDRAFTHELP: 'Laman memiliki perubahan yang tidak terbit' MODIFIEDONDRAFTHELP: 'Laman memiliki perubahan yang tidak terbit'
MODIFIEDONDRAFTSHORT: Diubah MODIFIEDONDRAFTSHORT: Diubah
MetadataToggle: Metadata
MoreOptions: 'Pilihan lain' MoreOptions: 'Pilihan lain'
NOTPUBLISHED: 'Tidak diterbitkan' NOTPUBLISHED: 'Tidak diterbitkan'
OBSOLETECLASS: 'Jenis laman {type} ini sudah usang. Menyimpannya akan memperbarui jenisnya dan Anda kemungkinan akan kehilangan data' OBSOLETECLASS: 'Jenis laman {type} ini sudah usang. Menyimpannya akan memperbarui jenisnya dan Anda kemungkinan akan kehilangan data'
@ -210,6 +216,7 @@ id:
SilverStripe\CMS\Model\VirtualPage: SilverStripe\CMS\Model\VirtualPage:
CHOOSE: 'Laman Tertaut' CHOOSE: 'Laman Tertaut'
DESCRIPTION: 'Tampilkan konten laman lain' DESCRIPTION: 'Tampilkan konten laman lain'
EditLink: edit
HEADER: 'Ini adalah laman virtual' HEADER: 'Ini adalah laman virtual'
HEADERWITHLINK: 'Ini adalah laman virtual dengan konten salinan dari "{title}" ({link})' HEADERWITHLINK: 'Ini adalah laman virtual dengan konten salinan dari "{title}" ({link})'
PLURALNAME: 'Laman Dasar' PLURALNAME: 'Laman Dasar'
@ -228,6 +235,7 @@ id:
ColumnDateLastModified: 'Tanggal terakhir modifikasi' ColumnDateLastModified: 'Tanggal terakhir modifikasi'
ColumnDateLastPublished: 'Tanggal terbit terakhir' ColumnDateLastPublished: 'Tanggal terbit terakhir'
ColumnProblemType: 'Jenis masalah' ColumnProblemType: 'Jenis masalah'
ColumnURL: URL
HasBrokenFile: 'terdapat berkas yang rusak' HasBrokenFile: 'terdapat berkas yang rusak'
HasBrokenLink: 'terdapat tautan yang rusak' HasBrokenLink: 'terdapat tautan yang rusak'
HasBrokenLinkAndFile: 'terdapat berkas dan tautan yang rusak' HasBrokenLinkAndFile: 'terdapat berkas dan tautan yang rusak'

View File

@ -5,6 +5,7 @@ id_ID:
CANT_REORGANISE: 'Anda tidak diijinkan mengubah laman Tingkat Atas. Pengubahan Anda tidak tersimpan.' CANT_REORGANISE: 'Anda tidak diijinkan mengubah laman Tingkat Atas. Pengubahan Anda tidak tersimpan.'
Cancel: Batal Cancel: Batal
Create: Buat Create: Buat
EMAIL: Email
PAGETYPEANYOPT: Semua PAGETYPEANYOPT: Semua
PLEASESAVE: 'Mohon Simpan Laman: Laman ini tidak dapat diperbarui karena belum disimpan.' PLEASESAVE: 'Mohon Simpan Laman: Laman ini tidak dapat diperbarui karena belum disimpan.'
REORGANISATIONSUCCESSFUL: 'Pengaturan ulang struktur situs berhasil.' REORGANISATIONSUCCESSFUL: 'Pengaturan ulang struktur situs berhasil.'
@ -19,6 +20,7 @@ id_ID:
SilverStripe\CMS\Controllers\CMSPagesController: SilverStripe\CMS\Controllers\CMSPagesController:
FILTER: Saring FILTER: Saring
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
Email: Email
LOGOUT: Keluar LOGOUT: Keluar
NOTLOGGEDIN: 'Belum masuk' NOTLOGGEDIN: 'Belum masuk'
Password: 'Kata kunci' Password: 'Kata kunci'
@ -29,6 +31,7 @@ id_ID:
LINKDESCR: 'Deskripsi tautan' LINKDESCR: 'Deskripsi tautan'
SilverStripe\CMS\Forms\SiteTreeURLSegmentField: SilverStripe\CMS\Forms\SiteTreeURLSegmentField:
Cancel: Batal Cancel: Batal
Edit: Edit
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
FILE: Berkas FILE: Berkas
REDIRECTTOEXTERNAL: 'Situs lain' REDIRECTTOEXTERNAL: 'Situs lain'
@ -43,6 +46,7 @@ id_ID:
db_Title: Judul db_Title: Judul
SilverStripe\CMS\Reports\BrokenLinksReport: SilverStripe\CMS\Reports\BrokenLinksReport:
Any: Semua Any: Semua
ColumnURL: URL
SilverStripe\CMS\Search\SearchForm: SilverStripe\CMS\Search\SearchForm:
FILTERLABELTEXT: Cari FILTERLABELTEXT: Cari
GO: Lanjut GO: Lanjut

View File

@ -30,6 +30,7 @@ it:
Create: Crea Create: Crea
DUPLICATED: '''{title}'' duplicato correttamente' DUPLICATED: '''{title}'' duplicato correttamente'
DUPLICATEDWITHCHILDREN: '''{title}'' e figlie duplicate con successo' DUPLICATEDWITHCHILDREN: '''{title}'' e figlie duplicate con successo'
EMAIL: Email
NEWPAGE: 'Nuova {pagetype}' NEWPAGE: 'Nuova {pagetype}'
PAGENOTEXISTS: 'Questa pagina non esiste' PAGENOTEXISTS: 'Questa pagina non esiste'
PAGES: 'Stato pagina' PAGES: 'Stato pagina'
@ -116,8 +117,10 @@ it:
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
ARCHIVEDSITE: 'Anteprima versione' ARCHIVEDSITE: 'Anteprima versione'
ARCHIVEDSITEFROM: 'Sito archiviato da' ARCHIVEDSITEFROM: 'Sito archiviato da'
CMS: CMS
DRAFT: Bozza DRAFT: Bozza
DRAFTSITE: 'Sito Bozza' DRAFTSITE: 'Sito Bozza'
Email: Email
INSTALL_SUCCESS: 'Installazione conclusa con successo!' INSTALL_SUCCESS: 'Installazione conclusa con successo!'
InstallFilesDeleted: 'I file di installazione sono stati eliminati con successo.' InstallFilesDeleted: 'I file di installazione sono stati eliminati con successo.'
InstallSecurityWarning: 'Ora per motivi di sicurezza devi eliminare i file di installazione, a meno di non aver pianificato una nuova installazione (<em>richiede accesso da amministratore, vedi sopra</em>). Inoltre il server web richiede permessi di scrittura per la sola cartella "assets", puoi quindi rimuovere i permessi di scrittura da tutte le altre cartelle. <a href="{link}" style="text-align: center;">Clicca qui per cancellare i file di installazione.</a>' InstallSecurityWarning: 'Ora per motivi di sicurezza devi eliminare i file di installazione, a meno di non aver pianificato una nuova installazione (<em>richiede accesso da amministratore, vedi sopra</em>). Inoltre il server web richiede permessi di scrittura per la sola cartella "assets", puoi quindi rimuovere i permessi di scrittura da tutte le altre cartelle. <a href="{link}" style="text-align: center;">Clicca qui per cancellare i file di installazione.</a>'
@ -129,6 +132,7 @@ it:
NOTLOGGEDIN: 'Non connesso' NOTLOGGEDIN: 'Non connesso'
PUBLISHED: Pubblicato PUBLISHED: Pubblicato
PUBLISHEDSITE: 'Sito pubblicato' PUBLISHEDSITE: 'Sito pubblicato'
Password: Password
PostInstallTutorialIntro: 'Questo sito web è una versione semplificata di un sito SilverStripe 3. Per estenderlo, dai un''occhiata a {link}.' PostInstallTutorialIntro: 'Questo sito web è una versione semplificata di un sito SilverStripe 3. Per estenderlo, dai un''occhiata a {link}.'
StartEditing: 'Puoi iniziare a modificare i contenuti del sito aprendo <a href="{link}">il CMS</a>.' StartEditing: 'Puoi iniziare a modificare i contenuti del sito aprendo <a href="{link}">il CMS</a>.'
UNVERSIONEDPREVIEW: Anteprima UNVERSIONEDPREVIEW: Anteprima
@ -148,8 +152,10 @@ it:
EMPTY: 'Inserire un segmento URL o cliccare annulla' EMPTY: 'Inserire un segmento URL o cliccare annulla'
Edit: Modifica Edit: Modifica
HelpChars: 'I caratteri speciali sono automaticamente convertiti o eliminati.' HelpChars: 'I caratteri speciali sono automaticamente convertiti o eliminati.'
OK: OK
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
DESCRIPTION: 'Reinoltra ad una pagina interna o una URL esterna' DESCRIPTION: 'Reinoltra ad una pagina interna o una URL esterna'
FILE: File
HEADER: 'Questa pagina redirigerà gli utenti su un''altra' HEADER: 'Questa pagina redirigerà gli utenti su un''altra'
OTHERURL: 'Altro indirizzo del sito web' OTHERURL: 'Altro indirizzo del sito web'
PLURALNAME: 'Pagine Base' PLURALNAME: 'Pagine Base'
@ -191,6 +197,7 @@ it:
DEFAULTCONTACTCONTENT: '<p>Puoi riempire questa pagina con i tuoi contenuti, oppure cancellarla e creare le tue pagine.</p>' DEFAULTCONTACTCONTENT: '<p>Puoi riempire questa pagina con i tuoi contenuti, oppure cancellarla e creare le tue pagine.</p>'
DEFAULTCONTACTTITLE: Contattaci DEFAULTCONTACTTITLE: Contattaci
DEFAULTHOMECONTENT: '<p>Benvenuto in SilverStripe! Questa è la home page di default. Puoi modificare questa pagina direttamente <a href="admin/">dal CMS</a>.</p><p>Puoi accedere alla <a href="http://docs.silverstripe.org">documentazione per gli sviluppatori</a> o partire dalle <a href="http://www.silverstripe.org/learn/lessons">lezioni di SilverStripe</a>.</p>' DEFAULTHOMECONTENT: '<p>Benvenuto in SilverStripe! Questa è la home page di default. Puoi modificare questa pagina direttamente <a href="admin/">dal CMS</a>.</p><p>Puoi accedere alla <a href="http://docs.silverstripe.org">documentazione per gli sviluppatori</a> o partire dalle <a href="http://www.silverstripe.org/learn/lessons">lezioni di SilverStripe</a>.</p>'
DEFAULTHOMETITLE: Home
DEPENDENT_NOTE: 'Le seguenti pagine dipendono da questa pagina. Queste includono pagine virtuali, pagine di redirezione e pagine con link nel contenuto.' DEPENDENT_NOTE: 'Le seguenti pagine dipendono da questa pagina. Queste includono pagine virtuali, pagine di redirezione e pagine con link nel contenuto.'
DESCRIPTION: 'Pagina di contenuto generico' DESCRIPTION: 'Pagina di contenuto generico'
DependtPageColumnLinkType: 'Tipo di link' DependtPageColumnLinkType: 'Tipo di link'
@ -273,6 +280,7 @@ it:
many_many_ImageTracking: 'Monitoraggio immagine' many_many_ImageTracking: 'Monitoraggio immagine'
many_many_LinkTracking: 'Monitoraggio link' many_many_LinkTracking: 'Monitoraggio link'
SilverStripe\CMS\Model\SiteTreeFileExtension: SilverStripe\CMS\Model\SiteTreeFileExtension:
TITLE_INDEX: '#'
TITLE_TYPE: Tipo TITLE_TYPE: Tipo
TITLE_USED_ON: 'Usato in' TITLE_USED_ON: 'Usato in'
SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension: SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension:
@ -311,6 +319,7 @@ it:
ColumnDateLastModified: 'Data ultima modifica' ColumnDateLastModified: 'Data ultima modifica'
ColumnDateLastPublished: 'Data ultima pubblicazione' ColumnDateLastPublished: 'Data ultima pubblicazione'
ColumnProblemType: 'Tipo problema' ColumnProblemType: 'Tipo problema'
ColumnURL: URL
HasBrokenFile: 'ha un file non funzionante' HasBrokenFile: 'ha un file non funzionante'
HasBrokenLink: 'ha un link non funzionante' HasBrokenLink: 'ha un link non funzionante'
HasBrokenLinkAndFile: 'ha link e file non funzionanti' HasBrokenLinkAndFile: 'ha link e file non funzionanti'

View File

@ -88,6 +88,7 @@ ja:
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
ARCHIVEDSITE: プレビュー版 ARCHIVEDSITE: プレビュー版
ARCHIVEDSITEFROM: からアーカイブされたサイト ARCHIVEDSITEFROM: からアーカイブされたサイト
CMS: CMS
DRAFT: 下書き DRAFT: 下書き
DRAFTSITE: 下書きサイト DRAFTSITE: 下書きサイト
Email: メール Email: メール
@ -236,6 +237,7 @@ ja:
ColumnDateLastModified: 最終更新日 ColumnDateLastModified: 最終更新日
ColumnDateLastPublished: 最終公開日 ColumnDateLastPublished: 最終公開日
ColumnProblemType: 問題の種類 ColumnProblemType: 問題の種類
ColumnURL: URL
HasBrokenFile: 壊れたファイルがあります HasBrokenFile: 壊れたファイルがあります
HasBrokenLink: リンクが壊れています HasBrokenLink: リンクが壊れています
HasBrokenLinkAndFile: リンク切れのファイルがあります HasBrokenLinkAndFile: リンク切れのファイルがあります

View File

@ -76,6 +76,7 @@ ja_JP:
SilverStripe\CMS\Forms\InternalLinkFormFactory: SilverStripe\CMS\Forms\InternalLinkFormFactory:
LINKDESCR: リンクの説明 LINKDESCR: リンクの説明
SilverStripe\CMS\Forms\SiteTreeURLSegmentField: SilverStripe\CMS\Forms\SiteTreeURLSegmentField:
Edit: Edit
HelpChars: 特殊文字は自動的に変換されたか取り除かれました HelpChars: 特殊文字は自動的に変換されたか取り除かれました
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
FILE: ファイル FILE: ファイル

View File

@ -74,6 +74,7 @@ ko:
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
ARCHIVEDSITE: '미리보기 버젼' ARCHIVEDSITE: '미리보기 버젼'
ARCHIVEDSITEFROM: '로부터 보관된 사이트' ARCHIVEDSITEFROM: '로부터 보관된 사이트'
CMS: CMS
DRAFT: 초안 DRAFT: 초안
DRAFTSITE: '초안 사이트' DRAFTSITE: '초안 사이트'
Email: 이메일 Email: 이메일
@ -100,6 +101,7 @@ ko:
Cancel: 취소 Cancel: 취소
Edit: 편집 Edit: 편집
HelpChars: '특수 문자는 자동으로 변환되었는지 제거되었습니다' HelpChars: '특수 문자는 자동으로 변환되었는지 제거되었습니다'
OK: OK
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
HEADER: '이 페이지는 다른 페이지로 사용자들을 이동시킵니다.' HEADER: '이 페이지는 다른 페이지로 사용자들을 이동시킵니다.'
OTHERURL: '다른 웹사이트 URL' OTHERURL: '다른 웹사이트 URL'
@ -215,6 +217,7 @@ ko:
ColumnDateLastModified: '최종 수정일' ColumnDateLastModified: '최종 수정일'
ColumnDateLastPublished: '최종 게시일' ColumnDateLastPublished: '최종 게시일'
ColumnProblemType: '문제 유형' ColumnProblemType: '문제 유형'
ColumnURL: URL
HasBrokenFile: '깨진 파일이 있습니다' HasBrokenFile: '깨진 파일이 있습니다'
HasBrokenLink: '링크가 손상되었습니다' HasBrokenLink: '링크가 손상되었습니다'
HasBrokenLinkAndFile: '손상된 링크와 파일이 있습니다' HasBrokenLinkAndFile: '손상된 링크와 파일이 있습니다'

View File

@ -25,6 +25,8 @@ lv:
ANCHORVALUE: Enkurs ANCHORVALUE: Enkurs
SilverStripe\CMS\Forms\InternalLinkFormFactory: SilverStripe\CMS\Forms\InternalLinkFormFactory:
LINKDESCR: 'Saites apraksts' LINKDESCR: 'Saites apraksts'
SilverStripe\CMS\Forms\SiteTreeURLSegmentField:
Edit: Edit
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
FILE: Fails FILE: Fails
HEADER: 'Šī lapa novirzīs lietotājus uz citu lapu ' HEADER: 'Šī lapa novirzīs lietotājus uz citu lapu '

View File

@ -77,6 +77,7 @@ mi:
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
ARCHIVEDSITE: 'Putanga Arokite' ARCHIVEDSITE: 'Putanga Arokite'
ARCHIVEDSITEFROM: 'Pae putumōhio mai i' ARCHIVEDSITEFROM: 'Pae putumōhio mai i'
CMS: CMS
DRAFT: Hukihuki DRAFT: Hukihuki
DRAFTSITE: 'Pae Hukihuki' DRAFTSITE: 'Pae Hukihuki'
Email: Īmēra Email: Īmēra

View File

@ -10,6 +10,8 @@ ms:
Password: 'Kata Laluan' Password: 'Kata Laluan'
SilverStripe\CMS\Forms\InternalLinkFormFactory: SilverStripe\CMS\Forms\InternalLinkFormFactory:
LINKDESCR: 'Deskripsi pautan' LINKDESCR: 'Deskripsi pautan'
SilverStripe\CMS\Forms\SiteTreeURLSegmentField:
Edit: Edit
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
FILE: Fail FILE: Fail
HEADER: 'Mukasurat ini akan mengalih pengguna ke mukasurat lain' HEADER: 'Mukasurat ini akan mengalih pengguna ke mukasurat lain'

View File

@ -128,6 +128,7 @@ nb:
Cancel: Avbryt Cancel: Avbryt
Edit: Rediger Edit: Rediger
HelpChars: 'Spesialtegn blir automatisk konvertert eller fjernet.' HelpChars: 'Spesialtegn blir automatisk konvertert eller fjernet.'
OK: OK
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
FILE: Fil FILE: Fil
HEADER: 'Denne siden vil omdirigere brukere til en annen side' HEADER: 'Denne siden vil omdirigere brukere til en annen side'
@ -184,6 +185,7 @@ nb:
METAEXTRA: 'Egendefinerte meta-elementer' METAEXTRA: 'Egendefinerte meta-elementer'
MODIFIEDONDRAFTHELP: 'Siden har upubliserte forandringer' MODIFIEDONDRAFTHELP: 'Siden har upubliserte forandringer'
MODIFIEDONDRAFTSHORT: Endret MODIFIEDONDRAFTSHORT: Endret
MetadataToggle: Metadata
MoreOptions: 'Flere alternativer' MoreOptions: 'Flere alternativer'
NOTPUBLISHED: 'Ikke publisert' NOTPUBLISHED: 'Ikke publisert'
OBSOLETECLASS: 'Denne siden er av den utdaterte typen {type}. Lagring vil tilbakestille typen og kan medføre tap av informasjon.' OBSOLETECLASS: 'Denne siden er av den utdaterte typen {type}. Lagring vil tilbakestille typen og kan medføre tap av informasjon.'
@ -246,6 +248,7 @@ nb:
ColumnDateLastModified: 'Dato sist endret' ColumnDateLastModified: 'Dato sist endret'
ColumnDateLastPublished: 'Dato sist publisert' ColumnDateLastPublished: 'Dato sist publisert'
ColumnProblemType: Problemtype ColumnProblemType: Problemtype
ColumnURL: URL
HasBrokenFile: 'har ødelagt fil' HasBrokenFile: 'har ødelagt fil'
HasBrokenLink: 'har ødelagt lenke' HasBrokenLink: 'har ødelagt lenke'
HasBrokenLinkAndFile: 'har ødelagt lenke og fil' HasBrokenLinkAndFile: 'har ødelagt lenke og fil'

View File

@ -10,6 +10,8 @@ ne:
Password: पासओड Password: पासओड
SilverStripe\CMS\Forms\InternalLinkFormFactory: SilverStripe\CMS\Forms\InternalLinkFormFactory:
LINKDESCR: 'लिन्क विवरण' LINKDESCR: 'लिन्क विवरण'
SilverStripe\CMS\Forms\SiteTreeURLSegmentField:
Edit: Edit
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
FILE: फाइल FILE: फाइल
HASBEENSETUP: 'कुनै पनि पुनर्निर्देशनबिना नै एउटा पुनर्निदेशन पृष्ठ सेटअप गरियो । ' HASBEENSETUP: 'कुनै पनि पुनर्निर्देशनबिना नै एउटा पुनर्निदेशन पृष्ठ सेटअप गरियो । '

View File

@ -19,13 +19,13 @@ nl:
AddNew: 'Voeg nieuwe pagina toe' AddNew: 'Voeg nieuwe pagina toe'
AddNewButton: Nieuw... AddNewButton: Nieuw...
AddPageRestriction: 'Opmerking: Sommige paginatypes zijn niet toegestaan voor deze selectie' AddPageRestriction: 'Opmerking: Sommige paginatypes zijn niet toegestaan voor deze selectie'
ArchiveWarning: 'Let op: de publicatie van deze pagina wordt ingetrokken voordat hij wordt gearchiveerd.\n\nWeet je zeker dat je wil doorgaan?' ArchiveWarning: 'Let op: de publicatie van deze pagina wordt ingetrokken voordat hij wordt gearchiveerd.\n\nWeet u zeker dat u wilt doorgaan?'
ArchiveWarningWithCampaigns: 'Let op: de publicatie van deze pagina wordt ingetrokken en de pagina wordt automatisch uit alle {NumCampaigns} campagnes verwijderd voordat deze wordt gearchiveerd.\n\nWeet je zeker dat je wil doorgaan?' ArchiveWarningWithCampaigns: 'Let op: de publicatie van deze pagina wordt ingetrokken en de pagina wordt automatisch uit alle {NumCampaigns} campagnes verwijderd voordat deze wordt gearchiveerd.\n\nWeet u zeker dat u wilt doorgaan?'
ArchiveWarningWithChildren: 'Let op: deze pagina en alle bijbehorende subpagina''s worden van de gepubliceerde site verwijderd voordat ze worden gearchiveerd.\n\nWeet je zeker dat je wil doorgaan?' ArchiveWarningWithChildren: 'Let op: deze pagina en alle bijbehorende subpagina''s worden van de gepubliceerde site verwijderd voordat ze worden gearchiveerd.\n\nWeet u zeker dat u wilt doorgaan?'
ArchiveWarningWithChildrenAndCampaigns: 'Let op: deze pagina en alle bijbehorende subpagina''s worden automatisch van de gepubliceerde site én uit alle {NumCampaigns} campagnes verwijderd, voordat ze worden gearchiveerd.\n\nWeet je zeker dat je wil doorgaan?' ArchiveWarningWithChildrenAndCampaigns: 'Let op: deze pagina en alle bijbehorende subpagina''s worden automatisch van de gepubliceerde site én uit alle {NumCampaigns} campagnes verwijderd, voordat ze worden gearchiveerd.\n\nWeet u zeker dat u wilt doorgaan?'
CANT_REORGANISE: 'Je hebt onvoldoende rechten om pagina''s op het topniveau te wijzigen. Je wijziging is niet opgeslagen.' CANT_REORGANISE: 'U hebt onvoldoende rechten om pagina''s op het topniveau te wijzigen. Uw wijziging is niet opgeslagen.'
Cancel: Annuleren Cancel: Annuleren
ChoosePageParentMode: 'Kies waar je deze pagina wilt aanmaken' ChoosePageParentMode: 'Kies waar u deze pagina wilt aanmaken'
ChoosePageType: 'Kies een pagina type' ChoosePageType: 'Kies een pagina type'
Create: Aanmaken Create: Aanmaken
DUPLICATED: '''{title}'' met succes gedupliceerd' DUPLICATED: '''{title}'' met succes gedupliceerd'
@ -79,7 +79,7 @@ nl:
SilverStripe\CMS\Controllers\CMSPageHistoryController: SilverStripe\CMS\Controllers\CMSPageHistoryController:
AUTHOR: Auteur AUTHOR: Auteur
COMPAREMODE: 'Vergelijken (selecteer 2)' COMPAREMODE: 'Vergelijken (selecteer 2)'
COMPARINGVERSION: 'Vergelijking versie {version1} en {version2}.' COMPARINGVERSION: 'U vergelijkt versie {version1} en {version2}.'
MENUTITLE: Geschiedenis MENUTITLE: Geschiedenis
MULTISELECT: 'Bulk acties' MULTISELECT: 'Bulk acties'
NOTPUBLISHED: 'Niet gepubliceerd' NOTPUBLISHED: 'Niet gepubliceerd'
@ -89,12 +89,13 @@ nl:
SHOWUNPUBLISHED: 'Toon nog niet gepubliceerde versies' SHOWUNPUBLISHED: 'Toon nog niet gepubliceerde versies'
UNKNOWN: Onbekend UNKNOWN: Onbekend
VIEW: toon VIEW: toon
VIEWINGLATEST: 'Je bekijkt nu de laatste versie.' VIEWINGLATEST: 'U bekijkt nu de laatste versie.'
VIEWINGVERSION: 'Je bekijkt nu versie {version}.' VIEWINGVERSION: 'U bekijkt nu versie {version}.'
WHEN: Wanneer WHEN: Wanneer
SilverStripe\CMS\Controllers\CMSPageSettingsController: SilverStripe\CMS\Controllers\CMSPageSettingsController:
MENUTITLE: 'Bewerk pagina' MENUTITLE: 'Bewerk pagina'
SilverStripe\CMS\Controllers\CMSPagesController: SilverStripe\CMS\Controllers\CMSPagesController:
FILTER: Filter
ListView: Lijstweergave ListView: Lijstweergave
MENUTITLE: 'Pagina''s' MENUTITLE: 'Pagina''s'
TreeView: Boomstructuur TreeView: Boomstructuur
@ -115,6 +116,7 @@ nl:
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
ARCHIVEDSITE: 'Voorbeeld van versie bekijken' ARCHIVEDSITE: 'Voorbeeld van versie bekijken'
ARCHIVEDSITEFROM: 'Gearchiveerde site van' ARCHIVEDSITEFROM: 'Gearchiveerde site van'
CMS: CMS
DRAFT: Concept DRAFT: Concept
DRAFTSITE: 'Concept site' DRAFTSITE: 'Concept site'
Email: E-mail Email: E-mail
@ -131,7 +133,7 @@ nl:
PUBLISHEDSITE: 'Gepubliceerde site' PUBLISHEDSITE: 'Gepubliceerde site'
Password: Wachtwoord Password: Wachtwoord
PostInstallTutorialIntro: 'Deze website is een eenvoudige versie van een SilverStripe 3 website. Voor uitbreidingen kunt u hier een kijkje nemen: {link}.' PostInstallTutorialIntro: 'Deze website is een eenvoudige versie van een SilverStripe 3 website. Voor uitbreidingen kunt u hier een kijkje nemen: {link}.'
StartEditing: 'Je kan de inhoud aanpassen via <a href="{link}">het CMS</a>.' StartEditing: 'U kunt de inhoud aanpassen via <a href="{link}">het CMS</a>.'
UNVERSIONEDPREVIEW: Voorbeeld UNVERSIONEDPREVIEW: Voorbeeld
UnableDeleteInstall: 'De installatiebestanden konden niet verwijderd worden. Verwijder onderstaande bestanden handmatig:' UnableDeleteInstall: 'De installatiebestanden konden niet verwijderd worden. Verwijder onderstaande bestanden handmatig:'
VIEWPAGEIN: 'Bekijk pagina in:' VIEWPAGEIN: 'Bekijk pagina in:'
@ -149,6 +151,7 @@ nl:
EMPTY: 'Vul een URL segment in of klik op annuleren' EMPTY: 'Vul een URL segment in of klik op annuleren'
Edit: Bewerken Edit: Bewerken
HelpChars: 'Speciale tekens worden automatische omgezet of verwijderd.' HelpChars: 'Speciale tekens worden automatische omgezet of verwijderd.'
OK: OK
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
DESCRIPTION: 'Stuurt door naar een interne pagina of een externe URL' DESCRIPTION: 'Stuurt door naar een interne pagina of een externe URL'
FILE: Bestand FILE: Bestand
@ -187,11 +190,12 @@ nl:
BUTTONUNPUBLISHDESC: 'Deze pagina verwijderen uit de gepubliceerde site' BUTTONUNPUBLISHDESC: 'Deze pagina verwijderen uit de gepubliceerde site'
Comments: Commentaar Comments: Commentaar
Content: Inhoud Content: Inhoud
DEFAULTABOUTCONTENT: '<p>Je kan deze pagina vullen met eigen tekst, of deze verwijderen en nieuwe pagina''s aanmaken.</p>' DEFAULTABOUTCONTENT: '<p>U kunt deze pagina vullen met eigen tekst, of deze verwijderen en nieuwe pagina''s aanmaken.</p>'
DEFAULTABOUTTITLE: 'Over Ons' DEFAULTABOUTTITLE: 'Over Ons'
DEFAULTCONTACTCONTENT: '<p>Je kan deze pagina vullen met nieuwe tekst, of verwijderen en nieuwe pagina''s aanmaken.</p>' DEFAULTCONTACTCONTENT: '<p>U kunt deze pagina vullen met nieuwe tekst, of verwijderen en nieuwe pagina''s aanmaken.</p>'
DEFAULTCONTACTTITLE: Contact DEFAULTCONTACTTITLE: Contact
DEFAULTHOMECONTENT: '<p>Welkom bij Silverstripe! Dit is de standaard homepagina. Je kan deze pagina wijzigen door <a href="admin/">het CMS</a> te openen.</p><p>Je kan verder de <a href="http://docs.silverstripe.org">documentatie voor ontwikkelaars</a> raadplegen of aan <a href="http://www.silverstripe.org/learn/lessons">de tutorials</a> beginnen.</p>' DEFAULTHOMECONTENT: '<p>Welkom bij Silverstripe! Dit is de standaard homepagina. Je kan deze pagina wijzigen door <a href="admin/">het CMS</a> te openen.</p><p>Je kan verder de <a href="http://docs.silverstripe.org">documentatie voor ontwikkelaars</a> raadplegen of aan <a href="http://www.silverstripe.org/learn/lessons">de tutorials</a> beginnen.</p>'
DEFAULTHOMETITLE: Home
DEPENDENT_NOTE: 'De volgende pagina''s zijn afhankelijk van deze pagina. Hieronder vallen virtuele pagina''s, verwijzingspagina''s en pagina''s met links in hun inhoud.' DEPENDENT_NOTE: 'De volgende pagina''s zijn afhankelijk van deze pagina. Hieronder vallen virtuele pagina''s, verwijzingspagina''s en pagina''s met links in hun inhoud.'
DESCRIPTION: 'Algemene pagina' DESCRIPTION: 'Algemene pagina'
DependtPageColumnLinkType: Linktype DependtPageColumnLinkType: Linktype
@ -219,6 +223,7 @@ nl:
METAEXTRAHELP: 'HTML-tags voor extra meta-informatie. Bijvoorbeeld <meta name="customName" content="your custom content here">' METAEXTRAHELP: 'HTML-tags voor extra meta-informatie. Bijvoorbeeld <meta name="customName" content="your custom content here">'
MODIFIEDONDRAFTHELP: 'Pagina heeft wijzigingen die nog niet gepubliceerd zijn' MODIFIEDONDRAFTHELP: 'Pagina heeft wijzigingen die nog niet gepubliceerd zijn'
MODIFIEDONDRAFTSHORT: Aangepast MODIFIEDONDRAFTSHORT: Aangepast
MetadataToggle: Metadata
MoreOptions: 'Meer opties' MoreOptions: 'Meer opties'
NOTPUBLISHED: 'Niet gepubliceerd' NOTPUBLISHED: 'Niet gepubliceerd'
OBSOLETECLASS: 'Deze pagina is van het type {type}. Dit type is niet meer in gebruik. Het opslaan van deze pagina zal het type wijzigen. Hierbij kan data verloren gaan.' OBSOLETECLASS: 'Deze pagina is van het type {type}. Dit type is niet meer in gebruik. Het opslaan van deze pagina zal het type wijzigen. Hierbij kan data verloren gaan.'
@ -250,6 +255,7 @@ nl:
TABDEPENDENT: 'Afhankelijke pagina''s' TABDEPENDENT: 'Afhankelijke pagina''s'
TOPLEVEL: 'Site inhoud (hoogste niveau)' TOPLEVEL: 'Site inhoud (hoogste niveau)'
UNTITLED: 'Naamloos {pagetype}' UNTITLED: 'Naamloos {pagetype}'
URLSegment: 'URL segment'
UntitledDependentObject: 'Naamloos {instanceType}' UntitledDependentObject: 'Naamloos {instanceType}'
VIEWERGROUPS: Bekijkersgroepen VIEWERGROUPS: Bekijkersgroepen
VIEWER_GROUPS_FIELD_DESC: 'Groepen die alles mogen bekijken: {groupList}' VIEWER_GROUPS_FIELD_DESC: 'Groepen die alles mogen bekijken: {groupList}'
@ -257,20 +263,23 @@ nl:
VIEW_ALL_HELP: 'Bevoegdheid om alle pagina''s op de site te wijzigen, onafhankelijk van de instellingen in het ''Toegang'' tabblad. Vereist "Toegang tot site inhoud" rechten' VIEW_ALL_HELP: 'Bevoegdheid om alle pagina''s op de site te wijzigen, onafhankelijk van de instellingen in het ''Toegang'' tabblad. Vereist "Toegang tot site inhoud" rechten'
VIEW_DRAFT_CONTENT: 'Bekijk concept inhoud' VIEW_DRAFT_CONTENT: 'Bekijk concept inhoud'
VIEW_DRAFT_CONTENT_HELP: 'Bevoegdheid om pagina''s buiten het CMS in concept mode te bekijken. Nuttig voor externe medewerkers zonder CMS toegang.' VIEW_DRAFT_CONTENT_HELP: 'Bevoegdheid om pagina''s buiten het CMS in concept mode te bekijken. Nuttig voor externe medewerkers zonder CMS toegang.'
VIRTUALPAGEDRAFTWARNING: 'Publiceer eerst de gekoppelde pagina, om de virtuele pagina te kunnen publiceren' VIRTUALPAGEDRAFTWARNING: 'U dient eerst de gekoppelde pagina te publiceren voordat u de virtuele pagina publiceert.'
VIRTUALPAGEWARNING: 'Kies eerst een gekoppelde pagina en sla deze eerst op, om deze pagina te kunnen publiceren' VIRTUALPAGEWARNING: 'U dient eerst een gekoppelde pagina te selecteren en op te slaan voordat u deze pagina kunt publiceren.'
VIRTUALPAGEWARNINGSETTINGS: 'Kies eerst een gekoppelde pagina op het hoofdscherm, voordat je deze pagina kan publiceren' VIRTUALPAGEWARNINGSETTINGS: 'U dient een gekoppelde pagina te selecteren op het hoofdscherm voordat u kunt publiceren.'
Viewers: Bekijkersgroepen Viewers: Bekijkersgroepen
Visibility: Zichtbaarheid Visibility: Zichtbaarheid
db_Content: Inhoud db_Content: Inhoud
db_Sort: Volgorde db_Sort: Volgorde
db_Title: Titel db_Title: Titel
db_Version: Versie db_URLSegment: 'URL segment'
has_one_Parent: 'Bovenliggende pagina' has_one_Parent: 'Bovenliggende pagina'
has_one_Subsite: Subsite
many_many_BackLinkTracking: 'Backlinks traceren' many_many_BackLinkTracking: 'Backlinks traceren'
many_many_ImageTracking: 'Afbeeldingen traceren' many_many_ImageTracking: 'Afbeeldingen traceren'
many_many_LinkTracking: 'Links traceren' many_many_LinkTracking: 'Links traceren'
SilverStripe\CMS\Model\SiteTreeFileExtension: SilverStripe\CMS\Model\SiteTreeFileExtension:
TITLE_INDEX: '#'
TITLE_TYPE: Type
TITLE_USED_ON: 'Gebruikt op:' TITLE_USED_ON: 'Gebruikt op:'
SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension: SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension:
USAGE: Gebruik USAGE: Gebruik
@ -308,6 +317,7 @@ nl:
ColumnDateLastModified: 'Laatste wijzigingsdatum' ColumnDateLastModified: 'Laatste wijzigingsdatum'
ColumnDateLastPublished: 'Laatste publicatiedatum' ColumnDateLastPublished: 'Laatste publicatiedatum'
ColumnProblemType: Probleemtype ColumnProblemType: Probleemtype
ColumnURL: URL
HasBrokenFile: 'heeft verbroken bestand' HasBrokenFile: 'heeft verbroken bestand'
HasBrokenLink: 'heeft verbroken link' HasBrokenLink: 'heeft verbroken link'
HasBrokenLinkAndFile: 'heeft verbroken link en bestand' HasBrokenLinkAndFile: 'heeft verbroken link en bestand'

View File

@ -30,6 +30,7 @@ pl:
Create: Utwórz Create: Utwórz
DUPLICATED: 'Duplikowanie ''{title}'' zakończone powodzeniem' DUPLICATED: 'Duplikowanie ''{title}'' zakończone powodzeniem'
DUPLICATEDWITHCHILDREN: 'Duplikowanie ''{title}'' oraz podstron zakończone powodzeniem' DUPLICATEDWITHCHILDREN: 'Duplikowanie ''{title}'' oraz podstron zakończone powodzeniem'
EMAIL: Email
NEWPAGE: 'Nowa {pagetype}' NEWPAGE: 'Nowa {pagetype}'
PAGENOTEXISTS: 'Ta strona nie istnieje' PAGENOTEXISTS: 'Ta strona nie istnieje'
PAGES: 'Status strony' PAGES: 'Status strony'
@ -119,6 +120,7 @@ pl:
CMS: 'System Zarządzania Treścią' CMS: 'System Zarządzania Treścią'
DRAFT: Szkic DRAFT: Szkic
DRAFTSITE: 'Szkic witryny' DRAFTSITE: 'Szkic witryny'
Email: Email
INSTALL_SUCCESS: 'Instalacja przebiegła pomyślnie' INSTALL_SUCCESS: 'Instalacja przebiegła pomyślnie'
InstallFilesDeleted: 'Pliki instalacyjne zostały pomyślnie usunięte' InstallFilesDeleted: 'Pliki instalacyjne zostały pomyślnie usunięte'
InstallSecurityWarning: 'Dla bezpieczeństwa powinieneś skasować pliki instalacyjne, chyba że planujesz reinstalację w późniejszym czasie (<em>wymaga zalogowania się jako admin, patrz wyżej</em>). Serwer potrzebuje teraz tylko dostępu do folderu "assets", możesz usunąć dostęp do innych folderów. <a href="{link}" style="text-align: center;">Kliknij tutaj aby usunąć pliki instalacyjne.</a>' InstallSecurityWarning: 'Dla bezpieczeństwa powinieneś skasować pliki instalacyjne, chyba że planujesz reinstalację w późniejszym czasie (<em>wymaga zalogowania się jako admin, patrz wyżej</em>). Serwer potrzebuje teraz tylko dostępu do folderu "assets", możesz usunąć dostęp do innych folderów. <a href="{link}" style="text-align: center;">Kliknij tutaj aby usunąć pliki instalacyjne.</a>'
@ -150,6 +152,7 @@ pl:
EMPTY: 'Proszę podać adres URL lub kliknąć anuluj' EMPTY: 'Proszę podać adres URL lub kliknąć anuluj'
Edit: Edytuj Edit: Edytuj
HelpChars: 'Znaki specjalne są automatycznie konwertowane lub usuwane.' HelpChars: 'Znaki specjalne są automatycznie konwertowane lub usuwane.'
OK: OK
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
DESCRIPTION: 'Przekierowuje do wskazanej wewnętrznej strony' DESCRIPTION: 'Przekierowuje do wskazanej wewnętrznej strony'
FILE: Plik FILE: Plik
@ -277,6 +280,7 @@ pl:
many_many_ImageTracking: 'Śledzenie obrazków' many_many_ImageTracking: 'Śledzenie obrazków'
many_many_LinkTracking: 'Śledzenie linków' many_many_LinkTracking: 'Śledzenie linków'
SilverStripe\CMS\Model\SiteTreeFileExtension: SilverStripe\CMS\Model\SiteTreeFileExtension:
TITLE_INDEX: '#'
TITLE_TYPE: 'Rodzaj strony' TITLE_TYPE: 'Rodzaj strony'
TITLE_USED_ON: 'Używany na:' TITLE_USED_ON: 'Używany na:'
SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension: SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension:

View File

@ -151,6 +151,7 @@ pl_PL:
EMPTY: 'Proszę podać adres URL lub kliknąć anuluj' EMPTY: 'Proszę podać adres URL lub kliknąć anuluj'
Edit: Edytuj Edit: Edytuj
HelpChars: 'Znaki specjalne są automatycznie konwertowane lub usuwane.' HelpChars: 'Znaki specjalne są automatycznie konwertowane lub usuwane.'
OK: OK
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
DESCRIPTION: 'Przekierowuje do wskazanej wewnętrznej strony' DESCRIPTION: 'Przekierowuje do wskazanej wewnętrznej strony'
FILE: Plik FILE: Plik
@ -278,6 +279,7 @@ pl_PL:
many_many_ImageTracking: 'Śledzenie obrazków' many_many_ImageTracking: 'Śledzenie obrazków'
many_many_LinkTracking: 'Śledzenie linków' many_many_LinkTracking: 'Śledzenie linków'
SilverStripe\CMS\Model\SiteTreeFileExtension: SilverStripe\CMS\Model\SiteTreeFileExtension:
TITLE_INDEX: '#'
TITLE_TYPE: Typ TITLE_TYPE: Typ
TITLE_USED_ON: 'Użyto na' TITLE_USED_ON: 'Użyto na'
SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension: SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension:
@ -318,6 +320,7 @@ pl_PL:
ColumnDateLastModified: 'Data ostatniej modyfikacji' ColumnDateLastModified: 'Data ostatniej modyfikacji'
ColumnDateLastPublished: 'Data ostatniej publikacji' ColumnDateLastPublished: 'Data ostatniej publikacji'
ColumnProblemType: 'Problem do sprawdzenia' ColumnProblemType: 'Problem do sprawdzenia'
ColumnURL: URL
HasBrokenFile: 'ma uszkodzony plik' HasBrokenFile: 'ma uszkodzony plik'
HasBrokenLink: 'ma uszkodzony link' HasBrokenLink: 'ma uszkodzony link'
HasBrokenLinkAndFile: 'ma uszkodzony link oraz plik' HasBrokenLinkAndFile: 'ma uszkodzony link oraz plik'

View File

@ -96,6 +96,7 @@ pt:
LINKDESCR: 'Descrição do link' LINKDESCR: 'Descrição do link'
SilverStripe\CMS\Forms\SiteTreeURLSegmentField: SilverStripe\CMS\Forms\SiteTreeURLSegmentField:
Cancel: Cancelar Cancel: Cancelar
Edit: Edit
HelpChars: 'Os caracteres especiais são automaticamente convertido ou removidos.' HelpChars: 'Os caracteres especiais são automaticamente convertido ou removidos.'
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
FILE: Ficheiro FILE: Ficheiro

View File

@ -25,11 +25,14 @@ pt_BR:
MENUTITLE: Páginas MENUTITLE: Páginas
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
Email: E-mail Email: E-mail
LOGIN: Login
Password: Senha Password: Senha
SilverStripe\CMS\Forms\AnchorLinkFormFactory: SilverStripe\CMS\Forms\AnchorLinkFormFactory:
ANCHORVALUE: Âncora ANCHORVALUE: Âncora
SilverStripe\CMS\Forms\InternalLinkFormFactory: SilverStripe\CMS\Forms\InternalLinkFormFactory:
LINKDESCR: 'Descrição do link' LINKDESCR: 'Descrição do link'
SilverStripe\CMS\Forms\SiteTreeURLSegmentField:
Edit: Edit
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
FILE: Arquivo FILE: Arquivo
HEADER: 'Esta página redireccionará os utilizadores para outra página' HEADER: 'Esta página redireccionará os utilizadores para outra página'

View File

@ -72,6 +72,7 @@ ro:
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
ARCHIVEDSITE: 'Previzualizare versiune' ARCHIVEDSITE: 'Previzualizare versiune'
ARCHIVEDSITEFROM: 'Site arhivat din' ARCHIVEDSITEFROM: 'Site arhivat din'
CMS: CMS
DRAFT: Cironă DRAFT: Cironă
DRAFTSITE: 'Site ciornă' DRAFTSITE: 'Site ciornă'
Email: E-mail Email: E-mail
@ -80,6 +81,7 @@ ro:
InstallSecurityWarning: 'Din motive de secutitate ar trebuii să ștergeți acum fișierele de instalare, în cazul în care nu planificați o reinstalare ulterioară (<em>necesită drepturi de admin, referințe mai sue</em>). De acum serverul necesită doar drepturi de scriere in directorul "assets", puteți șterge dreturile de scriere pentru celelalte directoare.. <a href="{link}" style="text-align: center;">Click aici pentru ștergerea fișierelor de instalare.</a>' InstallSecurityWarning: 'Din motive de secutitate ar trebuii să ștergeți acum fișierele de instalare, în cazul în care nu planificați o reinstalare ulterioară (<em>necesită drepturi de admin, referințe mai sue</em>). De acum serverul necesită doar drepturi de scriere in directorul "assets", puteți șterge dreturile de scriere pentru celelalte directoare.. <a href="{link}" style="text-align: center;">Click aici pentru ștergerea fișierelor de instalare.</a>'
InstallSuccessCongratulations: 'Silverstripe a fost instalat cu succes!' InstallSuccessCongratulations: 'Silverstripe a fost instalat cu succes!'
LOGGEDINAS: 'Logat ca' LOGGEDINAS: 'Logat ca'
LOGIN: Login
LOGOUT: Logout LOGOUT: Logout
NOTEWONTBESHOWN: 'Notă: acest mesaj nu v-a fi afișat vizitatorilor' NOTEWONTBESHOWN: 'Notă: acest mesaj nu v-a fi afișat vizitatorilor'
NOTLOGGEDIN: Ne-loginat NOTLOGGEDIN: Ne-loginat
@ -99,6 +101,7 @@ ro:
Cancel: Anulare Cancel: Anulare
Edit: Editare Edit: Editare
HelpChars: 'Caracterele speciale sunt convertite automat sau șterse' HelpChars: 'Caracterele speciale sunt convertite automat sau șterse'
OK: OK
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
FILE: Fisier FILE: Fisier
HEADER: 'Pagina v-a redirecționa utilizatorii către altă pagină' HEADER: 'Pagina v-a redirecționa utilizatorii către altă pagină'
@ -153,6 +156,7 @@ ro:
METAEXTRA: 'Etichetă Meta preferențială' METAEXTRA: 'Etichetă Meta preferențială'
MODIFIEDONDRAFTHELP: 'Pagina are modificări nepublicate' MODIFIEDONDRAFTHELP: 'Pagina are modificări nepublicate'
MODIFIEDONDRAFTSHORT: Modificat MODIFIEDONDRAFTSHORT: Modificat
MetadataToggle: Metadata
MoreOptions: 'Mai multe opțiuni' MoreOptions: 'Mai multe opțiuni'
NOTPUBLISHED: Nepublicat NOTPUBLISHED: Nepublicat
OBSOLETECLASS: 'Această pagină este de un tip {type} scos din uz. Salvând se va reseta tipul și se pot pierde datele' OBSOLETECLASS: 'Această pagină este de un tip {type} scos din uz. Salvând se va reseta tipul și se pot pierde datele'
@ -217,6 +221,7 @@ ro:
ColumnDateLastModified: 'Data ultimei modificări' ColumnDateLastModified: 'Data ultimei modificări'
ColumnDateLastPublished: 'Data ultimei publicări' ColumnDateLastPublished: 'Data ultimei publicări'
ColumnProblemType: 'Tip problemă' ColumnProblemType: 'Tip problemă'
ColumnURL: URL
HasBrokenFile: 'are fişiere corupte' HasBrokenFile: 'are fişiere corupte'
HasBrokenLink: 'are link-uri nefuncţionale' HasBrokenLink: 'are link-uri nefuncţionale'
HasBrokenLinkAndFile: 'are link-uri nefuncţionale şi fişiere corupte' HasBrokenLinkAndFile: 'are link-uri nefuncţionale şi fişiere corupte'

View File

@ -30,6 +30,7 @@ ru:
Create: Создать Create: Создать
DUPLICATED: 'Копия ''{title}'' создана' DUPLICATED: 'Копия ''{title}'' создана'
DUPLICATEDWITHCHILDREN: 'Копия ''{title}'' и дочерних элементов создана' DUPLICATEDWITHCHILDREN: 'Копия ''{title}'' и дочерних элементов создана'
EMAIL: Email
NEWPAGE: 'Новая {pagetype}' NEWPAGE: 'Новая {pagetype}'
PAGENOTEXISTS: 'Страница не существует' PAGENOTEXISTS: 'Страница не существует'
PAGES: 'Статус страницы' PAGES: 'Статус страницы'
@ -113,8 +114,10 @@ ru:
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
ARCHIVEDSITE: 'Версия для просмотра' ARCHIVEDSITE: 'Версия для просмотра'
ARCHIVEDSITEFROM: 'Архив сайта от' ARCHIVEDSITEFROM: 'Архив сайта от'
CMS: CMS
DRAFT: Черновик DRAFT: Черновик
DRAFTSITE: 'Черновой сайт' DRAFTSITE: 'Черновой сайт'
Email: Email
INSTALL_SUCCESS: 'Инсталляция прошла успешно!' INSTALL_SUCCESS: 'Инсталляция прошла успешно!'
InstallFilesDeleted: 'Установочные файлы были успешно удалены.' InstallFilesDeleted: 'Установочные файлы были успешно удалены.'
InstallSecurityWarning: 'Если вы не планируете в ближайшее время переустанавливать CMS, по соображениям безопасности рекомендуется удалить инсталляционные файлы (<em>для этого требуются права доступа администратора см. выше</em>). Теперь веб-серверу необходим доступ для записи только к папке "assets"; все остальные папки можно защитить от записи. <a href="{link}" style="text-align: center;">Щелкните здесь, чтобы удалить инсталляционные файлы.</a>' InstallSecurityWarning: 'Если вы не планируете в ближайшее время переустанавливать CMS, по соображениям безопасности рекомендуется удалить инсталляционные файлы (<em>для этого требуются права доступа администратора см. выше</em>). Теперь веб-серверу необходим доступ для записи только к папке "assets"; все остальные папки можно защитить от записи. <a href="{link}" style="text-align: center;">Щелкните здесь, чтобы удалить инсталляционные файлы.</a>'
@ -299,6 +302,7 @@ ru:
ColumnDateLastModified: 'Дата последнего изменения' ColumnDateLastModified: 'Дата последнего изменения'
ColumnDateLastPublished: 'Дата последней публикации' ColumnDateLastPublished: 'Дата последней публикации'
ColumnProblemType: 'Вид проблемы' ColumnProblemType: 'Вид проблемы'
ColumnURL: URL
HasBrokenFile: 'содержит поврежденный файл' HasBrokenFile: 'содержит поврежденный файл'
HasBrokenLink: 'содержит нерабочую ссылку' HasBrokenLink: 'содержит нерабочую ссылку'
HasBrokenLinkAndFile: 'содержит нерабочую ссылку и поврежденный файл' HasBrokenLinkAndFile: 'содержит нерабочую ссылку и поврежденный файл'

View File

@ -17,6 +17,8 @@ si:
Password: 'මුර පදය' Password: 'මුර පදය'
SilverStripe\CMS\Forms\InternalLinkFormFactory: SilverStripe\CMS\Forms\InternalLinkFormFactory:
LINKDESCR: 'බැදීම් විස්තරය' LINKDESCR: 'බැදීම් විස්තරය'
SilverStripe\CMS\Forms\SiteTreeURLSegmentField:
Edit: Edit
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
FILE: ලිපිය FILE: ලිපිය
HEADER: 'මෙම පිටුව පරිබෝඡකයන් වෙනත් යොමු කරයි' HEADER: 'මෙම පිටුව පරිබෝඡකයන් වෙනත් යොමු කරයි'

View File

@ -37,11 +37,9 @@ sk:
PAGESALLOPT: 'Všetky stránky' PAGESALLOPT: 'Všetky stránky'
PAGETYPEANYOPT: Akákoľvek PAGETYPEANYOPT: Akákoľvek
PAGETYPEOPT: 'Typ stránky' PAGETYPEOPT: 'Typ stránky'
PAGETYPE_TITLE: '(Typ stránky: {type}) {title}'
PLEASESAVE: 'Prosím uložte stránku: Táto stránka nemôže byť aktualizovaná, lebo ešte nebola uložená.' PLEASESAVE: 'Prosím uložte stránku: Táto stránka nemôže byť aktualizovaná, lebo ešte nebola uložená.'
PUBALLCONFIRM: 'Prosím, zverejnite všetky stránky webu, zkopírovaním obsahu na verejné' PUBALLCONFIRM: 'Prosím, zverejnite všetky stránky webu, zkopírovaním obsahu na verejné'
PUBALLFUN: 'Funkcia "Publikovať všetko"' PUBALLFUN: 'Funkcia "Publikovať všetko"'
PUBALLFUN2: 'Stlačením tohto tlačidla sa vykoná ekvivalent prechodu na každú stránku a stlačenie tlačidla "publikovať". Je to určené na použitie po rozsiahlych úpravách obsahu, napríklad pri prvom spustení stránky. V prípade veľkých webových stránok sa táto úloha nemusí podariť dokončiť. V tomto prípade vám odporúčame porozprávať sa s vašimi vývojármi a vytvoriť vlastnú úlohu'
PUBLISHED: 'Uverejnené "{title}" úspešne.' PUBLISHED: 'Uverejnené "{title}" úspešne.'
PUBPAGES: 'Hotovo: Publikované {count} stránky' PUBPAGES: 'Hotovo: Publikované {count} stránky'
PageAdded: 'Stránka vytvorená úspešne' PageAdded: 'Stránka vytvorená úspešne'
@ -58,7 +56,6 @@ sk:
ROLLEDBACKVERSIONv2: 'Vrátené späť na verziu #{version}.' ROLLEDBACKVERSIONv2: 'Vrátené späť na verziu #{version}.'
SAVED: 'Uložené ''{title}'' úspešne.' SAVED: 'Uložené ''{title}'' úspešne.'
SAVEDRAFT: Uložiť SAVEDRAFT: Uložiť
SEARCHRESULTS: 'Výsledky vyhľadávania'
SHOW_AS_LIST: 'ukázať ako zoznam' SHOW_AS_LIST: 'ukázať ako zoznam'
TOO_MANY_PAGES: 'Príliš veľa stránok' TOO_MANY_PAGES: 'Príliš veľa stránok'
TabContent: Obsah TabContent: Obsah
@ -83,7 +80,6 @@ sk:
MENUTITLE: História MENUTITLE: História
MULTISELECT: 'Dávkové akcie' MULTISELECT: 'Dávkové akcie'
NOTPUBLISHED: Nepublikované NOTPUBLISHED: Nepublikované
NO_PREVIEW: 'Žiaden náhľad k dispozícii'
PREVIEW: 'Náhľad webu' PREVIEW: 'Náhľad webu'
PUBLISHER: Vydavateľ PUBLISHER: Vydavateľ
REVERTTOTHISVERSION: 'Vrátiť sa k tejto verzii' REVERTTOTHISVERSION: 'Vrátiť sa k tejto verzii'
@ -96,6 +92,7 @@ sk:
SilverStripe\CMS\Controllers\CMSPageSettingsController: SilverStripe\CMS\Controllers\CMSPageSettingsController:
MENUTITLE: 'Upraviť stránku' MENUTITLE: 'Upraviť stránku'
SilverStripe\CMS\Controllers\CMSPagesController: SilverStripe\CMS\Controllers\CMSPagesController:
FILTER: Filter
ListView: 'Zobraziť zoznam' ListView: 'Zobraziť zoznam'
MENUTITLE: Stránky MENUTITLE: Stránky
TreeView: 'Zobraziť strom' TreeView: 'Zobraziť strom'
@ -116,6 +113,7 @@ sk:
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
ARCHIVEDSITE: 'Zobrazenie verzie' ARCHIVEDSITE: 'Zobrazenie verzie'
ARCHIVEDSITEFROM: 'Archivovaný web z' ARCHIVEDSITEFROM: 'Archivovaný web z'
CMS: CMS
DRAFT: Koncept DRAFT: Koncept
DRAFTSITE: 'Koncept webu' DRAFTSITE: 'Koncept webu'
Email: E-mail Email: E-mail
@ -142,42 +140,29 @@ sk:
ANCHORVALUE: Kotva ANCHORVALUE: Kotva
SilverStripe\CMS\Forms\InternalLinkFormFactory: SilverStripe\CMS\Forms\InternalLinkFormFactory:
LINKDESCR: 'Popis odkazu' LINKDESCR: 'Popis odkazu'
LINKOPENNEWWIN: 'Otvoriť v novom okne/záložke'
LINKTEXT: 'Text odkazu'
SELECT_PAGE: 'Vyberte stránku'
SilverStripe\CMS\Forms\SiteTreeURLSegmentField: SilverStripe\CMS\Forms\SiteTreeURLSegmentField:
Cancel: Zrušiť Cancel: Zrušiť
EMPTY: 'Zadajte prosím URL segment alebo kliknite zrušiť'
Edit: Editovať Edit: Editovať
HelpChars: 'Špeciálne znaky sú automaticky zkonvertované alebo ostránené.' HelpChars: 'Špeciálne znaky sú automaticky zkonvertované alebo ostránené.'
OK: OK
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
DESCRIPTION: 'Presmeruje na internú stránku alebo na externé URL' DESCRIPTION: 'Presmeruje na internú stránku alebo na externé URL'
FILE: Súbor FILE: Súbor
HEADER: 'Táto stránka presmeruje používateľov na inú stránku' HEADER: 'Táto stránka presmeruje používateľov na inú stránku'
OTHERURL: 'Iné web URL.' OTHERURL: 'Iné web URL.'
PLURALNAME: 'Základné stránky' PLURALNAME: 'Základné stránky'
PLURALS:
few: '{count} Základné stránky'
many: '{count} Základných stránok'
one: 'Presmerovacia stránka'
other: '{count} Základných stránok'
REDIRECTTO: 'Presmerovať na' REDIRECTTO: 'Presmerovať na'
REDIRECTTOEXTERNAL: 'Iná web stránka' REDIRECTTOEXTERNAL: 'Iná web stránka'
REDIRECTTOFILE: 'Súbor na vašom webe'
REDIRECTTOPAGE: 'Stránka na vašom webe' REDIRECTTOPAGE: 'Stránka na vašom webe'
SINGULARNAME: 'Presmerovacia stránka' SINGULARNAME: 'Presmerovacia stránka'
YOURPAGE: 'Stránka na vašom webe' YOURPAGE: 'Stránka na vašom webe'
db_ExternalURL: 'Externá URL'
db_RedirectionType: 'Typ presmerovania'
has_one_LinkTo: 'Odkaz na' has_one_LinkTo: 'Odkaz na'
has_one_LinkToFile: 'Odkaz na súbor'
SilverStripe\CMS\Model\RedirectorPageController: SilverStripe\CMS\Model\RedirectorPageController:
HASBEENSETUP: 'Stránka na presmerovanie bola nastavená bez cieľa.' HASBEENSETUP: 'Stránka na presmerovanie bola nastavená bez cieľa.'
SilverStripe\CMS\Model\SiteTree: SilverStripe\CMS\Model\SiteTree:
ACCESSANYONE: Ktokoľvek ACCESSANYONE: Ktokoľvek
ACCESSHEADER: 'Kto môže prezerať túto stránku?' ACCESSHEADER: 'Kto môže prezerať túto stránku?'
ACCESSLOGGEDIN: 'Prihlásení používatelia' ACCESSLOGGEDIN: 'Prihlásení používatelia'
ACCESSONLYMEMBERS: 'Iba títo používatelia (vyberte zo zoznamu)'
ACCESSONLYTHESE: 'Iba títo ľudia (vyberte zo zoznamu)' ACCESSONLYTHESE: 'Iba títo ľudia (vyberte zo zoznamu)'
ADDEDTODRAFTHELP: 'Stránka ešte nebola zverejnená' ADDEDTODRAFTHELP: 'Stránka ešte nebola zverejnená'
ADDEDTODRAFTSHORT: Koncept ADDEDTODRAFTSHORT: Koncept
@ -205,16 +190,12 @@ sk:
DependtPageColumnLinkType: 'Typ odkazu' DependtPageColumnLinkType: 'Typ odkazu'
EDITHEADER: 'Kto môže editovať túto stránku?' EDITHEADER: 'Kto môže editovať túto stránku?'
EDITORGROUPS: 'Skupiny upravovateľov' EDITORGROUPS: 'Skupiny upravovateľov'
EDITORMEMBERS: Upravovatelia
EDITOR_GROUPS_FIELD_DESC: 'Skupiny s globálnymi právami na úpravy: {groupList}'
EDIT_ALL_DESCRIPTION: 'Upraviť akúkoľvek stránku' EDIT_ALL_DESCRIPTION: 'Upraviť akúkoľvek stránku'
EDIT_ALL_HELP: 'Schopnosť upravovať ktorúkoľvek stránku na webe, nedbajúc na nastavenia v záložke prístupov. Vyžaduje "Prístup k ''Stránkam'' sekcia" povolenie' EDIT_ALL_HELP: 'Schopnosť upravovať ktorúkoľvek stránku na webe, nedbajúc na nastavenia v záložke prístupov. Vyžaduje "Prístup k ''Stránkam'' sekcia" povolenie'
Editors: 'Skupiny upravovateľov' Editors: 'Skupiny upravovateľov'
HASBROKENLINKS: 'Táto stránka obsahuje nefunkčné odkazy.' HASBROKENLINKS: 'Táto stránka obsahuje nefunkčné odkazy.'
HTMLEDITORTITLE: Obsah HTMLEDITORTITLE: Obsah
INHERIT: 'Dediť od nadradenej stránky' INHERIT: 'Dediť od nadradenej stránky'
INHERITSITECONFIG: 'Zdediť z nastavení prístupu na stránku'
InvalidExtraMeta: 'Vlastné metaznačky neobsahujú platný kód HTML'
LASTPUBLISHED: 'Posledne zverejnené' LASTPUBLISHED: 'Posledne zverejnené'
LASTSAVED: 'Posledne uložené' LASTSAVED: 'Posledne uložené'
LASTUPDATED: 'Posledne aktualizované' LASTUPDATED: 'Posledne aktualizované'
@ -225,7 +206,6 @@ sk:
METADESC: 'Meta Popis' METADESC: 'Meta Popis'
METADESCHELP: 'Vyhľadávače používajú tento obsah pre zobrazovanie výsledkov vyhľadávania (aj keď to nebude mať vplyv na ich hodnotenie).' METADESCHELP: 'Vyhľadávače používajú tento obsah pre zobrazovanie výsledkov vyhľadávania (aj keď to nebude mať vplyv na ich hodnotenie).'
METAEXTRA: 'Vlastné Meta Tagy' METAEXTRA: 'Vlastné Meta Tagy'
METAEXTRAHELP: 'HTML tagy pre ďalšie meta informácie. Napríklad <meta name="customName" content="your custom content here">'
MODIFIEDONDRAFTHELP: 'Stránka má nezverejnené zmeny' MODIFIEDONDRAFTHELP: 'Stránka má nezverejnené zmeny'
MODIFIEDONDRAFTSHORT: Zmenené MODIFIEDONDRAFTSHORT: Zmenené
MetadataToggle: Metaúdaje MetadataToggle: Metaúdaje
@ -244,11 +224,6 @@ sk:
PERMISSION_GRANTACCESS_DESCRIPTION: 'Spravovať prístupové práva pre obsah' PERMISSION_GRANTACCESS_DESCRIPTION: 'Spravovať prístupové práva pre obsah'
PERMISSION_GRANTACCESS_HELP: 'Povoliť nastavenie obmedzenia pre stránku v sekcií "Stránky".' PERMISSION_GRANTACCESS_HELP: 'Povoliť nastavenie obmedzenia pre stránku v sekcií "Stránky".'
PLURALNAME: Stránky PLURALNAME: Stránky
PLURALS:
few: '{count} Stránky'
many: '{count} Stránok'
one: Stránka
other: '{count} Stránok'
PageTypNotAllowedOnRoot: 'Stránka typu "{type}" nie je povolená na najvyššej úrovni' PageTypNotAllowedOnRoot: 'Stránka typu "{type}" nie je povolená na najvyššej úrovni'
PageTypeNotAllowed: 'Stránka typu "{type}" nie je povolená ako potomok nadradenej stránky' PageTypeNotAllowed: 'Stránka typu "{type}" nie je povolená ako potomok nadradenej stránky'
REMOVE_INSTALL_WARNING: 'Upozornenie: Z bezpečnostných dôvodov odstránte súbor install.php z SilverStripe inštalácie.' REMOVE_INSTALL_WARNING: 'Upozornenie: Z bezpečnostných dôvodov odstránte súbor install.php z SilverStripe inštalácie.'
@ -258,15 +233,9 @@ sk:
SHOWINSEARCH: 'Zobraziť v hľadaní?' SHOWINSEARCH: 'Zobraziť v hľadaní?'
SINGULARNAME: Stránka SINGULARNAME: Stránka
TABBEHAVIOUR: Správanie TABBEHAVIOUR: Správanie
TABCONTENT: 'Hlavný obsah'
TABDEPENDENT: 'Závislé stránky' TABDEPENDENT: 'Závislé stránky'
TOPLEVEL: 'Obsah Webu (Najvyššia úroveň)' TOPLEVEL: 'Obsah Webu (Najvyššia úroveň)'
UNTITLED: 'Bez názvu {pagetype}'
URLSegment: 'Časť URL'
UntitledDependentObject: 'Bez názvu {instanceType}'
VIEWERGROUPS: 'Skupiny prezeračov' VIEWERGROUPS: 'Skupiny prezeračov'
VIEWERMEMBERS: Prezerači
VIEWER_GROUPS_FIELD_DESC: 'Skupiny s globálnymi právami na zobrazenie: {groupList}'
VIEW_ALL_DESCRIPTION: 'Prezerať akúkoľvek stránku' VIEW_ALL_DESCRIPTION: 'Prezerať akúkoľvek stránku'
VIEW_ALL_HELP: 'Schopnosť zobrazovať ktorúkoľvek stránku na webe, nedbajúc na nastavenia v záložke prístupov. Vyžaduje povolenie "Prístup k sekcii ''Stránky''"' VIEW_ALL_HELP: 'Schopnosť zobrazovať ktorúkoľvek stránku na webe, nedbajúc na nastavenia v záložke prístupov. Vyžaduje povolenie "Prístup k sekcii ''Stránky''"'
VIEW_DRAFT_CONTENT: 'Zobraziť obsah konceptu' VIEW_DRAFT_CONTENT: 'Zobraziť obsah konceptu'
@ -276,65 +245,19 @@ sk:
VIRTUALPAGEWARNINGSETTINGS: 'Zvolte prosím odkazovanú stránku v poliach hlavného obsahu pre zverejnenie' VIRTUALPAGEWARNINGSETTINGS: 'Zvolte prosím odkazovanú stránku v poliach hlavného obsahu pre zverejnenie'
Viewers: 'Skupiny prezeračov' Viewers: 'Skupiny prezeračov'
Visibility: Viditeľnosť Visibility: Viditeľnosť
belongs_many_many_ContentReviewGroups: 'Skupiny na kontrolu obsahu'
belongs_many_many_ContentReviewUsers: 'Používatelia na kontrolu obsahu'
belongs_many_many_RelationFieldsTestPages: 'Testovacie stránky pre polia vzťahov'
db_CanEditType: 'Môže upraviť typ'
db_CanViewType: 'Môže zobraziť typ'
db_Content: Obsah db_Content: Obsah
db_ContentReviewType: 'Typ kontroly obsahu'
db_HasBrokenFile: 'Obsahuje porušený súbor'
db_HasBrokenLink: 'Obsahuje porušený odkaz'
db_LastEditedByName: 'Naposledy upravené podľa mena'
db_MenuTitle: 'Titulok menu'
db_MetaDescription: 'Meta popis'
db_NextReviewDate: 'Dátum ďalšej kontroly'
db_OwnerNames: 'Mená vlastníkov'
db_PublicHistory: 'Verejná história'
db_ReportClass: 'Trieda správy'
db_ReviewPeriodDays: 'Počet dní na kontrolu'
db_ShareTokenSalt: 'Zdielať soľ znaku'
db_ShowInMenus: 'Zobraziť v ponuke'
db_ShowInSearch: 'Zobraziť vo vyhľadávaní'
db_ShowPageUtilities: 'Zobraziť nástroje stránky'
db_Sort: Usporiadanie db_Sort: Usporiadanie
db_Title: Názov db_Title: Názov
db_URLSegment: 'Časť URL'
db_Version: Verzia
has_many_BackLinks: 'Spätné odkazy'
has_many_ReviewLogs: 'Prezerať záznamy'
has_many_ShareTokens: 'Zdielať znaky'
has_many_VirtualPages: 'Virtuálne stránky'
has_one_Parent: 'Nadradená stránka' has_one_Parent: 'Nadradená stránka'
has_one_RelationFieldsTestPage: 'Testovacia stránka pre polia vzťahov'
has_one_Subsite: Podstránka
has_one_WorkflowDefinition: 'Definícia pracovného toku'
many_many_AdditionalWorkflowDefinitions: 'Ďalšie definície pracovného toku'
many_many_BackLinkTracking: 'Záznamy o Backlinkoch' many_many_BackLinkTracking: 'Záznamy o Backlinkoch'
many_many_CrossSubsiteLinkTracking: 'Sledovanie odkazov naprieč podstránkami'
many_many_EditorGroups: 'Skupiny upravovateľov'
many_many_EditorMembers: 'Členovia upravovateľov'
many_many_ImageTracking: 'Záznamy o obrázkoch' many_many_ImageTracking: 'Záznamy o obrázkoch'
many_many_LinkTracking: 'Záznamy o odkazoch' many_many_LinkTracking: 'Záznamy o odkazoch'
many_many_ViewerGroups: 'Skupiny prezeračov'
many_many_ViewerMembers: 'Členovia prezeračov'
SilverStripe\CMS\Model\SiteTreeFileExtension: SilverStripe\CMS\Model\SiteTreeFileExtension:
TITLE_INDEX: '#'
TITLE_TYPE: Typ TITLE_TYPE: Typ
TITLE_USED_ON: 'Použité na' TITLE_USED_ON: 'Použité na'
SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension:
USAGE: Použitie
SilverStripe\CMS\Model\SiteTreeLink: SilverStripe\CMS\Model\SiteTreeLink:
PLURALNAME: 'Odkazy na strom stránky'
PLURALS:
few: '{count} Odkazy na strom stránky'
many: '{count} Odkazov na strom stránky'
one: 'Odkaz na strom stránky'
other: '{count} Odkazov na strom stránky'
SINGULARNAME: 'Odkaz na strom stránky'
has_one_Linked: Prepojené
has_one_Parent: 'Komentovaný príspevok' has_one_Parent: 'Komentovaný príspevok'
SilverStripe\CMS\Model\SiteTreeLinkTracking:
many_many_LinkTracking: 'Záznamy o odkazoch'
SilverStripe\CMS\Model\VirtualPage: SilverStripe\CMS\Model\VirtualPage:
CHOOSE: 'Odkazovaná stránka' CHOOSE: 'Odkazovaná stránka'
DESCRIPTION: 'Zobrazí obsah inej stránky' DESCRIPTION: 'Zobrazí obsah inej stránky'
@ -342,15 +265,8 @@ sk:
HEADER: 'Toto je virtuálna stránka' HEADER: 'Toto je virtuálna stránka'
HEADERWITHLINK: 'Toto je virtuálna stránka, kopíruje sa obsah z "{title}" ({link})' HEADERWITHLINK: 'Toto je virtuálna stránka, kopíruje sa obsah z "{title}" ({link})'
PLURALNAME: 'Základné stránky' PLURALNAME: 'Základné stránky'
PLURALS:
few: '{count} Základné stránky'
many: '{count} Základných stránok'
one: 'Virtuálna stránka'
other: '{count} Základných stránok'
PageTypNotAllowedOnRoot: 'Pôvodná stránka typu "{type}" nie je povolená na najvyššej úrovni pre túto virtuálnu stránku' PageTypNotAllowedOnRoot: 'Pôvodná stránka typu "{type}" nie je povolená na najvyššej úrovni pre túto virtuálnu stránku'
SINGULARNAME: 'Virtuálna stránka' SINGULARNAME: 'Virtuálna stránka'
db_VersionID: 'ID verzie'
has_one_CopyContentFrom: 'Kopírovať obsah z'
SilverStripe\CMS\Reports\BrokenFilesReport: SilverStripe\CMS\Reports\BrokenFilesReport:
BROKENFILES: 'Stránky s poškodenými súbormi' BROKENFILES: 'Stránky s poškodenými súbormi'
BrokenLinksGroupTitle: 'Výkazy porušených odkazov' BrokenLinksGroupTitle: 'Výkazy porušených odkazov'
@ -364,6 +280,7 @@ sk:
ColumnDateLastModified: 'Dátum poslednej úpravy' ColumnDateLastModified: 'Dátum poslednej úpravy'
ColumnDateLastPublished: 'Dátum poslednej publikácie' ColumnDateLastPublished: 'Dátum poslednej publikácie'
ColumnProblemType: 'Problémový typ' ColumnProblemType: 'Problémový typ'
ColumnURL: URL
HasBrokenFile: 'obsahuje porušený súbor' HasBrokenFile: 'obsahuje porušený súbor'
HasBrokenLink: 'obsahuje porušený odkaz' HasBrokenLink: 'obsahuje porušený odkaz'
HasBrokenLinkAndFile: 'obsahuje porušený odkaz a súbor' HasBrokenLinkAndFile: 'obsahuje porušený odkaz a súbor'
@ -386,7 +303,6 @@ sk:
ParameterLiveCheckbox: 'Skontrolovať publikovaný web' ParameterLiveCheckbox: 'Skontrolovať publikovaný web'
SilverStripe\CMS\Reports\EmptyPagesReport: SilverStripe\CMS\Reports\EmptyPagesReport:
ContentGroupTitle: 'Výkazy obsahu' ContentGroupTitle: 'Výkazy obsahu'
EMPTYPAGES: 'Stránky bez obsahu'
SilverStripe\CMS\Reports\RecentlyEditedReport: SilverStripe\CMS\Reports\RecentlyEditedReport:
ContentGroupTitle: 'Výkazy obsahu' ContentGroupTitle: 'Výkazy obsahu'
LAST2WEEKS: 'Stránky upravené počas posledných 2 týždňov' LAST2WEEKS: 'Stránky upravené počas posledných 2 týždňov'
@ -399,7 +315,7 @@ sk:
SEARCH: Hľadať SEARCH: Hľadať
SearchResults: 'Výsledky vyhľadávania' SearchResults: 'Výsledky vyhľadávania'
SilverStripe\CMS\Tasks\RemoveOrphanedPagesTask: SilverStripe\CMS\Tasks\RemoveOrphanedPagesTask:
BUTTONRUN: Spustiť BUTTONRUN: Bež
CHOOSEOPERATION: 'Vyberte operáciu:' CHOOSEOPERATION: 'Vyberte operáciu:'
DELETEWARNING: 'Upozornenie: Tieto operácie sú nezvratné. Prosím buďte opatrní.' DELETEWARNING: 'Upozornenie: Tieto operácie sú nezvratné. Prosím buďte opatrní.'
HEADER: 'Odstrániť všetky osamotené stránky' HEADER: 'Odstrániť všetky osamotené stránky'

View File

@ -70,7 +70,7 @@ sl:
SilverStripe\CMS\Controllers\CMSPageAddController: SilverStripe\CMS\Controllers\CMSPageAddController:
MENUTITLE: 'Dodaj stran' MENUTITLE: 'Dodaj stran'
ParentMode_child: 'Nivo nižje' ParentMode_child: 'Nivo nižje'
ParentMode_top: 'Stran na vrhnjem nivoju' ParentMode_top: 'Stran na prvem nivoju'
Title: 'Dodaj stran' Title: 'Dodaj stran'
SilverStripe\CMS\Controllers\CMSPageEditController: SilverStripe\CMS\Controllers\CMSPageEditController:
ErrorItemPermissionDenied: 'Nimate potrebnih pravic, da bi lahko dodali {ObjectTitle} v kampanjo.' ErrorItemPermissionDenied: 'Nimate potrebnih pravic, da bi lahko dodali {ObjectTitle} v kampanjo.'
@ -96,6 +96,7 @@ sl:
SilverStripe\CMS\Controllers\CMSPageSettingsController: SilverStripe\CMS\Controllers\CMSPageSettingsController:
MENUTITLE: 'Uredi stran' MENUTITLE: 'Uredi stran'
SilverStripe\CMS\Controllers\CMSPagesController: SilverStripe\CMS\Controllers\CMSPagesController:
FILTER: Filter
ListView: Seznam ListView: Seznam
MENUTITLE: 'Seznam strani' MENUTITLE: 'Seznam strani'
TreeView: Drevo TreeView: Drevo
@ -116,6 +117,7 @@ sl:
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
ARCHIVEDSITE: 'Predogled različice' ARCHIVEDSITE: 'Predogled različice'
ARCHIVEDSITEFROM: 'Arhivirana različica iz' ARCHIVEDSITEFROM: 'Arhivirana različica iz'
CMS: CMS
DRAFT: Osnutek DRAFT: Osnutek
DRAFTSITE: 'Osnutek spletnega mesta' DRAFTSITE: 'Osnutek spletnega mesta'
Email: E-pošta Email: E-pošta
@ -164,22 +166,17 @@ sl:
two: '{count} izvorni strani' two: '{count} izvorni strani'
REDIRECTTO: 'Preusmeri na' REDIRECTTO: 'Preusmeri na'
REDIRECTTOEXTERNAL: 'Druga spletna stran' REDIRECTTOEXTERNAL: 'Druga spletna stran'
REDIRECTTOFILE: 'Datoteka z vašega spletišča'
REDIRECTTOPAGE: 'Stran na tvojem spletnem mestu' REDIRECTTOPAGE: 'Stran na tvojem spletnem mestu'
SINGULARNAME: 'Preusmeritvena stran' SINGULARNAME: 'Preusmeritvena stran'
YOURPAGE: 'Stran na tvojem spletnem mestu' YOURPAGE: 'Stran na tvojem spletnem mestu'
db_ExternalURL: 'Zunanja povezava'
db_RedirectionType: 'Tip preusmeritve'
has_one_LinkTo: 'Poveži na' has_one_LinkTo: 'Poveži na'
has_one_LinkToFile: 'Povezava do datoteke'
SilverStripe\CMS\Model\RedirectorPageController: SilverStripe\CMS\Model\RedirectorPageController:
HASBEENSETUP: 'Nastavljena preusmeritev še nima določenega cilja.' HASBEENSETUP: 'Nastavljena preusmeritev še nima določenega cilja.'
SilverStripe\CMS\Model\SiteTree: SilverStripe\CMS\Model\SiteTree:
ACCESSANYONE: Vsakdo ACCESSANYONE: Vsakdo
ACCESSHEADER: 'Kdo lahko vidi to stran?' ACCESSHEADER: 'Kdo lahko vidi to stran?'
ACCESSLOGGEDIN: 'Prijavljeni uporabniki' ACCESSLOGGEDIN: 'Prijavljeni uporabniki'
ACCESSONLYMEMBERS: 'Izbrani uporabniki (izberite s seznama)' ACCESSONLYTHESE: 'Samo ti uporabniki (izberite jih s seznama)'
ACCESSONLYTHESE: 'Izbrane skupine (izberite s seznama)'
ADDEDTODRAFTHELP: 'Stran še ni bila objavljena' ADDEDTODRAFTHELP: 'Stran še ni bila objavljena'
ADDEDTODRAFTSHORT: Osnutek ADDEDTODRAFTSHORT: Osnutek
APPEARSVIRTUALPAGES: 'Vsebina je uporabljena na navideznih straneh iz razdelka {title}.' APPEARSVIRTUALPAGES: 'Vsebina je uporabljena na navideznih straneh iz razdelka {title}.'
@ -206,7 +203,6 @@ sl:
DependtPageColumnLinkType: 'Tip povezave' DependtPageColumnLinkType: 'Tip povezave'
EDITHEADER: 'Kdo lahko ureja to stran?' EDITHEADER: 'Kdo lahko ureja to stran?'
EDITORGROUPS: 'Skupine urednikov' EDITORGROUPS: 'Skupine urednikov'
EDITORMEMBERS: Uredniki
EDITOR_GROUPS_FIELD_DESC: 'Skupine s splošno pravico za urejanje vsebine: {groupList}' EDITOR_GROUPS_FIELD_DESC: 'Skupine s splošno pravico za urejanje vsebine: {groupList}'
EDIT_ALL_DESCRIPTION: 'Urejanje poljubne strani' EDIT_ALL_DESCRIPTION: 'Urejanje poljubne strani'
EDIT_ALL_HELP: 'Možnost urejanja katerekoli strani na spletnem mestu, ne glede na nastavitve v sklopu "Dostop". Zahteva dovoljenje za dostop do vsebine spletnega mesta.' EDIT_ALL_HELP: 'Možnost urejanja katerekoli strani na spletnem mestu, ne glede na nastavitve v sklopu "Dostop". Zahteva dovoljenje za dostop do vsebine spletnega mesta.'
@ -215,7 +211,6 @@ sl:
HTMLEDITORTITLE: Vsebina HTMLEDITORTITLE: Vsebina
INHERIT: 'Privzemi od nadrejene strani' INHERIT: 'Privzemi od nadrejene strani'
INHERITSITECONFIG: 'Privzemi iz nastavitev spletišča' INHERITSITECONFIG: 'Privzemi iz nastavitev spletišča'
InvalidExtraMeta: 'Prilagojene meta oznake ne uporabljajo pravilne kode HTML'
LASTPUBLISHED: 'Nazadnje objavljeno' LASTPUBLISHED: 'Nazadnje objavljeno'
LASTSAVED: 'Nazadnje shranjeno' LASTSAVED: 'Nazadnje shranjeno'
LASTUPDATED: 'Nazadnje urejeno' LASTUPDATED: 'Nazadnje urejeno'
@ -239,9 +234,9 @@ sl:
PAGETITLE: 'Naslov strani' PAGETITLE: 'Naslov strani'
PAGETYPE: 'Tip strani' PAGETYPE: 'Tip strani'
PARENTID: 'Nadrejena stran' PARENTID: 'Nadrejena stran'
PARENTTYPE: Umestitev PARENTTYPE: 'Lokacija strani'
PARENTTYPE_ROOT: 'Stran na vrhnjem nivoju' PARENTTYPE_ROOT: 'Stran na prvem nivoju'
PARENTTYPE_SUBPAGE: 'Podstran (izberite nadrejeno stran)' PARENTTYPE_SUBPAGE: 'Podstran (izberite nadrejeno stran spodaj)'
PERMISSION_GRANTACCESS_DESCRIPTION: 'Upravljaj s pravicami za dostop do vsebine' PERMISSION_GRANTACCESS_DESCRIPTION: 'Upravljaj s pravicami za dostop do vsebine'
PERMISSION_GRANTACCESS_HELP: 'Dovoli nastavitve pravic za dostop do izbrane strani v sklopu "Strani".' PERMISSION_GRANTACCESS_HELP: 'Dovoli nastavitve pravic za dostop do izbrane strani v sklopu "Strani".'
PLURALNAME: Strani PLURALNAME: Strani
@ -255,18 +250,17 @@ sl:
REMOVE_INSTALL_WARNING: 'Pozor: Zaradi varnosti priporočamo, da odstranite install.php it te SilverStripe namestitve.' REMOVE_INSTALL_WARNING: 'Pozor: Zaradi varnosti priporočamo, da odstranite install.php it te SilverStripe namestitve.'
REORGANISE_DESCRIPTION: 'Spremeni strukturo spletnega mesta' REORGANISE_DESCRIPTION: 'Spremeni strukturo spletnega mesta'
REORGANISE_HELP: 'Razvrsti strani v drevesni strukturi s funkcijo "povleci in izpusti".' REORGANISE_HELP: 'Razvrsti strani v drevesni strukturi s funkcijo "povleci in izpusti".'
SHOWINMENUS: 'Izpiši v navigaciji' SHOWINMENUS: 'Prikaži v navigaciji'
SHOWINSEARCH: 'Izpiši med rezultati iskanja' SHOWINSEARCH: 'Prikaži v iskalnikih'
SINGULARNAME: Stran SINGULARNAME: Stran
TABBEHAVIOUR: Obnašanje TABBEHAVIOUR: Obnašanje
TABCONTENT: 'Osrednja vsebina' TABCONTENT: 'Osrednja vsebina'
TABDEPENDENT: 'Odvisne strani' TABDEPENDENT: 'Odvisne strani'
TOPLEVEL: 'Vsebina spletišča (vrhnji nivo)' TOPLEVEL: 'Vsebina Strani (Zgornja Stopnja)'
UNTITLED: '{pagetype} brez naslova' UNTITLED: '{pagetype} brez naslova'
URLSegment: 'Naslov URL' URLSegment: 'Naslov URL'
UntitledDependentObject: '{instanceType} brez naslova' UntitledDependentObject: '{instanceType} brez naslova'
VIEWERGROUPS: 'Skupine ogledovalcev' VIEWERGROUPS: 'Skupine obiskovalcev'
VIEWERMEMBERS: Ogledovalci
VIEWER_GROUPS_FIELD_DESC: 'Skupine s splošno pravico za ogled vsebine: {groupList}' VIEWER_GROUPS_FIELD_DESC: 'Skupine s splošno pravico za ogled vsebine: {groupList}'
VIEW_ALL_DESCRIPTION: 'Ogled vsake strani' VIEW_ALL_DESCRIPTION: 'Ogled vsake strani'
VIEW_ALL_HELP: 'Možnost ogleda katere koli strani ne glede na to, kako so nastavljene pravice za ogled strani v sklopu ''Dostop''. Predpogoj je pravica za dostop do razdelka "Seznam strani".' VIEW_ALL_HELP: 'Možnost ogleda katere koli strani ne glede na to, kako so nastavljene pravice za ogled strani v sklopu ''Dostop''. Predpogoj je pravica za dostop do razdelka "Seznam strani".'
@ -277,50 +271,15 @@ sl:
VIRTUALPAGEWARNINGSETTINGS: 'Najprej v glavnih vsebinskih poljih izberite povezano stran, potem boste lahko objavili stran.' VIRTUALPAGEWARNINGSETTINGS: 'Najprej v glavnih vsebinskih poljih izberite povezano stran, potem boste lahko objavili stran.'
Viewers: 'Skupine obiskovalcev (viewers)' Viewers: 'Skupine obiskovalcev (viewers)'
Visibility: Vidnost Visibility: Vidnost
belongs_many_many_ContentReviewGroups: 'Skupine redaktorjev'
belongs_many_many_ContentReviewUsers: Redaktorji
belongs_many_many_RelationFieldsTestPages: 'Stran za preizkus relacij'
db_CanEditType: 'Lahko ureja'
db_CanViewType: 'Lahko ogleduje'
db_Content: Vsebina db_Content: Vsebina
db_ContentReviewType: 'Lahko redagira' db_Title: Naziv
db_ExtraMeta: 'Dodatne meta oznake'
db_HasBrokenFile: 'Vsebuje nedelujočo datoteko'
db_HasBrokenLink: 'Vsebuje nedelujočo povezavo'
db_LastEditedByName: 'Zadnje urejanje (poimensko)'
db_MenuTitle: 'Naslov v navigaciji'
db_MetaDescription: 'Meta opis'
db_NextReviewDate: 'Rok za naslednji pregled'
db_OwnerNames: 'Imena lastnikov'
db_PublicHistory: 'Javna zgodovina'
db_ReportClass: Poročilo
db_ReviewPeriodDays: 'Interval za pregled v dnevih'
db_ShareTokenSalt: 'Sol za ključe za dostop'
db_ShowInMenus: 'Izpiši v navigaciji'
db_ShowInSearch: 'Izpiši med rezultati iskanja'
db_ShowPageUtilities: 'Prikaži uporabo strani'
db_Sort: Razvrščanje
db_Title: Naslov
db_URLSegment: 'Naslov URL' db_URLSegment: 'Naslov URL'
db_Version: Verzija
has_many_BackLinks: 'Povratne povezave'
has_many_ReviewLogs: 'Dnevnik pregledov'
has_many_ShareTokens: 'Ključi za dostop'
has_many_VirtualPages: 'Navidezne strani'
has_one_Parent: 'Nadrejena stran' has_one_Parent: 'Nadrejena stran'
has_one_RelationFieldsTestPage: 'Stran za preizkus relacij' many_many_BackLinkTracking: 'Spremljanje povezav "nazaj"'
has_one_Subsite: Podspletišče
has_one_WorkflowDefinition: 'Definicija uredniškega procesa'
many_many_AdditionalWorkflowDefinitions: 'Dodatne definicije uredniških procesov'
many_many_BackLinkTracking: 'Spremljanje povratnih povezav'
many_many_CrossSubsiteLinkTracking: 'Spremljanje povezav med podspletišči'
many_many_EditorGroups: 'Skupine urednikov'
many_many_EditorMembers: Uredniki
many_many_ImageTracking: 'Spremljanje slik' many_many_ImageTracking: 'Spremljanje slik'
many_many_LinkTracking: 'Spremljanje povezav' many_many_LinkTracking: 'Spremljanje povezav'
many_many_ViewerGroups: 'Skupine ogledovalcev'
many_many_ViewerMembers: Ogledovalci
SilverStripe\CMS\Model\SiteTreeFileExtension: SilverStripe\CMS\Model\SiteTreeFileExtension:
TITLE_INDEX: '#'
TITLE_TYPE: Tip TITLE_TYPE: Tip
TITLE_USED_ON: 'Uporabljena na' TITLE_USED_ON: 'Uporabljena na'
SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension: SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension:
@ -333,10 +292,6 @@ sl:
other: '{count} povezav v strukturi' other: '{count} povezav v strukturi'
two: '{count} povezavi v strukturi' two: '{count} povezavi v strukturi'
SINGULARNAME: 'Povezava v strukturi' SINGULARNAME: 'Povezava v strukturi'
has_one_Linked: Povezano
has_one_Parent: 'Nadrejeno pravilo'
SilverStripe\CMS\Model\SiteTreeLinkTracking:
many_many_LinkTracking: 'Spremljanje povezav'
SilverStripe\CMS\Model\VirtualPage: SilverStripe\CMS\Model\VirtualPage:
CHOOSE: 'Povezana stran' CHOOSE: 'Povezana stran'
DESCRIPTION: 'Prikaže vsebino, ki je vnesena na drugi strani' DESCRIPTION: 'Prikaže vsebino, ki je vnesena na drugi strani'
@ -350,9 +305,7 @@ sl:
other: '{count} izvornih strani' other: '{count} izvornih strani'
two: '{count} izvorni strani' two: '{count} izvorni strani'
PageTypNotAllowedOnRoot: 'Tipa izvorne strani ({type}), ki je osnova za to virtualno stran, ni dovoljeno umestiti na korenskem nivoju' PageTypNotAllowedOnRoot: 'Tipa izvorne strani ({type}), ki je osnova za to virtualno stran, ni dovoljeno umestiti na korenskem nivoju'
SINGULARNAME: 'Navidezna stran' SINGULARNAME: 'Virtualna stran'
db_VersionID: Različica
has_one_CopyContentFrom: 'Kopiraj vsebino iz'
SilverStripe\CMS\Reports\BrokenFilesReport: SilverStripe\CMS\Reports\BrokenFilesReport:
BROKENFILES: 'Strani z nedelujočimi datotekami' BROKENFILES: 'Strani z nedelujočimi datotekami'
BrokenLinksGroupTitle: 'Poročila o nedelujočih povezavah' BrokenLinksGroupTitle: 'Poročila o nedelujočih povezavah'
@ -366,6 +319,7 @@ sl:
ColumnDateLastModified: 'Datum zadnje spremembe' ColumnDateLastModified: 'Datum zadnje spremembe'
ColumnDateLastPublished: 'Datum zadnje objave' ColumnDateLastPublished: 'Datum zadnje objave'
ColumnProblemType: 'Vrsta težave' ColumnProblemType: 'Vrsta težave'
ColumnURL: URL
HasBrokenFile: 'vsebuje datoteko z napako' HasBrokenFile: 'vsebuje datoteko z napako'
HasBrokenLink: 'ima nedelujočo povezavo' HasBrokenLink: 'ima nedelujočo povezavo'
HasBrokenLinkAndFile: 'ima nedelujočo povezavo in vsebuje datoteko z napako' HasBrokenLinkAndFile: 'ima nedelujočo povezavo in vsebuje datoteko z napako'

View File

@ -77,6 +77,7 @@ sr:
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
ARCHIVEDSITE: 'Верзија за претходни преглед' ARCHIVEDSITE: 'Верзија за претходни преглед'
ARCHIVEDSITEFROM: 'Архивирани сајт из' ARCHIVEDSITEFROM: 'Архивирани сајт из'
CMS: CMS
DRAFT: Нацрт DRAFT: Нацрт
DRAFTSITE: 'Нарцт сајта' DRAFTSITE: 'Нарцт сајта'
Email: Е-пошта Email: Е-пошта
@ -225,6 +226,7 @@ sr:
ColumnDateLastModified: 'Датум последње измене' ColumnDateLastModified: 'Датум последње измене'
ColumnDateLastPublished: 'Датум последњег публиковања' ColumnDateLastPublished: 'Датум последњег публиковања'
ColumnProblemType: 'Тип проблема' ColumnProblemType: 'Тип проблема'
ColumnURL: URL
HasBrokenFile: 'садржи оштећену датотеку' HasBrokenFile: 'садржи оштећену датотеку'
HasBrokenLink: 'садржи оштећен линк' HasBrokenLink: 'садржи оштећен линк'
HasBrokenLinkAndFile: 'садржи оштећене линк и датотеку' HasBrokenLinkAndFile: 'садржи оштећене линк и датотеку'

View File

@ -14,6 +14,8 @@ sr@latin:
TabContent: Sadržaj TabContent: Sadržaj
SilverStripe\CMS\Controllers\CMSPageHistoryController: SilverStripe\CMS\Controllers\CMSPageHistoryController:
UNKNOWN: Nepoznato UNKNOWN: Nepoznato
SilverStripe\CMS\Controllers\CMSPagesController:
FILTER: Filter
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
Email: 'Elektronska pošta' Email: 'Elektronska pošta'
LOGOUT: 'Odjavi se' LOGOUT: 'Odjavi se'
@ -44,6 +46,7 @@ sr@latin:
has_one_Parent: Roditelj has_one_Parent: Roditelj
SilverStripe\CMS\Reports\BrokenLinksReport: SilverStripe\CMS\Reports\BrokenLinksReport:
Any: 'Bilo koji' Any: 'Bilo koji'
ColumnURL: URL
SilverStripe\CMS\Search\SearchForm: SilverStripe\CMS\Search\SearchForm:
FILTERLABELTEXT: Pretraga FILTERLABELTEXT: Pretraga
GO: Idi GO: Idi

View File

@ -4,6 +4,7 @@ sr_RS:
CANT_REORGANISE: 'Немате право да мењате странице вршног нивоа. Ваше измене нису сачуване.' CANT_REORGANISE: 'Немате право да мењате странице вршног нивоа. Ваше измене нису сачуване.'
Cancel: Одустани Cancel: Одустани
Create: Креирај Create: Креирај
EMAIL: Email
PAGETYPEANYOPT: 'Било који' PAGETYPEANYOPT: 'Било који'
PLEASESAVE: 'Сачувајте страну: ова страна не може да буде ажурирана јер још увек није сачувана.' PLEASESAVE: 'Сачувајте страну: ова страна не може да буде ажурирана јер још увек није сачувана.'
REORGANISATIONSUCCESSFUL: 'Стабло сајта је успешно реорганизовано.' REORGANISATIONSUCCESSFUL: 'Стабло сајта је успешно реорганизовано.'
@ -15,11 +16,13 @@ sr_RS:
MENUTITLE: 'Измени страницу' MENUTITLE: 'Измени страницу'
SilverStripe\CMS\Controllers\CMSPageHistoryController: SilverStripe\CMS\Controllers\CMSPageHistoryController:
UNKNOWN: Непознато UNKNOWN: Непознато
WHEN: When
SilverStripe\CMS\Controllers\CMSPageSettingsController: SilverStripe\CMS\Controllers\CMSPageSettingsController:
MENUTITLE: 'Измени страницу' MENUTITLE: 'Измени страницу'
SilverStripe\CMS\Controllers\CMSPagesController: SilverStripe\CMS\Controllers\CMSPagesController:
FILTER: Филтер FILTER: Филтер
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
Email: Email
LOGOUT: 'Одјави се' LOGOUT: 'Одјави се'
NOTLOGGEDIN: 'Нисте пријављени' NOTLOGGEDIN: 'Нисте пријављени'
Password: Лозинка Password: Лозинка
@ -48,7 +51,9 @@ sr_RS:
PLURALNAME: 'User Defined Forms' PLURALNAME: 'User Defined Forms'
SilverStripe\CMS\Reports\BrokenLinksReport: SilverStripe\CMS\Reports\BrokenLinksReport:
Any: 'Било који' Any: 'Било који'
ColumnURL: URL
SilverStripe\CMS\Search\SearchForm: SilverStripe\CMS\Search\SearchForm:
FILTERDATEFROM: From
FILTERLABELTEXT: Претрага FILTERLABELTEXT: Претрага
GO: Иди GO: Иди
SEARCH: Претрага SEARCH: Претрага

View File

@ -68,6 +68,7 @@ sr_RS@latin:
SilverStripe\CMS\Controllers\CMSPageSettingsController: SilverStripe\CMS\Controllers\CMSPageSettingsController:
MENUTITLE: 'Izmeni stranicu' MENUTITLE: 'Izmeni stranicu'
SilverStripe\CMS\Controllers\CMSPagesController: SilverStripe\CMS\Controllers\CMSPagesController:
FILTER: Filter
ListView: 'Prikaz u vidu liste' ListView: 'Prikaz u vidu liste'
MENUTITLE: Stranice MENUTITLE: Stranice
TreeView: 'Prikaz u vidu stabla' TreeView: 'Prikaz u vidu stabla'
@ -76,6 +77,7 @@ sr_RS@latin:
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
ARCHIVEDSITE: 'Verzija za prethodni pregled' ARCHIVEDSITE: 'Verzija za prethodni pregled'
ARCHIVEDSITEFROM: 'Arhivirani sajt iz' ARCHIVEDSITEFROM: 'Arhivirani sajt iz'
CMS: CMS
DRAFT: Nacrt DRAFT: Nacrt
DRAFTSITE: 'Narct sajta' DRAFTSITE: 'Narct sajta'
Email: E-pošta Email: E-pošta
@ -224,6 +226,7 @@ sr_RS@latin:
ColumnDateLastModified: 'Datum poslednje izmene' ColumnDateLastModified: 'Datum poslednje izmene'
ColumnDateLastPublished: 'Datum poslednjeg publikovanja' ColumnDateLastPublished: 'Datum poslednjeg publikovanja'
ColumnProblemType: 'Tip problema' ColumnProblemType: 'Tip problema'
ColumnURL: URL
HasBrokenFile: 'sadrži oštećenu datoteku' HasBrokenFile: 'sadrži oštećenu datoteku'
HasBrokenLink: 'sadrži oštećen link' HasBrokenLink: 'sadrži oštećen link'
HasBrokenLinkAndFile: 'sadrži oštećene link i datoteku' HasBrokenLinkAndFile: 'sadrži oštećene link i datoteku'

View File

@ -94,6 +94,7 @@ sv:
SilverStripe\CMS\Controllers\CMSPageSettingsController: SilverStripe\CMS\Controllers\CMSPageSettingsController:
MENUTITLE: 'Redigera sida' MENUTITLE: 'Redigera sida'
SilverStripe\CMS\Controllers\CMSPagesController: SilverStripe\CMS\Controllers\CMSPagesController:
FILTER: Filter
ListView: Listvy ListView: Listvy
MENUTITLE: Sidor MENUTITLE: Sidor
TreeView: Trädvy TreeView: Trädvy
@ -114,6 +115,7 @@ sv:
SilverStripe\CMS\Controllers\ContentController: SilverStripe\CMS\Controllers\ContentController:
ARCHIVEDSITE: 'Utkast version' ARCHIVEDSITE: 'Utkast version'
ARCHIVEDSITEFROM: 'Arkiverad sajt från' ARCHIVEDSITEFROM: 'Arkiverad sajt från'
CMS: CMS
DRAFT: Utkast DRAFT: Utkast
DRAFTSITE: Utkast DRAFTSITE: Utkast
Email: E-post Email: E-post
@ -147,6 +149,7 @@ sv:
Cancel: Avbryt Cancel: Avbryt
Edit: Redigera Edit: Redigera
HelpChars: 'Specialtecken konverteras eller tas bort' HelpChars: 'Specialtecken konverteras eller tas bort'
OK: OK
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
DESCRIPTION: 'Omdirigerar till en annan intern eller extern sida' DESCRIPTION: 'Omdirigerar till en annan intern eller extern sida'
FILE: Fil FILE: Fil
@ -214,6 +217,7 @@ sv:
METAEXTRA: 'Egna metataggar' METAEXTRA: 'Egna metataggar'
MODIFIEDONDRAFTHELP: 'Sidan har ej publicerade ändringar' MODIFIEDONDRAFTHELP: 'Sidan har ej publicerade ändringar'
MODIFIEDONDRAFTSHORT: Ändrad MODIFIEDONDRAFTSHORT: Ändrad
MetadataToggle: Metadata
MoreOptions: 'Fler alternativ' MoreOptions: 'Fler alternativ'
NOTPUBLISHED: 'Ej publicerad' NOTPUBLISHED: 'Ej publicerad'
OBSOLETECLASS: 'Denna sida är den föråldrade typen {type}. Att spara kommer att återställa dess typ och du kan förlora data' OBSOLETECLASS: 'Denna sida är den föråldrade typen {type}. Att spara kommer att återställa dess typ och du kan förlora data'
@ -262,6 +266,7 @@ sv:
many_many_ImageTracking: 'Spåra bild' many_many_ImageTracking: 'Spåra bild'
many_many_LinkTracking: 'Spåra länk' many_many_LinkTracking: 'Spåra länk'
SilverStripe\CMS\Model\SiteTreeFileExtension: SilverStripe\CMS\Model\SiteTreeFileExtension:
TITLE_INDEX: '#'
TITLE_TYPE: Typ TITLE_TYPE: Typ
TITLE_USED_ON: 'Använd på' TITLE_USED_ON: 'Använd på'
SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension: SilverStripe\CMS\Model\SiteTreeFileFormFactoryExtension:
@ -295,6 +300,7 @@ sv:
ColumnDateLastModified: 'Datum vid senaste modifiering' ColumnDateLastModified: 'Datum vid senaste modifiering'
ColumnDateLastPublished: 'Datum vid senaste publicering' ColumnDateLastPublished: 'Datum vid senaste publicering'
ColumnProblemType: Problemtyp ColumnProblemType: Problemtyp
ColumnURL: URL
HasBrokenFile: 'har trasig fil' HasBrokenFile: 'har trasig fil'
HasBrokenLink: 'har trasig länk' HasBrokenLink: 'har trasig länk'
HasBrokenLinkAndFile: 'har trasig länk och fil' HasBrokenLinkAndFile: 'har trasig länk och fil'

View File

@ -62,6 +62,8 @@ tr:
ANCHORVALUE: Çapa ANCHORVALUE: Çapa
SilverStripe\CMS\Forms\InternalLinkFormFactory: SilverStripe\CMS\Forms\InternalLinkFormFactory:
LINKDESCR: 'Bağlantııklaması' LINKDESCR: 'Bağlantııklaması'
SilverStripe\CMS\Forms\SiteTreeURLSegmentField:
Edit: Edit
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
FILE: Dosya FILE: Dosya
HEADER: 'Bu sayfa, kullanıcıları başka bir sayfaya yönlendirir' HEADER: 'Bu sayfa, kullanıcıları başka bir sayfaya yönlendirir'

View File

@ -82,6 +82,7 @@ uk:
LINKDESCR: 'Опис посилання' LINKDESCR: 'Опис посилання'
SilverStripe\CMS\Forms\SiteTreeURLSegmentField: SilverStripe\CMS\Forms\SiteTreeURLSegmentField:
Cancel: Відмінити Cancel: Відмінити
Edit: Edit
HelpChars: 'Спеціальні символи автоматично перетворені або видалені.' HelpChars: 'Спеціальні символи автоматично перетворені або видалені.'
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
FILE: Файл FILE: Файл

View File

@ -1,50 +0,0 @@
uk_UA:
SilverStripe\CMS\Controllers\CMSMain:
ACCESS_HELP: 'Дозволити перегляд розділу, що містить дерево сторінок і вміст. Дозволи на перегляд і редагування можна налаштувати за допомогою спадних меню для окремих сторінок, а також за допомогою окремих "вміст дозволів".'
PAGETYPEOPT: 'Тип сторінки'
PUBALLCONFIRM: 'Будь ласка, опублікуйте кожну сторінку сайту, скопіювавши етап вмісту'
PUBALLFUN2: 'Натискання цієї кнопки еквівалентно переходу на кожну сторінку та натисканню "опублікувати". Він призначений для використання після масових редагувань вмісту, наприклад під час створення сайту. Для великих веб-сайтів це завдання може бути не виконано до кінця. У цьому випадку ми рекомендуємо поговорити з вашими розробниками, щоб створити спеціальне завдання'
TabContent: Зміст
SilverStripe\CMS\Controllers\ContentController:
StartEditing: 'Ви можете почати редагувати свій зміст, відкривши <a href="{link}">CMS</a>.'
SilverStripe\CMS\Forms\SiteTreeURLSegmentField:
Edit: Редагувати
SilverStripe\CMS\Model\SiteTree:
APPEARSVIRTUALPAGES: 'Цей зміст також відображається на віртуальних сторінках у розділах {title}.'
Content: Зміст
DEFAULTABOUTCONTENT: '<p>Ви можете заповнити цю сторінку власним змістом або видалити її та створити власні сторінки.</p>'
DEFAULTCONTACTCONTENT: '<p>Ви можете заповнити цю сторінку власним змістом або видалити її та створити власні сторінки.</p>'
DEPENDENT_NOTE: 'Наступні сторінки залежать від цієї сторінки. Це включає віртуальні сторінки, сторінки перенаправлення та сторінки з посиланнями на зміст.'
DESCRIPTION: 'Сторінка загального змісту'
HTMLEDITORTITLE: Зміст
MENUTITLE: 'Навігаційна мітка'
METADESCHELP: 'Пошукові системи використовують цей зміст для відображення результатів пошуку (хоча це не вплине на їх рейтинг).'
METAEXTRAHELP: 'Теги HTML для додаткової метаінформації. Наприклад <meta name="customName" content="ваш спеціальний зміст тут">'
PAGELOCATION: 'Розташування сторінки'
PAGETITLE: 'Назва сторінки'
PAGETYPE: 'Тип сторінки'
PARENTID: 'Батьківська сторінка'
PARENTTYPE: 'Розташування сторінки'
PARENTTYPE_ROOT: 'Сторінка верхнього рівня'
PERMISSION_GRANTACCESS_DESCRIPTION: 'Керувати правами доступу до змісту'
TABCONTENT: 'Основний зміст'
TOPLEVEL: 'Зміст сайту (верхній рівень)'
URLSegment: 'сегмент URL'
VIEW_DRAFT_CONTENT: 'Переглянути чернетку змісту'
VIRTUALPAGEWARNINGSETTINGS: 'Виберіть пов''язану сторінку в полях основного змісту, щоб опублікувати'
belongs_many_many_ContentReviewGroups: 'Групи перегляду змісту'
belongs_many_many_ContentReviewUsers: 'Користувачі перегляду змісту'
db_Content: Зміст
db_ContentReviewType: 'Тип перегляду змісту'
db_URLSegment: 'сегмент URL'
SilverStripe\CMS\Model\VirtualPage:
DESCRIPTION: 'Відображає зміст іншої сторінки'
HEADERWITHLINK: 'Це віртуальна сторінка, яка копіює вміст із "{title}" ({link})'
has_one_CopyContentFrom: 'Копіювати зміст із'
SilverStripe\CMS\Reports\BrokenLinksReport:
PageName: 'Назва сторінки'
SilverStripe\CMS\Reports\EmptyPagesReport:
ContentGroupTitle: 'Зміст звітів'
EMPTYPAGES: 'Сторінки без змісту'
SilverStripe\CMS\Reports\RecentlyEditedReport:
ContentGroupTitle: 'Зміст звітів'

View File

@ -7,6 +7,8 @@ vi_VN:
PAGETYPEOPT: Loại PAGETYPEOPT: Loại
SAVEDRAFT: Lưu SAVEDRAFT: Lưu
TabContent: 'Nội dung' TabContent: 'Nội dung'
SilverStripe\CMS\Forms\SiteTreeURLSegmentField:
Edit: Edit
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
HEADER: 'Trang này sẽ di chuyển người dùng đến một trang khác' HEADER: 'Trang này sẽ di chuyển người dùng đến một trang khác'
OTHERURL: 'Đường dẩn website khác' OTHERURL: 'Đường dẩn website khác'

View File

@ -27,6 +27,7 @@ zh:
Create: 创建 Create: 创建
DUPLICATED: '成功复制‘{title}' DUPLICATED: '成功复制‘{title}'
DUPLICATEDWITHCHILDREN: '成功复制‘{title}’及其子页面' DUPLICATEDWITHCHILDREN: '成功复制‘{title}’及其子页面'
EMAIL: Email
NEWPAGE: '新建{pagetype}' NEWPAGE: '新建{pagetype}'
PAGENOTEXISTS: 该页面不存在 PAGENOTEXISTS: 该页面不存在
PAGES: 页面状态 PAGES: 页面状态

View File

@ -27,6 +27,8 @@ zh_CN:
Password: 密码 Password: 密码
SilverStripe\CMS\Forms\InternalLinkFormFactory: SilverStripe\CMS\Forms\InternalLinkFormFactory:
LINKDESCR: 链接描述 LINKDESCR: 链接描述
SilverStripe\CMS\Forms\SiteTreeURLSegmentField:
Edit: Edit
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
FILE: 文件 FILE: 文件
HEADER: 该页会将用户重新导向另一网页 HEADER: 该页会将用户重新导向另一网页

View File

@ -44,6 +44,8 @@ zh_TW:
Password: 密碼 Password: 密碼
SilverStripe\CMS\Forms\InternalLinkFormFactory: SilverStripe\CMS\Forms\InternalLinkFormFactory:
LINKDESCR: 連結敘述 LINKDESCR: 連結敘述
SilverStripe\CMS\Forms\SiteTreeURLSegmentField:
Edit: Edit
SilverStripe\CMS\Model\RedirectorPage: SilverStripe\CMS\Model\RedirectorPage:
FILE: 檔案 FILE: 檔案
HEADER: 本網頁將重新導向用戶至別的網頁 HEADER: 本網頁將重新導向用戶至別的網頁

View File

@ -1,15 +1,15 @@
{ {
"name": "silverstripe-cms", "name": "silverstripe-cms",
"version": "4.0.0", "version": "5.0.0",
"description": "The SilverStripe CMS", "description": "The SilverStripe CMS",
"directories": { "directories": {
"test": "tests" "test": "tests"
}, },
"engines": { "engines": {
"node": "^10.x" "node": "^18.x"
}, },
"scripts": { "scripts": {
"build": "yarn && yarn test && NODE_ENV=production webpack -p --bail --progress", "build": "yarn && yarn lint && yarn test && rm -rf client/dist/* && NODE_ENV=production webpack --mode production --bail --progress",
"dev": "NODE_ENV=development webpack --progress", "dev": "NODE_ENV=development webpack --progress",
"watch": "NODE_ENV=development webpack --watch --progress", "watch": "NODE_ENV=development webpack --watch --progress",
"css": "WEBPACK_CHILD=css npm run build", "css": "WEBPACK_CHILD=css npm run build",
@ -32,36 +32,42 @@
}, },
"homepage": "https://github.com/silverstripe/silverstripe-cms#readme", "homepage": "https://github.com/silverstripe/silverstripe-cms#readme",
"dependencies": { "dependencies": {
"@silverstripe/reactstrap-confirm": "0.0.5", "@apollo/client": "^3.7.1",
"apollo-client": "^2.4.2", "@popperjs/core": "^2.11.6",
"bootstrap": "^4.3.1", "bootstrap": "^4.6.2",
"classnames": "^2.2.5", "classnames": "^2.3.2",
"deep-freeze-strict": "^1.1.1", "deep-freeze-strict": "^1.1.1",
"graphql": "^14.0.0", "graphql": "^16.6.0",
"graphql-tag": "^2.10.0", "graphql-tag": "^2.12.6",
"isomorphic-fetch": "^2.2.1", "isomorphic-fetch": "^3.0.0",
"jquery": "^3.5.0",
"merge": "^2.1.1", "merge": "^2.1.1",
"popper.js": "^1.14.4", "prop-types": "^15.8.1",
"prop-types": "^15.6.2", "react": "^18.2.0",
"react": "^16.6.1", "react-dom": "^18.2.0",
"react-apollo": "^2.1.11", "react-redux": "^8.0.5",
"react-dom": "^16.6.1", "react-select": "^5.6.0",
"react-redux": "^5.0.7", "reactstrap": "^8.9.0",
"react-select": "^1.3", "reactstrap-confirm": "^1.3.2",
"reactstrap": "^6.4.0", "redux": "^4.2.0",
"redux": "^4.0.0", "redux-form": "^8.3.8"
"redux-form": "^7.4.2"
}, },
"devDependencies": { "devDependencies": {
"@silverstripe/eslint-config": "^0.1.0", "@silverstripe/eslint-config": "^1.1.0",
"@silverstripe/webpack-config": "^1.3.0", "@silverstripe/webpack-config": "^2.0.0",
"babel-jest": "^23.6.0", "@testing-library/react": "^14.0.0",
"babel-polyfill": "^6.26.0", "babel-jest": "^29.3.0",
"copy-webpack-plugin": "^4", "copy-webpack-plugin": "^11.0.0",
"jest-cli": "^23.6.0" "core-js": "^3.26.0",
"jest-cli": "^29.3.0",
"jest-environment-jsdom": "^29.3.1",
"webpack": "^5.74.0",
"webpack-cli": "^5.0.0"
}, },
"browserslist": [
"defaults"
],
"jest": { "jest": {
"testEnvironment": "jsdom",
"roots": [ "roots": [
"client/src" "client/src"
], ],
@ -82,16 +88,6 @@
} }
}, },
"resolutions": { "resolutions": {
"colors": "1.1.2", "colors": "1.4.0"
"eslint": "^4.6.1"
},
"babel": {
"presets": [
"env",
"react"
],
"plugins": [
"transform-object-rest-spread"
]
} }
} }

View File

View File

@ -1,16 +0,0 @@
<div class="cms-preview fill-height flexbox-area-grow" data-layout-type="border">
<div class="panel flexbox-area-grow fill-height">
<div class="preview-note">
<div class="icon font-icon-monitor display-1"></div>
<%t SilverStripe\CMS\Controllers\CMSPageHistoryController.NO_PREVIEW 'No preview available' %>
</div>
<div class="preview__device">
<div class="preview-device-outer">
<div class="preview-device-inner">
<iframe src="about:blank" class="center" name="cms-preview-iframe"></iframe>
</div>
</div>
</div>
</div>
<div class="toolbar toolbar--south cms-content-controls cms-preview-controls"></div>
</div>

View File

@ -13,12 +13,12 @@
<div class="input-group"> <div class="input-group">
<input $AttributesHTML /> <input $AttributesHTML />
<div class="input-group-append"> <div class="input-group-append">
<button role="button" data-icon="accept" type="button" class="btn btn-primary update"> <button role="button" type="button" class="btn btn-primary update">
<%t SilverStripe\CMS\Forms\SiteTreeURLSegmentField.OK 'OK' %> <%t SilverStripe\CMS\Forms\SiteTreeURLSegmentField.OK 'OK' %>
</button> </button>
</div> </div>
<div class="input-group-append"> <div class="input-group-append">
<button role="button" data-icon="cancel" type="button" class="btn btn-outline-secondary btn-sm input-group-append cancel"> <button role="button" type="button" class="btn btn-outline-secondary btn-sm input-group-append cancel">
<%t SilverStripe\CMS\Forms\SiteTreeURLSegmentField.Cancel 'Cancel' %> <%t SilverStripe\CMS\Forms\SiteTreeURLSegmentField.Cancel 'Cancel' %>
</button> </button>
</div> </div>

View File

@ -1,27 +0,0 @@
<% if $BackLinkTracking %>
<table class="table">
<thead>
<tr>
<th><%t SilverStripe\CMS\Model\SiteTreeFileExtension.TITLE_INDEX '#' %></th>
<th><%t SilverStripe\CMS\Model\SiteTreeFileExtension.TITLE_USED_ON 'Used on' %></th>
<th><%t SilverStripe\CMS\Model\SiteTreeFileExtension.TITLE_TYPE 'Type' %></th>
</tr>
</thead>
<tbody>
<% loop $BackLinkTracking %>
<tr>
<td>$Pos</td>
<td><a href="$CMSEditLink">$MenuTitle</a></td>
<td>
$i18n_singular_name
<% if $isPublished %>
<span class="badge badge-success">Published</span>
<% else %>
<span class="badge status-addedtodraft">Draft</span>
<% end_if %>
</td>
</tr>
<% end_loop %>
</tbody>
</table>
<% end_if %>

View File

@ -81,19 +81,19 @@ Feature: Edit a page
When I click on "About Us" in the tree When I click on "About Us" in the tree
# Embed files from the "Files" section of the admin area # Embed files from the "Files" section of the admin area
And I click on the "div[aria-label='Insert from Files'] button" element And I press the "Insert from Files" HTML field button
And I click on the ".gallery__files .gallery-item__thumbnail" element And I click on the ".gallery__files .gallery-item__thumbnail" element
And I press the "Insert file" button And I press the "Insert file" button
# Link to a file in the "Files" section of the admin area # Link to a file in the "Files" section of the admin area
And I click on the "div[aria-label='Insert link [Ctrl+K]'] button" element And I press the "Insert link" HTML field button
And I select "Link to a file" from the TinyMCE menu with javascript And I click "Link to a file" in the ".tox-collection__group" element
And I click on the ".gallery__files .gallery-item__thumbnail" element And I click on the ".gallery__files .gallery-item__thumbnail" element
And I fill in "Form_fileInsertForm_Text" with "MyImage" And I fill in "Form_fileInsertForm_Text" with "MyImage"
And I press the "Link to file" button And I press the "Link to file" button
# Embed media from a URL # Embed media from a URL
And I click on the "div[aria-label='Insert media via URL'] button" element And I press the "Insert media via URL" button
And I fill in "Form_remoteCreateForm_Url" with "https://www.youtube.com/watch?v=ScMzIvxBSi4" And I fill in "Form_remoteCreateForm_Url" with "https://www.youtube.com/watch?v=ScMzIvxBSi4"
And I press "Add media" And I press "Add media"
And I wait for 15 seconds And I wait for 15 seconds

View File

@ -17,12 +17,11 @@ So that I can link to a external website or a page on my site
Scenario: I can link to an internal page Scenario: I can link to an internal page
When I select "awesome" in the "Content" HTML field When I select "awesome" in the "Content" HTML field
And I press the "Insert link" HTML field button And I press the "Insert link" HTML field button
And I click "Page on this site" in the ".mce-menu" element And I click "Page on this site" in the ".tox-collection__group" element
Then I should see an "form#Form_editorInternalLink" element Then I should see an "form#Form_editorInternalLink" element
When I click "(Search or choose Page)" in the ".Select-multi-value-wrapper" element When I select "About Us" in the "#Form_editorInternalLink_PageID_Holder" tree dropdown
And I click "About Us" in the ".treedropdownfield__menu" element
And I fill in "my desc" for "Link description" And I fill in "my desc" for "Link description"
And I press the "Insert" button And I press the "Insert link" button
Then the "Content" HTML field should contain "<a title="my desc" href="[sitetree_link,id=2]">awesome</a>" Then the "Content" HTML field should contain "<a title="my desc" href="[sitetree_link,id=2]">awesome</a>"
# Required to avoid "unsaved changes" browser dialog # Required to avoid "unsaved changes" browser dialog
Then I press the "Save" button Then I press the "Save" button
@ -31,12 +30,11 @@ So that I can link to a external website or a page on my site
Given I fill in the "Content" HTML field with "<p><img src='file1.jpg'></p>" Given I fill in the "Content" HTML field with "<p><img src='file1.jpg'></p>"
When I select the image "file1.jpg" in the "Content" HTML field When I select the image "file1.jpg" in the "Content" HTML field
And I press the "Insert link" HTML field button And I press the "Insert link" HTML field button
And I click "Page on this site" in the ".mce-menu" element And I click "Page on this site" in the ".tox-collection__group" element
Then I should see an "form#Form_editorInternalLink" element Then I should see an "form#Form_editorInternalLink" element
And I should not see "Link text" And I should not see "Link text"
When I click "(Search or choose Page)" in the ".Select-multi-value-wrapper" element When I select "About Us" in the "#Form_editorInternalLink_PageID_Holder" tree dropdown
And I click "About Us" in the ".treedropdownfield__menu" element And I press the "Insert link" button
And I press the "Insert" button
Then the "Content" HTML field should contain "<a href="[sitetree_link,id=2]"><img src="file1.jpg"></a>" Then the "Content" HTML field should contain "<a href="[sitetree_link,id=2]"><img src="file1.jpg"></a>"
# Required to avoid "unsaved changed" browser dialog # Required to avoid "unsaved changed" browser dialog
And I press the "Save" button And I press the "Save" button
@ -45,15 +43,14 @@ So that I can link to a external website or a page on my site
Given I fill in the "Content" HTML field with "<a title='my desc' href='[sitetree_link,id=2]'>awesome</a>" Given I fill in the "Content" HTML field with "<a title='my desc' href='[sitetree_link,id=2]'>awesome</a>"
And I select "awesome" in the "Content" HTML field And I select "awesome" in the "Content" HTML field
And I press the "Insert link" HTML field button And I press the "Insert link" HTML field button
And I click "Page on this site" in the ".mce-menu" element And I click "Page on this site" in the ".tox-collection__group" element
And I should see an "form#Form_editorInternalLink" element And I should see an "form#Form_editorInternalLink" element
Then I should see "About Us" in the ".Select-value" element Then I should see "About Us" in the "#Form_editorInternalLink_PageID_Holder .treedropdownfield__value-container" element
And the "Link description" field should contain "my desc" And the "Link description" field should contain "my desc"
# This doesn't seem to suffer from that issue # This doesn't seem to suffer from that issue
When I click "About Us" in the ".Select-value" element When I select "Home" in the "#Form_editorInternalLink_PageID_Holder" tree dropdown
And I click "Home" in the ".treedropdownfield__menu" element
And I fill in "my new desc" for "Link description" And I fill in "my new desc" for "Link description"
And I press the "Insert" button And I press the "Insert link" button
Then the "Content" HTML field should contain "<a title="my new desc" href="[sitetree_link,id=1]">awesome</a>" Then the "Content" HTML field should contain "<a title="my new desc" href="[sitetree_link,id=1]">awesome</a>"
# Required to avoid "unsaved changes" browser dialog # Required to avoid "unsaved changes" browser dialog
Then I press the "Save" button Then I press the "Save" button
@ -61,11 +58,11 @@ So that I can link to a external website or a page on my site
Scenario: I can link to an external URL Scenario: I can link to an external URL
Given I select "awesome" in the "Content" HTML field Given I select "awesome" in the "Content" HTML field
And I press the "Insert link" HTML field button And I press the "Insert link" HTML field button
When I click "Link to external URL" in the ".mce-menu" element When I click "Link to external URL" in the ".tox-collection__group" element
And I should see an "form#Form_ModalsEditorExternalLink" element And I should see an "form#Form_ModalsEditorExternalLink" element
When I fill in "http://silverstripe.org" for "URL" When I fill in "http://silverstripe.org" for "URL"
And I check "Open in new window/tab" And I check "Open in new window/tab"
And I press the "Insert" button And I press the "Insert link" button
Then the "Content" HTML field should contain "<a rel="noopener" href="http://silverstripe.org" target="_blank">awesome</a>" Then the "Content" HTML field should contain "<a rel="noopener" href="http://silverstripe.org" target="_blank">awesome</a>"
# Required to avoid "unsaved changes" browser dialog # Required to avoid "unsaved changes" browser dialog
Then I press the "Save" button Then I press the "Save" button
@ -74,11 +71,11 @@ So that I can link to a external website or a page on my site
Given I fill in the "Content" HTML field with "<p><img src='file1.jpg'></p>" Given I fill in the "Content" HTML field with "<p><img src='file1.jpg'></p>"
When I select the image "file1.jpg" in the "Content" HTML field When I select the image "file1.jpg" in the "Content" HTML field
And I press the "Insert link" HTML field button And I press the "Insert link" HTML field button
When I click "Link to external URL" in the ".mce-menu" element When I click "Link to external URL" in the ".tox-collection__group" element
And I should see an "form#Form_ModalsEditorExternalLink" element And I should see an "form#Form_ModalsEditorExternalLink" element
And I should not see "Link text" And I should not see "Link text"
When I fill in "http://silverstripe.org" for "URL" When I fill in "http://silverstripe.org" for "URL"
And I press the "Insert" button And I press the "Insert link" button
Then the "Content" HTML field should contain "<a href="http://silverstripe.org"><img src="file1.jpg"></a>" Then the "Content" HTML field should contain "<a href="http://silverstripe.org"><img src="file1.jpg"></a>"
# Required to avoid "unsaved changed" browser dialog # Required to avoid "unsaved changed" browser dialog
And I press the "Save" button And I press the "Save" button
@ -87,12 +84,12 @@ So that I can link to a external website or a page on my site
Given I fill in the "Content" HTML field with "<p>My <a href='http://silverstripe.org'>awesome</a> content" Given I fill in the "Content" HTML field with "<p>My <a href='http://silverstripe.org'>awesome</a> content"
And I select "awesome" in the "Content" HTML field And I select "awesome" in the "Content" HTML field
When I press the "Insert link" HTML field button When I press the "Insert link" HTML field button
And I click "Link to external URL" in the ".mce-menu" element And I click "Link to external URL" in the ".tox-collection__group" element
And I should see an "form#Form_ModalsEditorExternalLink" element And I should see an "form#Form_ModalsEditorExternalLink" element
Then the "URL" field should contain "http://silverstripe.org" Then the "URL" field should contain "http://silverstripe.org"
# This doesn't seem to suffer from that issue # This doesn't seem to suffer from that issue
When I fill in "http://google.com" for "URL" When I fill in "http://google.com" for "URL"
And I press the "Insert" button And I press the "Insert link" button
Then the "Content" HTML field should contain "<a href="http://google.com">awesome</a>" Then the "Content" HTML field should contain "<a href="http://google.com">awesome</a>"
# Required to avoid "unsaved changes" browser dialog # Required to avoid "unsaved changes" browser dialog
Then I press the "Save" button Then I press the "Save" button

View File

@ -17,16 +17,14 @@ So that I can link to a external website or a page on my site
Scenario: I can link to an anchor in an internal page Scenario: I can link to an anchor in an internal page
When I select "awesome" in the "Content" HTML field When I select "awesome" in the "Content" HTML field
And I press the "Insert link" HTML field button And I press the "Insert link" HTML field button
And I click "Anchor on a page" in the ".mce-menu" element And I click "Anchor on a page" in the ".tox-collection__group" element
Then I should see an "form#Form_editorAnchorLink" element Then I should see an "form#Form_editorAnchorLink" element
And I should see "About Us" in the "#Form_editorAnchorLink_PageID_Holder .Select-multi-value-wrapper" element And I should see "About Us" in the "#Form_editorAnchorLink_PageID_Holder .treedropdownfield__value-container" element
When I click "About Us" in the "#Form_editorAnchorLink_PageID_Holder .Select-multi-value-wrapper" element When I select "Details" in the "#Form_editorAnchorLink_PageID_Holder" tree dropdown
And I click "Details" in the "#Form_editorAnchorLink_PageID_Holder .Select-menu-outer" element And I select "youranchor" in the "#Form_editorAnchorLink_Anchor_Holder" anchor dropdown
And I click "Select or enter anchor" in the "#Form_editorAnchorLink_Anchor_Holder .Select-multi-value-wrapper" element Then I should see "youranchor" in the "#Form_editorAnchorLink_Anchor_Holder .anchorselectorfield__value-container" element
And I click "youranchor" in the "#Form_editorAnchorLink_Anchor_Holder .Select-menu-outer" element
Then I should see "youranchor" in the "#Form_editorAnchorLink_Anchor_Holder .Select-value" element
When I fill in "my desc" for "Link description" When I fill in "my desc" for "Link description"
And I press the "Insert" button And I press the "Insert link" button
Then the "Content" HTML field should contain "<a title="my desc" href="[sitetree_link,id=3]#youranchor">awesome</a>" Then the "Content" HTML field should contain "<a title="my desc" href="[sitetree_link,id=3]#youranchor">awesome</a>"
# Required to avoid "unsaved changes" browser dialog # Required to avoid "unsaved changes" browser dialog
Then I press the "Save" button Then I press the "Save" button
@ -35,16 +33,13 @@ So that I can link to a external website or a page on my site
Given I fill in the "Content" HTML field with "<p><img src='file1.jpg'></p>" Given I fill in the "Content" HTML field with "<p><img src='file1.jpg'></p>"
When I select the image "file1.jpg" in the "Content" HTML field When I select the image "file1.jpg" in the "Content" HTML field
And I press the "Insert link" HTML field button And I press the "Insert link" HTML field button
And I click "Anchor on a page" in the ".mce-menu" element And I click "Anchor on a page" in the ".tox-collection__group" element
Then I should see an "form#Form_editorAnchorLink" element Then I should see an "form#Form_editorAnchorLink" element
And I should not see "Link text" And I should not see "Link text"
And I should see "About Us" in the "#Form_editorAnchorLink_PageID_Holder .Select-multi-value-wrapper" element And I should see "About Us" in the "#Form_editorAnchorLink_PageID_Holder .treedropdownfield__value-container" element
When I click "About Us" in the "#Form_editorAnchorLink_PageID_Holder .Select-multi-value-wrapper" element When I select "Details" in the "#Form_editorAnchorLink_PageID_Holder" tree dropdown
And I click "Details" in the "#Form_editorAnchorLink_PageID_Holder .Select-menu-outer" element And I select "youranchor" in the "#Form_editorAnchorLink_Anchor_Holder" anchor dropdown
And I click "Select or enter anchor" in the "#Form_editorAnchorLink_Anchor_Holder .Select-multi-value-wrapper" element And I press the "Insert link" button
And I click "youranchor" in the "#Form_editorAnchorLink_Anchor_Holder .Select-menu-outer" element
Then I should see "youranchor" in the "#Form_editorAnchorLink_Anchor_Holder .Select-value" element
And I press the "Insert" button
Then the "Content" HTML field should contain "<a href="[sitetree_link,id=3]#youranchor"><img src="file1.jpg"></a>" Then the "Content" HTML field should contain "<a href="[sitetree_link,id=3]#youranchor"><img src="file1.jpg"></a>"
# Required to avoid "unsaved changed" browser dialog # Required to avoid "unsaved changed" browser dialog
And I press the "Save" button And I press the "Save" button
@ -52,15 +47,13 @@ So that I can link to a external website or a page on my site
Scenario: I can link to an anchor from a dataobject on the current page Scenario: I can link to an anchor from a dataobject on the current page
When I select "awesome" in the "Content" HTML field When I select "awesome" in the "Content" HTML field
And I press the "Insert link" HTML field button And I press the "Insert link" HTML field button
And I click "Anchor on a page" in the ".mce-menu" element And I click "Anchor on a page" in the ".tox-collection__group" element
Then I should see an "form#Form_editorAnchorLink" element Then I should see an "form#Form_editorAnchorLink" element
And I should see "About Us" in the "#Form_editorAnchorLink_PageID_Holder .Select-multi-value-wrapper" element And I should see "About Us" in the "#Form_editorAnchorLink_PageID_Holder .treedropdownfield__value-container" element
When I click "Select or enter anchor" in the "#Form_editorAnchorLink_Anchor_Holder .Select-multi-value-wrapper" element When I select "dataobject-anchor" in the "#Form_editorAnchorLink_Anchor_Holder" anchor dropdown
Then I should see "dataobject-anchor" in the "#Form_editorAnchorLink_Anchor_Holder .Select-menu-outer" element Then I should see "dataobject-anchor" in the "#Form_editorAnchorLink_Anchor_Holder .anchorselectorfield__value-container" element
When I click "dataobject-anchor" in the "#Form_editorAnchorLink_Anchor_Holder .Select-menu-outer" element
Then I should see "dataobject-anchor" in the "#Form_editorAnchorLink_Anchor_Holder .Select-value" element
When I fill in "my desc" for "Link description" When I fill in "my desc" for "Link description"
And I press the "Insert" button And I press the "Insert link" button
Then the "Content" HTML field should contain "<a title="my desc" href="[sitetree_link,id=2]#dataobject-anchor">awesome</a>" Then the "Content" HTML field should contain "<a title="my desc" href="[sitetree_link,id=2]#dataobject-anchor">awesome</a>"
# Required to avoid "unsaved changes" browser dialog # Required to avoid "unsaved changes" browser dialog
Then I press the "Save" button Then I press the "Save" button
@ -69,16 +62,15 @@ So that I can link to a external website or a page on my site
Given I fill in the "Content" HTML field with "<p>My awesome content</p><p><a id='unsaved-anchor'></a>unsaved content</p>" Given I fill in the "Content" HTML field with "<p>My awesome content</p><p><a id='unsaved-anchor'></a>unsaved content</p>"
When I select "awesome" in the "Content" HTML field When I select "awesome" in the "Content" HTML field
And I press the "Insert link" HTML field button And I press the "Insert link" HTML field button
And I click "Anchor on a page" in the ".mce-menu" element And I click "Anchor on a page" in the ".tox-collection__group" element
Then I should see an "form#Form_editorAnchorLink" element Then I should see an "form#Form_editorAnchorLink" element
And I should see "About Us" in the "#Form_editorAnchorLink_PageID_Holder .Select-multi-value-wrapper" element And I should see "About Us" in the "#Form_editorAnchorLink_PageID_Holder .treedropdownfield__value-container" element
When I click "Select or enter anchor" in the "#Form_editorAnchorLink_Anchor_Holder .Select-multi-value-wrapper" element When I click on the ".anchorselectorfield__dropdown-indicator" element
Then I should see "unsaved-anchor" in the "#Form_editorAnchorLink_Anchor_Holder .Select-menu-outer" element Then I should see "dataobject-anchor" in the ".anchorselectorfield__menu-list" element
And I should see "dataobject-anchor" in the "#Form_editorAnchorLink_Anchor_Holder .Select-menu-outer" element When I select "unsaved-anchor" in the "#Form_editorAnchorLink_Anchor_Holder" anchor dropdown
When I click "unsaved-anchor" in the "#Form_editorAnchorLink_Anchor_Holder .Select-menu-outer" element Then I should see "unsaved-anchor" in the "#Form_editorAnchorLink_Anchor_Holder .anchorselectorfield__value-container" element
Then I should see "unsaved-anchor" in the "#Form_editorAnchorLink_Anchor_Holder .Select-value" element
When I fill in "my desc" for "Link description" When I fill in "my desc" for "Link description"
And I press the "Insert" button And I press the "Insert link" button
Then the "Content" HTML field should contain "<a title="my desc" href="[sitetree_link,id=2]#unsaved-anchor">awesome</a>" Then the "Content" HTML field should contain "<a title="my desc" href="[sitetree_link,id=2]#unsaved-anchor">awesome</a>"
# Required to avoid "unsaved changes" browser dialog # Required to avoid "unsaved changes" browser dialog
Then I press the "Save" button Then I press the "Save" button

View File

@ -19,10 +19,6 @@ Feature: Preview a page
And the preview contains "About Us" And the preview contains "About Us"
Then I set the CMS mode to "Edit mode" Then I set the CMS mode to "Edit mode"
# TODO:
# - Only tests correctly on fresh database
# - We should continue testing against it after we have fixtures ready
@javascript
Scenario: I can see an updated preview when editing content Scenario: I can see an updated preview when editing content
And I go to "/admin/pages" And I go to "/admin/pages"
Then I should see "About Us" in the tree Then I should see "About Us" in the tree

View File

@ -8,6 +8,7 @@ use Behat\Mink\Element\NodeElement;
use PHPUnit\Framework\Assert; use PHPUnit\Framework\Assert;
use SilverStripe\BehatExtension\Context\BasicContext; use SilverStripe\BehatExtension\Context\BasicContext;
use SilverStripe\BehatExtension\Context\FixtureContext as BehatFixtureContext; use SilverStripe\BehatExtension\Context\FixtureContext as BehatFixtureContext;
use SilverStripe\BehatExtension\Utility\StepHelper;
use SilverStripe\CMS\Model\RedirectorPage; use SilverStripe\CMS\Model\RedirectorPage;
use SilverStripe\CMS\Model\SiteTree; use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Core\ClassInfo; use SilverStripe\Core\ClassInfo;
@ -20,6 +21,8 @@ use SilverStripe\Versioned\Versioned;
*/ */
class FixtureContext extends BehatFixtureContext class FixtureContext extends BehatFixtureContext
{ {
use StepHelper;
/** /**
* @var BasicContext * @var BasicContext
*/ */
@ -118,22 +121,6 @@ class FixtureContext extends BehatFixtureContext
Assert::assertEquals($value, $radioButton->getAttribute($attribute)); Assert::assertEquals($value, $radioButton->getAttribute($attribute));
} }
/**
* Assumes you've just opened the Insert link menu, e.g.
* I click on the "div[aria-label='Insert link [Ctrl+K]'] button" element
*
* @When /^I select "(.+?)" from the TinyMCE menu with javascript$/
* @param string $label
*/
public function iSelectFromTheTinyMceMenu($label)
{
// :visible and :contains are jQuery css selectors
$js = <<<JS
jQuery(".mce-menu-item:visible span:contains('{$label}')").click();
JS;
$this->getMainContext()->getSession()->executeScript($js);
}
/** /**
* e.g. --PageOne,--PageTwo,---PageTwoChild,--PageThree * e.g. --PageOne,--PageTwo,---PageTwoChild,--PageThree
* *
@ -155,4 +142,33 @@ JS;
$actual = $this->getMainContext()->getSession()->evaluateScript($js); $actual = $this->getMainContext()->getSession()->evaluateScript($js);
Assert::assertEquals($expected, $actual); Assert::assertEquals($expected, $actual);
} }
/**
* Select a value in the anchor selector field
*
* @When /^I select "([^"]*)" in the "([^"]*)" anchor dropdown$/
*/
public function iSelectValueInAnchorDropdown($text, $selector)
{
$page = $this->getMainContext()->getSession()->getPage();
/** @var NodeElement $parentElement */
$parentElement = null;
$this->retryThrowable(function () use (&$parentElement, &$page, $selector) {
$parentElement = $page->find('css', $selector);
Assert::assertNotNull($parentElement, sprintf('"%s" element not found', $selector));
$page = $this->getMainContext()->getSession()->getPage();
});
$this->retryThrowable(function () use ($parentElement, $selector) {
$dropdown = $parentElement->find('css', '.anchorselectorfield__dropdown-indicator');
Assert::assertNotNull($dropdown, sprintf('Unable to find the dropdown in "%s"', $selector));
$dropdown->click();
});
$this->retryThrowable(function () use ($text, $parentElement, $selector) {
$element = $parentElement->find('xpath', sprintf('//*[count(*)=0 and .="%s"]', $text));
Assert::assertNotNull($element, sprintf('"%s" not found in "%s"', $text, $selector));
$element->click();
});
}
} }

View File

@ -16,7 +16,6 @@ use SilverStripe\Versioned\Versioned;
*/ */
class CMSBatchActionsTest extends SapphireTest class CMSBatchActionsTest extends SapphireTest
{ {
protected static $fixture_file = 'CMSBatchActionsTest.yml'; protected static $fixture_file = 'CMSBatchActionsTest.yml';
protected function setUp(): void protected function setUp(): void
@ -142,10 +141,10 @@ class CMSBatchActionsTest extends SapphireTest
$this->assertEquals($archivedID, $list->first()->ParentID); $this->assertEquals($archivedID, $list->first()->ParentID);
// Run restore // Run restore
$result = json_decode($action->run($list) ?? '', true); $result = json_decode($action->run($list)->getBody(), true);
$this->assertEquals( $this->assertEquals(
[ [
$archivedxID => $archivedxID $archivedxID => $archivedxID,
], ],
$result['success'] $result['success']
); );
@ -162,13 +161,13 @@ class CMSBatchActionsTest extends SapphireTest
$this->assertEquals(0, $list->last()->ParentID); // archived (parent) $this->assertEquals(0, $list->last()->ParentID); // archived (parent)
// Run restore // Run restore
$result = json_decode($action->run($list) ?? '', true); $result = json_decode($action->run($list)->getBody(), true);
$this->assertEquals( $this->assertEquals(
[ [
// Order of archived is opposite to order items are passed in, as // Order of archived is opposite to order items are passed in, as
// these are sorted by level first // these are sorted by level first
$archivedID => $archivedID, $archivedID => $archivedID,
$archivedyID => $archivedyID $archivedyID => $archivedyID,
], ],
$result['success'] $result['success']
); );

View File

@ -2,7 +2,6 @@
namespace SilverStripe\CMS\Tests\Controllers; namespace SilverStripe\CMS\Tests\Controllers;
use Page;
use Psr\SimpleCache\CacheInterface; use Psr\SimpleCache\CacheInterface;
use SilverStripe\Admin\CMSBatchActionHandler; use SilverStripe\Admin\CMSBatchActionHandler;
use SilverStripe\CMS\Controllers\CMSMain; use SilverStripe\CMS\Controllers\CMSMain;
@ -25,7 +24,6 @@ use SilverStripe\Security\Member;
use SilverStripe\Security\Security; use SilverStripe\Security\Security;
use SilverStripe\SiteConfig\SiteConfig; use SilverStripe\SiteConfig\SiteConfig;
use SilverStripe\Versioned\Versioned; use SilverStripe\Versioned\Versioned;
use SilverStripe\Dev\Deprecation;
class CMSMainTest extends FunctionalTest class CMSMainTest extends FunctionalTest
{ {
@ -119,40 +117,6 @@ class CMSMainTest extends FunctionalTest
); );
} }
/**
* @todo Test the results of a publication better
*/
public function testPublish()
{
if (Deprecation::isEnabled()) {
$this->markTestSkipped('Test calls deprecated code');
}
$page1 = $this->objFromFixture(Page::class, "page1");
$page2 = $this->objFromFixture(Page::class, "page2");
$this->logInAs('admin');
$response = $this->get('admin/pages/publishall?confirm=1');
$this->assertStringContainsString(
'Done: Published 30 pages',
$response->getBody()
);
// Some modules (e.g., cmsworkflow) will remove this action
$actions = CMSBatchActionHandler::config()->batch_actions;
if (isset($actions['publish'])) {
$response = $this->get('admin/pages/batchactions/publish?ajax=1&csvIDs=' . implode(',', [$page1->ID, $page2->ID]));
$responseData = json_decode($response->getBody() ?? '', true);
$this->assertArrayHasKey($page1->ID, $responseData['modified']);
$this->assertArrayHasKey($page2->ID, $responseData['modified']);
}
// Get the latest version of the redirector page
$pageID = $this->idFromFixture(RedirectorPage::class, 'page5');
$latestID = DB::prepared_query('select max("Version") from "RedirectorPage_Versions" where "RecordID" = ?', [$pageID])->value();
$dsCount = DB::prepared_query('select count("Version") from "RedirectorPage_Versions" where "RecordID" = ? and "Version"= ?', [$pageID, $latestID])->value();
$this->assertEquals(1, $dsCount, "Published page has no duplicate version records: it has " . $dsCount . " for version " . $latestID);
}
/** /**
* Test that getCMSFields works on each page type. * Test that getCMSFields works on each page type.
* Mostly, this is just checking that the method doesn't return an error * Mostly, this is just checking that the method doesn't return an error
@ -185,8 +149,8 @@ class CMSMainTest extends FunctionalTest
$this->logInWithPermission('ADMIN'); $this->logInWithPermission('ADMIN');
Config::modify()->set(SiteTree::class, 'enforce_strict_hierarchy', true); Config::modify()->set(SiteTree::class, 'enforce_strict_hierarchy', true);
$parentPage = $this->objFromFixture(Page::class, 'page3'); $parentPage = $this->objFromFixture(SiteTree::class, 'page3');
$childPage = $this->objFromFixture(Page::class, 'page1'); $childPage = $this->objFromFixture(SiteTree::class, 'page1');
$parentPage->doUnpublish(); $parentPage->doUnpublish();
$childPage->doUnpublish(); $childPage->doUnpublish();
@ -208,7 +172,7 @@ class CMSMainTest extends FunctionalTest
$this->logInWithPermission('ADMIN'); $this->logInWithPermission('ADMIN');
// Set up a page that is delete from live // Set up a page that is delete from live
$page = $this->objFromFixture(Page::class, 'page1'); $page = $this->objFromFixture(SiteTree::class, 'page1');
$pageID = $page->ID; $pageID = $page->ID;
$page->publishRecursive(); $page->publishRecursive();
$page->delete(); $page->delete();
@ -216,7 +180,7 @@ class CMSMainTest extends FunctionalTest
$response = $this->get('admin/pages/edit/show/' . $pageID); $response = $this->get('admin/pages/edit/show/' . $pageID);
$livePage = Versioned::get_one_by_stage(SiteTree::class, Versioned::LIVE, [ $livePage = Versioned::get_one_by_stage(SiteTree::class, Versioned::LIVE, [
'"SiteTree"."ID"' => $pageID '"SiteTree"."ID"' => $pageID,
]); ]);
$this->assertInstanceOf(SiteTree::class, $livePage); $this->assertInstanceOf(SiteTree::class, $livePage);
$this->assertTrue($livePage->canDelete()); $this->assertTrue($livePage->canDelete());
@ -233,7 +197,7 @@ class CMSMainTest extends FunctionalTest
$this->logInWithPermission('ADMIN'); $this->logInWithPermission('ADMIN');
// Set up a page that is delete from live // Set up a page that is delete from live
$page1 = $this->objFromFixture(Page::class, 'page1'); $page1 = $this->objFromFixture(SiteTree::class, 'page1');
$page1ID = $page1->ID; $page1ID = $page1->ID;
$page1->publishRecursive(); $page1->publishRecursive();
$page1->delete(); $page1->delete();
@ -246,18 +210,18 @@ class CMSMainTest extends FunctionalTest
$this->assertNull($cmsMain->getRecord('asdf')); $this->assertNull($cmsMain->getRecord('asdf'));
// Pages that are on draft and aren't on draft should both work // Pages that are on draft and aren't on draft should both work
$this->assertInstanceOf('Page', $cmsMain->getRecord($page1ID)); $this->assertInstanceOf(SiteTree::class, $cmsMain->getRecord($page1ID));
$this->assertInstanceOf('Page', $cmsMain->getRecord($this->idFromFixture('Page', 'page2'))); $this->assertInstanceOf(SiteTree::class, $cmsMain->getRecord($this->idFromFixture(SiteTree::class, 'page2')));
// This functionality isn't actually used any more. // This functionality isn't actually used any more.
$newPage = $cmsMain->getRecord('new-Page-5'); $newPage = $cmsMain->getRecord('new-Page-5');
$this->assertInstanceOf('Page', $newPage); $this->assertInstanceOf(SiteTree::class, $newPage);
$this->assertEquals('5', $newPage->ParentID); $this->assertEquals('5', $newPage->ParentID);
} }
public function testDeletedPagesSiteTreeFilter() public function testDeletedPagesSiteTreeFilter()
{ {
$id = $this->idFromFixture('Page', 'page3'); $id = $this->idFromFixture(SiteTree::class, 'page3');
$this->logInWithPermission('ADMIN'); $this->logInWithPermission('ADMIN');
$result = $this->get('admin/pages/getsubtree?filter=CMSSiteTreeFilter_DeletedPages&ajax=1&ID=' . $id); $result = $this->get('admin/pages/getsubtree?filter=CMSSiteTreeFilter_DeletedPages&ajax=1&ID=' . $id);
$this->assertEquals(200, $result->getStatusCode()); $this->assertEquals(200, $result->getStatusCode());
@ -278,7 +242,7 @@ class CMSMainTest extends FunctionalTest
'admin/pages/add/AddForm', 'admin/pages/add/AddForm',
[ [
'ParentID' => '0', 'ParentID' => '0',
'PageType' => 'Page', 'PageType' => RedirectorPage::class,
'Locale' => 'en_US', 'Locale' => 'en_US',
'action_doAdd' => 1, 'action_doAdd' => 1,
'ajax' => 1, 'ajax' => 1,
@ -298,7 +262,7 @@ class CMSMainTest extends FunctionalTest
'admin/pages/add/AddForm', 'admin/pages/add/AddForm',
[ [
'ParentID' => '0', 'ParentID' => '0',
'PageType' => 'Page', 'PageType' => RedirectorPage::class,
'Locale' => 'en_US', 'Locale' => 'en_US',
'action_doAdd' => 1, 'action_doAdd' => 1,
'ajax' => 1, 'ajax' => 1,
@ -332,7 +296,7 @@ class CMSMainTest extends FunctionalTest
'PageType' => CMSMainTest_ClassA::class, 'PageType' => CMSMainTest_ClassA::class,
'Locale' => 'en_US', 'Locale' => 'en_US',
'action_doAdd' => 1, 'action_doAdd' => 1,
'ajax' => 1 'ajax' => 1,
], ],
[ [
'X-Pjax' => 'CurrentForm,Breadcrumbs', 'X-Pjax' => 'CurrentForm,Breadcrumbs',
@ -352,7 +316,7 @@ class CMSMainTest extends FunctionalTest
'PageType' => CMSMainTest_ClassB::class, 'PageType' => CMSMainTest_ClassB::class,
'Locale' => 'en_US', 'Locale' => 'en_US',
'action_doAdd' => 1, 'action_doAdd' => 1,
'ajax' => 1 'ajax' => 1,
], ],
[ [
'X-Pjax' => 'CurrentForm,Breadcrumbs', 'X-Pjax' => 'CurrentForm,Breadcrumbs',
@ -375,10 +339,10 @@ class CMSMainTest extends FunctionalTest
'admin/pages/add/AddForm', 'admin/pages/add/AddForm',
[ [
'ParentID' => $newPageId, 'ParentID' => $newPageId,
'PageType' => 'Page', 'PageType' => RedirectorPage::class,
'Locale' => 'en_US', 'Locale' => 'en_US',
'action_doAdd' => 1, 'action_doAdd' => 1,
'ajax' => 1 'ajax' => 1,
], ],
[ [
'X-Pjax' => 'CurrentForm,Breadcrumbs', 'X-Pjax' => 'CurrentForm,Breadcrumbs',
@ -393,8 +357,8 @@ class CMSMainTest extends FunctionalTest
public function testBreadcrumbs() public function testBreadcrumbs()
{ {
$page3 = $this->objFromFixture(Page::class, 'page3'); $page3 = $this->objFromFixture(SiteTree::class, 'page3');
$page31 = $this->objFromFixture(Page::class, 'page31'); $page31 = $this->objFromFixture(SiteTree::class, 'page31');
$this->logInAs('admin'); $this->logInAs('admin');
$response = $this->get('admin/pages/edit/show/' . $page31->ID); $response = $this->get('admin/pages/edit/show/' . $page31->ID);
@ -420,7 +384,7 @@ class CMSMainTest extends FunctionalTest
$this->assertEquals($page->Title, 'New Page'); $this->assertEquals($page->Title, 'New Page');
$this->assertNotEquals($page->Sort, 0); $this->assertNotEquals($page->Sort, 0);
$this->assertInstanceOf('Page', $page); $this->assertInstanceOf(SiteTree::class, $page);
// Test failure // Test failure
try { try {
@ -449,10 +413,10 @@ class CMSMainTest extends FunctionalTest
); );
// Change state of tree // Change state of tree
$page1 = $this->objFromFixture(Page::class, 'page1'); $page1 = $this->objFromFixture(SiteTree::class, 'page1');
$page3 = $this->objFromFixture(Page::class, 'page3'); $page3 = $this->objFromFixture(SiteTree::class, 'page3');
$page11 = $this->objFromFixture(Page::class, 'page11'); $page11 = $this->objFromFixture(SiteTree::class, 'page11');
$page12 = $this->objFromFixture(Page::class, 'page12'); $page12 = $this->objFromFixture(SiteTree::class, 'page12');
// Deleted // Deleted
$page1->doUnpublish(); $page1->doUnpublish();
$page1->delete(); $page1->delete();
@ -472,7 +436,7 @@ class CMSMainTest extends FunctionalTest
// Test deleted page filter // Test deleted page filter
$params = [ $params = [
'FilterClass' => 'SilverStripe\\CMS\\Controllers\\CMSSiteTreeFilter_StatusDeletedPages' 'FilterClass' => 'SilverStripe\\CMS\\Controllers\\CMSSiteTreeFilter_StatusDeletedPages',
]; ];
$pages = $controller->getList($params); $pages = $controller->getList($params);
$this->assertEquals(1, $pages->count()); $this->assertEquals(1, $pages->count());
@ -483,7 +447,7 @@ class CMSMainTest extends FunctionalTest
// Test live, but not on draft filter // Test live, but not on draft filter
$params = [ $params = [
'FilterClass' => 'SilverStripe\\CMS\\Controllers\\CMSSiteTreeFilter_StatusRemovedFromDraftPages' 'FilterClass' => 'SilverStripe\\CMS\\Controllers\\CMSSiteTreeFilter_StatusRemovedFromDraftPages',
]; ];
$pages = $controller->getList($params); $pages = $controller->getList($params);
$this->assertEquals(1, $pages->count()); $this->assertEquals(1, $pages->count());
@ -494,7 +458,7 @@ class CMSMainTest extends FunctionalTest
// Test live pages filter // Test live pages filter
$params = [ $params = [
'FilterClass' => 'SilverStripe\\CMS\\Controllers\\CMSSiteTreeFilter_PublishedPages' 'FilterClass' => 'SilverStripe\\CMS\\Controllers\\CMSSiteTreeFilter_PublishedPages',
]; ];
$pages = $controller->getList($params); $pages = $controller->getList($params);
$this->assertEquals(2, $pages->count()); $this->assertEquals(2, $pages->count());
@ -529,7 +493,7 @@ class CMSMainTest extends FunctionalTest
$this->loginWithPermission('ADMIN'); $this->loginWithPermission('ADMIN');
// Get a associated with a fixture page. // Get a associated with a fixture page.
$page = $this->objFromFixture(Page::class, 'page1'); $page = $this->objFromFixture(SiteTree::class, 'page1');
$controller = CMSMain::create(); $controller = CMSMain::create();
$controller->setRequest(Controller::curr()->getRequest()); $controller->setRequest(Controller::curr()->getRequest());
$form = $controller->getEditForm($page->ID); $form = $controller->getEditForm($page->ID);
@ -557,7 +521,7 @@ class CMSMainTest extends FunctionalTest
$form->loadDataFrom(['ClassName' => CMSMainTest_ClassB::class]); $form->loadDataFrom(['ClassName' => CMSMainTest_ClassB::class]);
$result = $cms->save([ $result = $cms->save([
'ID' => $page->ID, 'ID' => $page->ID,
'ClassName' => CMSMainTest_ClassB::class 'ClassName' => CMSMainTest_ClassB::class,
], $form); ], $form);
$this->assertEquals(200, $result->getStatusCode()); $this->assertEquals(200, $result->getStatusCode());

View File

@ -1,4 +1,4 @@
Page: SilverStripe\CMS\Model\SiteTree:
page1: page1:
Title: Page 1 Title: Page 1
Sort: 1 Sort: 1
@ -10,11 +10,11 @@ Page:
Sort: 3 Sort: 3
page31: page31:
Title: Page 3.1 Title: Page 3.1
Parent: =>Page.page3 Parent: =>SilverStripe\CMS\Model\SiteTree.page3
Sort: 1 Sort: 1
page32: page32:
Title: Page 3.2 Title: Page 3.2
Parent: =>Page.page3 Parent: =>SilverStripe\CMS\Model\SiteTree.page3
Sort: 2 Sort: 2
page4: page4:
Title: Page 4 Title: Page 4

View File

@ -2,11 +2,11 @@
namespace SilverStripe\CMS\Tests\Controllers; namespace SilverStripe\CMS\Tests\Controllers;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use SilverStripe\ORM\ValidationException; use SilverStripe\ORM\ValidationException;
use Page;
class CMSMainTest_ClassA extends Page implements TestOnly class CMSMainTest_ClassA extends SiteTree implements TestOnly
{ {
private static $table_name = 'CMSMainTest_ClassA'; private static $table_name = 'CMSMainTest_ClassA';

View File

@ -2,11 +2,11 @@
namespace SilverStripe\CMS\Tests\Controllers; namespace SilverStripe\CMS\Tests\Controllers;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use SilverStripe\ORM\ValidationException; use SilverStripe\ORM\ValidationException;
use Page;
class CMSMainTest_ClassB extends Page implements TestOnly class CMSMainTest_ClassB extends SiteTree implements TestOnly
{ {
private static $table_name = 'CMSMainTest_ClassB'; private static $table_name = 'CMSMainTest_ClassB';

View File

@ -2,11 +2,10 @@
namespace SilverStripe\CMS\Tests\Controllers; namespace SilverStripe\CMS\Tests\Controllers;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use SilverStripe\ORM\HiddenClass; use SilverStripe\ORM\HiddenClass;
use Page;
class CMSMainTest_HiddenClass extends Page implements TestOnly, HiddenClass class CMSMainTest_HiddenClass extends SiteTree implements TestOnly, HiddenClass
{ {
} }

View File

@ -2,10 +2,10 @@
namespace SilverStripe\CMS\Tests\Controllers; namespace SilverStripe\CMS\Tests\Controllers;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use Page;
class CMSMainTest_NotRoot extends Page implements TestOnly class CMSMainTest_NotRoot extends SiteTree implements TestOnly
{ {
private static $table_name = 'CMSMainTest_NotRoot'; private static $table_name = 'CMSMainTest_NotRoot';

View File

@ -1,219 +0,0 @@
<?php
namespace SilverStripe\CMS\Tests\Controllers;
use Page;
use SilverStripe\CMS\Controllers\CMSPageHistoryController;
use SilverStripe\CMS\Tests\Controllers\CMSPageHistoryControllerTest\HistoryController;
use SilverStripe\Control\Controller;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\Dev\FunctionalTest;
use SilverStripe\Forms\FieldGroup;
use SilverStripe\Forms\FieldList;
use SilverStripe\Forms\HiddenField;
use SilverStripe\Forms\HTMLReadonlyField;
use SilverStripe\Dev\Deprecation;
use SilverStripe\Forms\TextField;
class CMSPageHistoryControllerTest extends FunctionalTest
{
protected static $fixture_file = 'CMSPageHistoryControllerTest.yml';
protected $versionUnpublishedCheck;
protected $versionPublishCheck;
protected $versionUnpublishedCheck2;
protected $versionPublishCheck2;
protected $page;
protected static $extra_controllers = [
CMSPageHistoryControllerTest\HistoryController::class,
];
protected function setUp(): void
{
parent::setUp();
Deprecation::withNoReplacement(function () {
Injector::inst()->registerService(
new CMSPageHistoryController(),
CMSPageHistoryController::class
);
});
$this->loginWithPermission('ADMIN');
// creates a series of published, unpublished versions of a page
$this->page = new Page();
$this->page->URLSegment = "test";
$this->page->Content = "new content";
$this->page->write();
$this->versionUnpublishedCheck = $this->page->Version; // v1
$this->page->Content = "some further content";
$this->page->publishSingle();
$this->versionPublishCheck = $this->page->Version; // v2
$this->page->Content = "No, more changes please";
$this->page->Title = "Changing titles too";
$this->page->write();
$this->versionUnpublishedCheck2 = $this->page->Version; // v3
$this->page->Title = "Final Change";
$this->page->publishSingle();
$this->versionPublishCheck2 = $this->page->Version; // v4
}
public function testGetEditForm()
{
if (Deprecation::isEnabled()) {
$this->markTestSkipped('Test calls deprecated code');
}
$controller = new CMSPageHistoryController();
$controller->setRequest(Controller::curr()->getRequest());
// should get the latest version which we cannot rollback to
$form = $controller->getEditForm($this->page->ID);
$this->assertTrue($form->Actions()->dataFieldByName('action_doRollback')->isReadonly());
$this->assertEquals($this->page->ID, $form->Fields()->dataFieldByName('ID')->Value());
$this->assertEquals($this->versionPublishCheck2, $form->Fields()->dataFieldByName('Version')->Value());
$this->assertStringContainsString(
'Currently viewing the latest version',
$form->Fields()->fieldByName('Root.Main.CurrentlyViewingMessage')->getContent()
);
// edit form with a given version
$form = $controller->getEditForm($this->page->ID, null, $this->versionPublishCheck);
$this->assertFalse($form->Actions()->dataFieldByName('action_doRollback')->isReadonly());
$this->assertEquals($this->page->ID, $form->Fields()->dataFieldByName('ID')->Value());
$this->assertEquals($this->versionPublishCheck, $form->Fields()->dataFieldByName('Version')->Value());
$this->assertStringContainsString(
sprintf("Currently viewing version %s.", $this->versionPublishCheck),
$form->Fields()->fieldByName('Root.Main.CurrentlyViewingMessage')->getContent()
);
// check that compare mode updates the message
$form = $controller->getEditForm($this->page->ID, null, $this->versionPublishCheck, $this->versionPublishCheck2);
$this->assertStringContainsString(
sprintf("Comparing versions %s", $this->versionPublishCheck),
$form->Fields()->fieldByName('Root.Main.CurrentlyViewingMessage')->getContent()
);
$this->assertStringContainsString(
sprintf("and %s", $this->versionPublishCheck2),
$form->Fields()->fieldByName('Root.Main.CurrentlyViewingMessage')->getContent()
);
}
/**
* @todo should be less tied to cms theme.
* @todo check highlighting for comparing pages.
*/
public function testVersionsForm()
{
if (Deprecation::isEnabled()) {
$this->markTestSkipped('Test calls deprecated code');
}
$this->get('admin/pages/legacyhistory/show/' . $this->page->ID);
$form = $this->cssParser()->getBySelector('#Form_VersionsForm');
$this->assertEquals(1, count($form ?? []));
// check the page ID is present
$hidden = $form[0]->xpath("fieldset/input[@type='hidden']");
$this->assertThat($hidden, $this->logicalNot($this->isNull()), 'Hidden ID field exists');
$this->assertEquals($this->page->ID, (int) $hidden[0]->attributes()->value);
// ensure that all the versions are present in the table and displayed
$rows = $form[0]->xpath("fieldset/table/tbody/tr");
$this->assertEquals(4, count($rows ?? []));
}
public function testVersionsFormTableContainsInformation()
{
if (Deprecation::isEnabled()) {
$this->markTestSkipped('Test calls deprecated code');
}
$this->get('admin/pages/legacyhistory/show/' . $this->page->ID);
$form = $this->cssParser()->getBySelector('#Form_VersionsForm');
$rows = $form[0]->xpath("fieldset/table/tbody/tr");
$expected = [
['version' => $this->versionPublishCheck2, 'status' => 'published'],
['version' => $this->versionUnpublishedCheck2, 'status' => 'internal'],
['version' => $this->versionPublishCheck, 'status' => 'published'],
['version' => $this->versionUnpublishedCheck, 'status' => 'internal']
];
// goes the reverse order that we created in setUp()
$i = 0;
foreach ($rows as $tr) {
// data-link must be present for the javascript to load new
$this->assertStringContainsString($expected[$i]['status'], (string) $tr->attributes()->class);
$i++;
}
// test highlighting
$this->assertStringContainsString('active', (string) $rows[0]->attributes()->class);
$this->assertThat((string) $rows[1]->attributes()->class, $this->logicalNot($this->stringContains('active')));
}
public function testVersionsFormSelectsUnpublishedCheckbox()
{
if (Deprecation::isEnabled()) {
$this->markTestSkipped('Test calls deprecated code');
}
$this->get('admin/pages/legacyhistory/show/' . $this->page->ID);
$checkbox = $this->cssParser()->getBySelector('#Form_VersionsForm_ShowUnpublished');
$this->assertThat($checkbox[0], $this->logicalNot($this->isNull()));
$checked = $checkbox[0]->attributes()->checked ?: '';
$this->assertThat($checked, $this->logicalNot($this->stringContains('checked')));
// viewing an unpublished
$this->get('admin/pages/legacyhistory/show/' . $this->page->ID . '/' . $this->versionUnpublishedCheck);
$checkbox = $this->cssParser()->getBySelector('#Form_VersionsForm_ShowUnpublished');
$this->assertThat($checkbox[0], $this->logicalNot($this->isNull()));
$this->assertEquals('checked', (string) $checkbox[0]->attributes()->checked);
}
public function testTransformReadonly()
{
if (Deprecation::isEnabled()) {
$this->markTestSkipped('Test calls deprecated code');
}
/** @var CMSPageHistoryController $history */
$history = new CMSPageHistoryController();
$history->setRequest(Controller::curr()->getRequest());
$fieldList = FieldList::create([
FieldGroup::create('group', [
TextField::create('childField', 'child field'),
]),
TextField::create('field', 'field', 'My <del>value</del><ins>change</ins>'),
HiddenField::create('hiddenField', 'hidden field'),
]);
$newList = $history->transformReadonly($fieldList);
$field = $newList->dataFieldByName('field');
$this->assertTrue($field instanceof HTMLReadonlyField);
$this->assertStringContainsString('<ins>', $field->forTemplate());
$groupField = $newList->fieldByName('group');
$this->assertTrue($groupField instanceof FieldGroup);
$childField = $newList->dataFieldByName('childField');
$this->assertTrue($childField instanceof HTMLReadonlyField);
$hiddenField = $newList->dataFieldByName('hiddenField');
$this->assertTrue($hiddenField instanceof HiddenField);
}
}

View File

@ -1,10 +0,0 @@
Page:
page1:
Title: Page 1
Sort: 1
page2:
Title: Page 2
Sort: 2
page3:
Title: Page 3
Sort: 3

View File

@ -1,15 +0,0 @@
<?php
namespace SilverStripe\CMS\Tests\Controllers\CMSPageHistoryControllerTest;
use SilverStripe\CMS\Controllers\CMSPageHistoryController;
use SilverStripe\Dev\TestOnly;
/**
* Used to circumvent potential URL conflicts with the silverstripe/versioned-admin history viewer controller
* when running unit tests on the legacy CMSPageHistoryController.
*/
class HistoryController extends CMSPageHistoryController implements TestOnly
{
private static $url_segment = 'pages/legacyhistory';
}

View File

@ -2,7 +2,6 @@
namespace SilverStripe\CMS\Tests\Controllers; namespace SilverStripe\CMS\Tests\Controllers;
use Page;
use SilverStripe\CMS\Model\SiteTree; use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Versioned\Versioned; use SilverStripe\Versioned\Versioned;
use SilverStripe\CMS\Controllers\CMSSiteTreeFilter_Search; use SilverStripe\CMS\Controllers\CMSSiteTreeFilter_Search;
@ -15,13 +14,12 @@ use SilverStripe\Dev\SapphireTest;
class CMSSiteTreeFilterTest extends SapphireTest class CMSSiteTreeFilterTest extends SapphireTest
{ {
protected static $fixture_file = 'CMSSiteTreeFilterTest.yml'; protected static $fixture_file = 'CMSSiteTreeFilterTest.yml';
public function testSearchFilterEmpty() public function testSearchFilterEmpty()
{ {
$page1 = $this->objFromFixture('Page', 'page1'); $page1 = $this->objFromFixture(SiteTree::class, 'page1');
$page2 = $this->objFromFixture('Page', 'page2'); $page2 = $this->objFromFixture(SiteTree::class, 'page2');
$f = new CMSSiteTreeFilter_Search(); $f = new CMSSiteTreeFilter_Search();
$results = $f->pagesIncluded(); $results = $f->pagesIncluded();
@ -32,8 +30,8 @@ class CMSSiteTreeFilterTest extends SapphireTest
public function testSearchFilterByTitle() public function testSearchFilterByTitle()
{ {
$page1 = $this->objFromFixture('Page', 'page1'); $page1 = $this->objFromFixture(SiteTree::class, 'page1');
$page2 = $this->objFromFixture('Page', 'page2'); $page2 = $this->objFromFixture(SiteTree::class, 'page2');
$f = new CMSSiteTreeFilter_Search(['Title' => 'Page 1']); $f = new CMSSiteTreeFilter_Search(['Title' => 'Page 1']);
$results = $f->pagesIncluded(); $results = $f->pagesIncluded();
@ -49,7 +47,7 @@ class CMSSiteTreeFilterTest extends SapphireTest
public function testUrlSegmentFilter() public function testUrlSegmentFilter()
{ {
$page = $this->objFromFixture(Page::class, 'page8'); $page = $this->objFromFixture(SiteTree::class, 'page8');
$filter = CMSSiteTreeFilter_Search::create(['Term' => 'lake-wanaka+adventure']); $filter = CMSSiteTreeFilter_Search::create(['Term' => 'lake-wanaka+adventure']);
$this->assertTrue($filter->isPageIncluded($page)); $this->assertTrue($filter->isPageIncluded($page));
@ -60,8 +58,8 @@ class CMSSiteTreeFilterTest extends SapphireTest
public function testIncludesParentsForNestedMatches() public function testIncludesParentsForNestedMatches()
{ {
$parent = $this->objFromFixture('Page', 'page3'); $parent = $this->objFromFixture(SiteTree::class, 'page3');
$child = $this->objFromFixture('Page', 'page3b'); $child = $this->objFromFixture(SiteTree::class, 'page3b');
$f = new CMSSiteTreeFilter_Search(['Title' => 'Page 3b']); $f = new CMSSiteTreeFilter_Search(['Title' => 'Page 3b']);
$results = $f->pagesIncluded(); $results = $f->pagesIncluded();
@ -78,11 +76,11 @@ class CMSSiteTreeFilterTest extends SapphireTest
public function testChangedPagesFilter() public function testChangedPagesFilter()
{ {
/** @var Page $unchangedPage */ /** @var Page $unchangedPage */
$unchangedPage = $this->objFromFixture('Page', 'page1'); $unchangedPage = $this->objFromFixture(SiteTree::class, 'page1');
$unchangedPage->publishRecursive(); $unchangedPage->publishRecursive();
/** @var Page $changedPage */ /** @var Page $changedPage */
$changedPage = $this->objFromFixture('Page', 'page2'); $changedPage = $this->objFromFixture(SiteTree::class, 'page2');
$changedPage->Title = 'Original'; $changedPage->Title = 'Original';
$changedPage->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE); $changedPage->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
$changedPage->Title = 'Changed'; $changedPage->Title = 'Changed';
@ -121,7 +119,7 @@ class CMSSiteTreeFilterTest extends SapphireTest
public function testDeletedPagesFilter() public function testDeletedPagesFilter()
{ {
$deletedPage = $this->objFromFixture('Page', 'page2'); $deletedPage = $this->objFromFixture(SiteTree::class, 'page2');
$deletedPage->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE); $deletedPage->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
$deletedPageID = $deletedPage->ID; $deletedPageID = $deletedPage->ID;
$deletedPage->delete(); $deletedPage->delete();
@ -141,7 +139,7 @@ class CMSSiteTreeFilterTest extends SapphireTest
public function testStatusDraftPagesFilter() public function testStatusDraftPagesFilter()
{ {
$draftPage = $this->objFromFixture('Page', 'page4'); $draftPage = $this->objFromFixture(SiteTree::class, 'page4');
$draftPage = Versioned::get_one_by_stage( $draftPage = Versioned::get_one_by_stage(
SiteTree::class, SiteTree::class,
'Stage', 'Stage',
@ -164,20 +162,23 @@ class CMSSiteTreeFilterTest extends SapphireTest
public function testDateFromToLastSameDate() public function testDateFromToLastSameDate()
{ {
$draftPage = $this->objFromFixture('Page', 'page4'); $draftPage = $this->objFromFixture(SiteTree::class, 'page4');
// Grab the date // Grab the date
$date = substr($draftPage->LastEdited ?? '', 0, 10); $date = substr($draftPage->LastEdited ?? '', 0, 10);
// Filter with that date // Filter with that date
$filter = new CMSSiteTreeFilter_Search([ $filter = new CMSSiteTreeFilter_Search([
'LastEditedFrom' => $date, 'LastEditedFrom' => $date,
'LastEditedTo' => $date 'LastEditedTo' => $date,
]); ]);
$this->assertTrue($filter->isPageIncluded($draftPage), 'Using the same date for from and to should show find that page'); $this->assertTrue(
$filter->isPageIncluded($draftPage),
'Using the same date for from and to should show find that page'
);
} }
public function testStatusRemovedFromDraftFilter() public function testStatusRemovedFromDraftFilter()
{ {
$removedDraftPage = $this->objFromFixture('Page', 'page6'); $removedDraftPage = $this->objFromFixture(SiteTree::class, 'page6');
$removedDraftPage->publishRecursive(); $removedDraftPage->publishRecursive();
$removedDraftPage->deleteFromStage('Stage'); $removedDraftPage->deleteFromStage('Stage');
$removedDraftPage = Versioned::get_one_by_stage( $removedDraftPage = Versioned::get_one_by_stage(
@ -202,7 +203,7 @@ class CMSSiteTreeFilterTest extends SapphireTest
public function testStatusDeletedFilter() public function testStatusDeletedFilter()
{ {
$deletedPage = $this->objFromFixture('Page', 'page7'); $deletedPage = $this->objFromFixture(SiteTree::class, 'page7');
$deletedPage->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE); $deletedPage->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
$deletedPageID = $deletedPage->ID; $deletedPageID = $deletedPage->ID;

View File

@ -1,4 +1,4 @@
Page: SilverStripe\CMS\Model\SiteTree:
page1: page1:
Title: Page 1 Title: Page 1
page2: page2:
@ -15,19 +15,19 @@ Page:
page7: page7:
Title: Page 7 Title: Page 7
page7a: page7a:
Parent: =>Page.page7 Parent: =>SilverStripe\CMS\Model\SiteTree.page7
Title: Page 7a Title: Page 7a
page2a: page2a:
Parent: =>Page.page2 Parent: =>SilverStripe\CMS\Model\SiteTree.page2
Title: Page 2a Title: Page 2a
page2b: page2b:
Parent: =>Page.page2 Parent: =>SilverStripe\CMS\Model\SiteTree.page2
Title: Page 2b Title: Page 2b
page3a: page3a:
Parent: =>Page.page3 Parent: =>SilverStripe\CMS\Model\SiteTree.page3
Title: Page 3a Title: Page 3a
page3b: page3b:
Parent: =>Page.page3 Parent: =>SilverStripe\CMS\Model\SiteTree.page3
Title: Page 3b Title: Page 3b
page8: page8:
Title: EncodedUrlSegment Title: EncodedUrlSegment

View File

@ -32,7 +32,7 @@ class CMSTreeTest extends FunctionalTest
$data = [ $data = [
'SiblingIDs' => $siblingIDs, 'SiblingIDs' => $siblingIDs,
'ID' => $page2->ID, 'ID' => $page2->ID,
'ParentID' => 0 'ParentID' => 0,
]; ];
$response = $this->post('admin/pages/edit/savetreenode', $data); $response = $this->post('admin/pages/edit/savetreenode', $data);
@ -62,12 +62,12 @@ class CMSTreeTest extends FunctionalTest
$siblingIDs = [ $siblingIDs = [
$page31->ID, $page31->ID,
$page2->ID, $page2->ID,
$page32->ID $page32->ID,
]; ];
$data = [ $data = [
'SiblingIDs' => $siblingIDs, 'SiblingIDs' => $siblingIDs,
'ID' => $page2->ID, 'ID' => $page2->ID,
'ParentID' => $page3->ID 'ParentID' => $page3->ID,
]; ];
$response = $this->post('admin/pages/edit/savetreenode', $data); $response = $this->post('admin/pages/edit/savetreenode', $data);
$this->assertEquals(200, $response->getStatusCode()); $this->assertEquals(200, $response->getStatusCode());

View File

@ -6,7 +6,7 @@ use SilverStripe\Versioned\Versioned;
use SilverStripe\Control\HTTPResponse_Exception; use SilverStripe\Control\HTTPResponse_Exception;
use SilverStripe\Core\Config\Config; use SilverStripe\Core\Config\Config;
use SilverStripe\Dev\FunctionalTest; use SilverStripe\Dev\FunctionalTest;
use Page; use SilverStripe\CMS\Model\SiteTree;
class ContentControllerPermissionsTest extends FunctionalTest class ContentControllerPermissionsTest extends FunctionalTest
{ {
@ -17,7 +17,7 @@ class ContentControllerPermissionsTest extends FunctionalTest
public function testCanViewStage() public function testCanViewStage()
{ {
// Create a new page // Create a new page
$page = new Page(); $page = new SiteTree();
$page->URLSegment = 'testpage'; $page->URLSegment = 'testpage';
$page->write(); $page->write();
$page->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE); $page->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
@ -38,7 +38,11 @@ class ContentControllerPermissionsTest extends FunctionalTest
$response = $responseException->getResponse(); $response = $responseException->getResponse();
} }
// should redirect to login // should redirect to login
$this->assertEquals($response->getStatusCode(), 302, 'Redirects to login page when not logged in for draft stage'); $this->assertEquals(
$response->getStatusCode(),
302,
'Redirects to login page when not logged in for draft stage'
);
$this->assertStringContainsString( $this->assertStringContainsString(
Config::inst()->get('SilverStripe\\Security\\Security', 'login_url'), Config::inst()->get('SilverStripe\\Security\\Security', 'login_url'),
$response->getHeader('Location') $response->getHeader('Location')
@ -47,6 +51,10 @@ class ContentControllerPermissionsTest extends FunctionalTest
$this->logInWithPermission('CMS_ACCESS_CMSMain'); $this->logInWithPermission('CMS_ACCESS_CMSMain');
$response = $this->get('/testpage/?stage=Stage'); $response = $this->get('/testpage/?stage=Stage');
$this->assertEquals($response->getStatusCode(), 200, 'Doesnt redirect to login, but shows page for authenticated user'); $this->assertEquals(
$response->getStatusCode(),
200,
'Doesnt redirect to login, but shows page for authenticated user'
);
} }
} }

View File

@ -4,23 +4,23 @@ namespace SilverStripe\CMS\Tests\Controllers;
use SilverStripe\Assets\File; use SilverStripe\Assets\File;
use SilverStripe\CMS\Controllers\ContentController; use SilverStripe\CMS\Controllers\ContentController;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\CMS\Search\ContentControllerSearchExtension; use SilverStripe\CMS\Search\ContentControllerSearchExtension;
use SilverStripe\Dev\SapphireTest; use SilverStripe\Dev\SapphireTest;
use SilverStripe\ORM\Search\FulltextSearchable; use SilverStripe\ORM\Search\FulltextSearchable;
use SilverStripe\Versioned\Versioned; use SilverStripe\Versioned\Versioned;
use Page;
class ContentControllerSearchExtensionTest extends SapphireTest class ContentControllerSearchExtensionTest extends SapphireTest
{ {
protected static $required_extensions = [ protected static $required_extensions = [
ContentController::class => [ ContentController::class => [
ContentControllerSearchExtension::class, ContentControllerSearchExtension::class,
] ],
]; ];
public function testCustomSearchFormClassesToTest() public function testCustomSearchFormClassesToTest()
{ {
$page = new Page(); $page = new SiteTree();
$page->URLSegment = 'whatever'; $page->URLSegment = 'whatever';
$page->Content = 'oh really?'; $page->Content = 'oh really?';
$page->write(); $page->write();

10
tests/php/Controllers/ContentControllerTest.php Executable file → Normal file
View File

@ -10,7 +10,6 @@ use SilverStripe\Control\HTTPResponse_Exception;
use SilverStripe\Core\Config\Config; use SilverStripe\Core\Config\Config;
use SilverStripe\Dev\FunctionalTest; use SilverStripe\Dev\FunctionalTest;
use SilverStripe\Versioned\Versioned; use SilverStripe\Versioned\Versioned;
use Page;
class ContentControllerTest extends FunctionalTest class ContentControllerTest extends FunctionalTest
{ {
@ -31,8 +30,8 @@ class ContentControllerTest extends FunctionalTest
Config::modify()->set(SiteTree::class, 'nested_urls', true); Config::modify()->set(SiteTree::class, 'nested_urls', true);
// Ensure all pages are published // Ensure all pages are published
/** @var Page $page */ /** @var SiteTree $page */
foreach (Page::get() as $page) { foreach (SiteTree::get() as $page) {
$page->publishSingle(); $page->publishSingle();
} }
} }
@ -95,8 +94,7 @@ class ContentControllerTest extends FunctionalTest
public function testDeepNestedURLs() public function testDeepNestedURLs()
{ {
$page = new SiteTree();
$page = new Page();
$page->URLSegment = 'base-page'; $page->URLSegment = 'base-page';
$page->write(); $page->write();
$page->publishSingle(); $page->publishSingle();
@ -174,7 +172,7 @@ class ContentControllerTest extends FunctionalTest
$response = $this->get($page->RelativeLink()); $response = $this->get($page->RelativeLink());
$this->assertEquals("ContentControllerTestPageWithoutController", trim($response->getBody() ?? '')); $this->assertEquals("ContentControllerTestPageWithoutController", trim($response->getBody() ?? ''));
// // This should fall over to user Page.ss // This should fall over to user Page.ss
$page = new ContentControllerTestPage(); $page = new ContentControllerTestPage();
$page->URLSegment = "test"; $page->URLSegment = "test";
$page->write(); $page->write();

View File

@ -2,10 +2,10 @@
namespace SilverStripe\CMS\Tests\Controllers; namespace SilverStripe\CMS\Tests\Controllers;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use Page;
class ContentControllerTestPage extends Page implements TestOnly class ContentControllerTestPage extends SiteTree implements TestOnly
{ {
private static $table_name = 'ContentControllerTestPage'; private static $table_name = 'ContentControllerTestPage';
} }

View File

@ -9,7 +9,7 @@ class ContentControllerTestPageController extends PageController implements Test
{ {
private static $allowed_actions = [ private static $allowed_actions = [
'test', 'test',
'testwithouttemplate' 'testwithouttemplate',
]; ];
public function testwithouttemplate() public function testwithouttemplate()

View File

@ -2,10 +2,9 @@
namespace SilverStripe\CMS\Tests\Controllers; namespace SilverStripe\CMS\Tests\Controllers;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use Page;
class ContentControllerTestPageWithoutController extends Page implements TestOnly class ContentControllerTestPageWithoutController extends SiteTree implements TestOnly
{ {
} }

View File

@ -2,10 +2,10 @@
namespace SilverStripe\CMS\Tests\Controllers; namespace SilverStripe\CMS\Tests\Controllers;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use Page;
class ContentControllerTest_Page extends Page implements TestOnly class ContentControllerTest_Page extends SiteTree implements TestOnly
{ {
private static $table_name = 'ContentControllerTest_Page'; private static $table_name = 'ContentControllerTest_Page';
} }

View File

@ -2,14 +2,13 @@
namespace SilverStripe\CMS\Tests\Controllers; namespace SilverStripe\CMS\Tests\Controllers;
use SilverStripe\CMS\Controllers\ContentController;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use PageController;
class ContentControllerTest_PageController extends PageController implements TestOnly class ContentControllerTest_PageController extends ContentController implements TestOnly
{ {
private static $allowed_actions = [ private static $allowed_actions = [
'second_index' 'second_index',
]; ];
public function index() public function index()

View File

@ -10,7 +10,6 @@ use SilverStripe\Core\Config\Config;
use SilverStripe\Control\Director; use SilverStripe\Control\Director;
use SilverStripe\Control\Controller; use SilverStripe\Control\Controller;
use SilverStripe\Dev\FunctionalTest; use SilverStripe\Dev\FunctionalTest;
use Page;
use SilverStripe\View\Parsers\URLSegmentFilter; use SilverStripe\View\Parsers\URLSegmentFilter;
class ModelAsControllerTest extends FunctionalTest class ModelAsControllerTest extends FunctionalTest
@ -34,7 +33,7 @@ class ModelAsControllerTest extends FunctionalTest
protected function generateNestedPagesFixture() protected function generateNestedPagesFixture()
{ {
$level1 = new Page(); $level1 = new SiteTree();
$level1->Title = 'First Level'; $level1->Title = 'First Level';
$level1->URLSegment = 'level1'; $level1->URLSegment = 'level1';
$level1->write(); $level1->write();
@ -44,7 +43,7 @@ class ModelAsControllerTest extends FunctionalTest
$level1->write(); $level1->write();
$level1->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE); $level1->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
$level2 = new Page(); $level2 = new SiteTree();
$level2->Title = 'Second Level'; $level2->Title = 'Second Level';
$level2->URLSegment = 'level2'; $level2->URLSegment = 'level2';
$level2->ParentID = $level1->ID; $level2->ParentID = $level1->ID;
@ -55,7 +54,7 @@ class ModelAsControllerTest extends FunctionalTest
$level2->write(); $level2->write();
$level2->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE); $level2->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
$level3 = new Page(); $level3 = new SiteTree();
$level3->Title = "Level 3"; $level3->Title = "Level 3";
$level3->URLSegment = 'level3'; $level3->URLSegment = 'level3';
$level3->ParentID = $level2->ID; $level3->ParentID = $level2->ID;
@ -93,7 +92,7 @@ class ModelAsControllerTest extends FunctionalTest
$response = $this->get('newlevel1/level2'); $response = $this->get('newlevel1/level2');
$this->assertEquals($response->getStatusCode(), 301); $this->assertEquals($response->getStatusCode(), 301);
$this->assertEquals( $this->assertEquals(
Controller::join_links(Director::baseURL() . 'newlevel1/newlevel2/'), Controller::join_links(Director::baseURL() . 'newlevel1/newlevel2'),
$response->getHeader('Location') $response->getHeader('Location')
); );
@ -101,7 +100,7 @@ class ModelAsControllerTest extends FunctionalTest
$response = $this->get('newlevel1/newlevel2/level3'); $response = $this->get('newlevel1/newlevel2/level3');
$this->assertEquals($response->getStatusCode(), 301); $this->assertEquals($response->getStatusCode(), 301);
$this->assertEquals( $this->assertEquals(
Controller::join_links(Director::baseURL() . 'newlevel1/newlevel2/newlevel3/'), Controller::join_links(Director::baseURL() . 'newlevel1/newlevel2/newlevel3'),
$response->getHeader('Location') $response->getHeader('Location')
); );
@ -115,7 +114,7 @@ class ModelAsControllerTest extends FunctionalTest
*/ */
public function testHeavilyNestedRenamedRedirectedPages() public function testHeavilyNestedRenamedRedirectedPages()
{ {
$page = new Page(); $page = new SiteTree();
$page->Title = 'First Level'; $page->Title = 'First Level';
$page->URLSegment = 'oldurl'; $page->URLSegment = 'oldurl';
$page->write(); $page->write();
@ -125,28 +124,28 @@ class ModelAsControllerTest extends FunctionalTest
$page->write(); $page->write();
$page->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE); $page->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
$page2 = new Page(); $page2 = new SiteTree();
$page2->Title = 'Second Level Page'; $page2->Title = 'Second Level Page';
$page2->URLSegment = 'level2'; $page2->URLSegment = 'level2';
$page2->ParentID = $page->ID; $page2->ParentID = $page->ID;
$page2->write(); $page2->write();
$page2->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE); $page2->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
$page3 = new Page(); $page3 = new SiteTree();
$page3->Title = 'Third Level Page'; $page3->Title = 'Third Level Page';
$page3->URLSegment = 'level3'; $page3->URLSegment = 'level3';
$page3->ParentID = $page2->ID; $page3->ParentID = $page2->ID;
$page3->write(); $page3->write();
$page3->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE); $page3->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
$page4 = new Page(); $page4 = new SiteTree();
$page4->Title = 'Fourth Level Page'; $page4->Title = 'Fourth Level Page';
$page4->URLSegment = 'level4'; $page4->URLSegment = 'level4';
$page4->ParentID = $page3->ID; $page4->ParentID = $page3->ID;
$page4->write(); $page4->write();
$page4->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE); $page4->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
$page5 = new Page(); $page5 = new SiteTree();
$page5->Title = 'Fifth Level Page'; $page5->Title = 'Fifth Level Page';
$page5->URLSegment = 'level5'; $page5->URLSegment = 'level5';
$page5->ParentID = $page4->ID; $page5->ParentID = $page4->ID;
@ -154,10 +153,10 @@ class ModelAsControllerTest extends FunctionalTest
$page5->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE); $page5->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
// Test that the redirect still works fine when trying to access the most nested page // Test that the redirect still works fine when trying to access the most nested page
$response = $this->get('oldurl/level2/level3/level4/level5/'); $response = $this->get('oldurl/level2/level3/level4/level5');
$this->assertEquals($response->getStatusCode(), 301); $this->assertEquals($response->getStatusCode(), 301);
$this->assertEquals( $this->assertEquals(
Controller::join_links(Director::baseURL() . 'newurl/level2/level3/level4/level5/'), Controller::join_links(Director::baseURL() . 'newurl/level2/level3/level4/level5'),
$response->getHeader('Location') $response->getHeader('Location')
); );
} }
@ -171,7 +170,7 @@ class ModelAsControllerTest extends FunctionalTest
$response = $this->get('newlevel3'); $response = $this->get('newlevel3');
$this->assertEquals(301, $response->getStatusCode()); $this->assertEquals(301, $response->getStatusCode());
$this->assertEquals( $this->assertEquals(
Director::baseURL() . 'newlevel1/newlevel2/newlevel3/', Director::baseURL() . 'newlevel1/newlevel2/newlevel3',
$response->getHeader("Location") $response->getHeader("Location")
); );
@ -179,7 +178,7 @@ class ModelAsControllerTest extends FunctionalTest
$response = $this->get('level3'); $response = $this->get('level3');
$this->assertEquals(301, $response->getStatusCode()); $this->assertEquals(301, $response->getStatusCode());
$this->assertEquals( $this->assertEquals(
Director::baseURL() . 'newlevel1/newlevel2/newlevel3/', Director::baseURL() . 'newlevel1/newlevel2/newlevel3',
$response->getHeader("Location") $response->getHeader("Location")
); );
} }
@ -188,8 +187,8 @@ class ModelAsControllerTest extends FunctionalTest
{ {
$this->generateNestedPagesFixture(); $this->generateNestedPagesFixture();
$otherParent = new Page([ $otherParent = new SiteTree([
'URLSegment' => 'otherparent' 'URLSegment' => 'otherparent',
]); ]);
$otherParent->write(); $otherParent->write();
$otherParent->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE); $otherParent->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
@ -215,10 +214,10 @@ class ModelAsControllerTest extends FunctionalTest
$this->generateNestedPagesFixture(); $this->generateNestedPagesFixture();
// check third level URLSegment // check third level URLSegment
$response = $this->get('newlevel1/newlevel2/level3/?foo=bar&test=test'); $response = $this->get('newlevel1/newlevel2/level3?foo=bar&test=test');
$this->assertEquals($response->getStatusCode(), 301); $this->assertEquals($response->getStatusCode(), 301);
$this->assertEquals( $this->assertEquals(
Controller::join_links(Director::baseURL() . 'newlevel1/newlevel2/newlevel3/', '?foo=bar&test=test'), Controller::join_links(Director::baseURL() . 'newlevel1/newlevel2/newlevel3', '?foo=bar&test=test'),
$response->getHeader('Location') $response->getHeader('Location')
); );
} }
@ -232,9 +231,9 @@ class ModelAsControllerTest extends FunctionalTest
{ {
$this->generateNestedPagesFixture(); $this->generateNestedPagesFixture();
$otherLevel1 = new Page([ $otherLevel1 = new SiteTree([
'Title' => "Other Level 1", 'Title' => "Other Level 1",
'URLSegment' => 'level1' 'URLSegment' => 'level1',
]); ]);
$otherLevel1->write(); $otherLevel1->write();
$otherLevel1->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE); $otherLevel1->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
@ -260,7 +259,7 @@ class ModelAsControllerTest extends FunctionalTest
*/ */
public function testFindOldPage() public function testFindOldPage()
{ {
$page = new Page(); $page = new SiteTree();
$page->Title = 'First Level'; $page->Title = 'First Level';
$page->URLSegment = 'oldurl'; $page->URLSegment = 'oldurl';
$page->write(); $page->write();
@ -274,7 +273,7 @@ class ModelAsControllerTest extends FunctionalTest
$matchedPage = SiteTree::get_by_link($url); $matchedPage = SiteTree::get_by_link($url);
$this->assertEquals('First Level', $matchedPage->Title); $this->assertEquals('First Level', $matchedPage->Title);
$page2 = new Page(); $page2 = new SiteTree();
$page2->Title = 'Second Level Page'; $page2->Title = 'Second Level Page';
$page2->URLSegment = 'oldpage2'; $page2->URLSegment = 'oldpage2';
$page2->ParentID = $page->ID; $page2->ParentID = $page->ID;
@ -304,12 +303,12 @@ class ModelAsControllerTest extends FunctionalTest
RootURLController::reset(); RootURLController::reset();
Config::modify()->set(SiteTree::class, 'nested_urls', true); Config::modify()->set(SiteTree::class, 'nested_urls', true);
$draft = new Page(); $draft = new SiteTree();
$draft->Title = 'Root Leve Draft Page'; $draft->Title = 'Root Leve Draft Page';
$draft->URLSegment = 'root'; $draft->URLSegment = 'root';
$draft->write(); $draft->write();
$published = new Page(); $published = new SiteTree();
$published->Title = 'Published Page Under Draft Page'; $published->Title = 'Published Page Under Draft Page';
$published->URLSegment = 'sub-root'; $published->URLSegment = 'sub-root';
$published->write(); $published->write();
@ -319,7 +318,8 @@ class ModelAsControllerTest extends FunctionalTest
$this->assertEquals( $this->assertEquals(
$response->getStatusCode(), $response->getStatusCode(),
404, 404,
'The page should not be found since its parent has not been published, in this case http://<yousitename>/root/sub-root or http://<yousitename>/sub-root' 'The page should not be found since its parent has not been published, in this case ' .
'http://<yousitename>/root/sub-root or http://<yousitename>/sub-root'
); );
} }
@ -327,13 +327,13 @@ class ModelAsControllerTest extends FunctionalTest
{ {
Config::modify()->set(URLSegmentFilter::class, 'default_allow_multibyte', true); Config::modify()->set(URLSegmentFilter::class, 'default_allow_multibyte', true);
$parent = new Page(); $parent = new SiteTree();
$parent->Title = 'Multibyte test'; $parent->Title = 'Multibyte test';
$parent->URLSegment = 'بلاگ'; $parent->URLSegment = 'بلاگ';
$parent->write(); $parent->write();
$parent->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE); $parent->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
$child = new Page(); $child = new SiteTree();
$child->Title = 'Multibyte test'; $child->Title = 'Multibyte test';
$child->URLSegment = 'فضة'; $child->URLSegment = 'فضة';
$child->ParentID = $parent->ID; $child->ParentID = $parent->ID;

View File

@ -13,7 +13,7 @@ class RootURLControllerTest extends SapphireTest
public function testGetHomepageLink() public function testGetHomepageLink()
{ {
$default = $this->objFromFixture('Page', 'home'); $default = $this->objFromFixture(SiteTree::class, 'home');
Config::modify()->set(SiteTree::class, 'nested_urls', false); Config::modify()->set(SiteTree::class, 'nested_urls', false);
$this->assertEquals('home', RootURLController::get_homepage_link()); $this->assertEquals('home', RootURLController::get_homepage_link());

View File

@ -1,9 +1,9 @@
Page: SilverStripe\CMS\Model\SiteTree:
home: home:
Title: Home Title: Home
nested: nested:
Title: Nested Home Title: Nested Home
Parent: =>Page.home Parent: =>SilverStripe\CMS\Model\SiteTree.home
page1: page1:
Title: First Page Title: First Page
URLSegment: page1 URLSegment: page1

View File

@ -1,239 +0,0 @@
<?php
namespace SilverStripe\CMS\Tests\Controllers;
use SilverStripe\CMS\Controllers\SilverStripeNavigator;
use SilverStripe\CMS\Controllers\SilverStripeNavigatorItem_ArchiveLink;
use SilverStripe\CMS\Controllers\SilverStripeNavigatorItem_LiveLink;
use SilverStripe\CMS\Controllers\SilverStripeNavigatorItem_StageLink;
use SilverStripe\CMS\Controllers\SilverStripeNavigatorItem_Unversioned;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\Security\Member;
class SilverStripeNavigatorTest extends SapphireTest
{
protected static $fixture_file = 'CMSMainTest.yml';
protected static $extra_dataobjects = [
SilverStripeNavigatorTest\UnstagedRecord::class,
SilverStripeNavigatorTest\UnversionedRecord::class,
SilverStripeNavigatorTest\VersionedRecord::class,
];
public function testGetItemsAutoDiscovery(): void
{
$record = new SilverStripeNavigatorTest\VersionedRecord();
$record->PreviewLinkTestProperty = 'some-value';
$record->write();
$navigator = new SilverStripeNavigator($record);
$classes = array_map('get_class', $navigator->getItems()->toArray());
$this->assertContains(
SilverStripeNavigatorTest_TestItem::class,
$classes,
'Autodiscovers new classes'
);
}
public function testGetItemsPublished(): void
{
$record = new SilverStripeNavigatorTest\VersionedRecord();
$record->PreviewLinkTestProperty = 'some-value';
$record->write();
$record->publishRecursive();
$navigator = new SilverStripeNavigator($record);
$classes = array_map('get_class', $navigator->getItems()->toArray());
// Has the live and staged links
$this->assertContains(SilverStripeNavigatorItem_LiveLink::class, $classes);
$this->assertContains(SilverStripeNavigatorItem_StageLink::class, $classes);
// Does not have the other links
$this->assertNotContains(SilverStripeNavigatorItem_ArchiveLink::class, $classes);
$this->assertNotContains(SilverStripeNavigatorItem_Unversioned::class, $classes);
}
public function testGetItemsStaged(): void
{
$record = new SilverStripeNavigatorTest\VersionedRecord();
$record->PreviewLinkTestProperty = 'some-value';
$record->write();
$navigator = new SilverStripeNavigator($record);
$classes = array_map('get_class', $navigator->getItems()->toArray());
// Has the stage link
$this->assertContains(SilverStripeNavigatorItem_StageLink::class, $classes);
// Does not have the other links
$this->assertNotContains(SilverStripeNavigatorItem_ArchiveLink::class, $classes);
$this->assertNotContains(SilverStripeNavigatorItem_LiveLink::class, $classes);
$this->assertNotContains(SilverStripeNavigatorItem_Unversioned::class, $classes);
}
public function testGetItemsArchived(): void
{
$record = new SilverStripeNavigatorTest\VersionedRecord();
$record->PreviewLinkTestProperty = 'some-value';
$record->write();
$record->doArchive();
$navigator = new SilverStripeNavigator($record);
$classes = array_map('get_class', $navigator->getItems()->toArray());
// Has the archived link
$this->assertContains(SilverStripeNavigatorItem_ArchiveLink::class, $classes);
// Does not have the other links
$this->assertNotContains(SilverStripeNavigatorItem_LiveLink::class, $classes);
$this->assertNotContains(SilverStripeNavigatorItem_StageLink::class, $classes);
$this->assertNotContains(SilverStripeNavigatorItem_UnversionedLink::class, $classes);
}
public function testGetItemsUnstaged(): void
{
$record = new SilverStripeNavigatorTest\UnstagedRecord();
$record->previewLinkTestProperty = 'some-value';
$record->write();
$navigator = new SilverStripeNavigator($record);
$classes = array_map('get_class', $navigator->getItems()->toArray());
// Has the unversioned link
$this->assertContains(SilverStripeNavigatorItem_Unversioned::class, $classes);
// Does not have the other links
$this->assertNotContains(SilverStripeNavigatorItem_ArchiveLink::class, $classes);
$this->assertNotContains(SilverStripeNavigatorItem_LiveLink::class, $classes);
$this->assertNotContains(SilverStripeNavigatorItem_StageLink::class, $classes);
}
public function testGetItemsUnversioned(): void
{
$record = new SilverStripeNavigatorTest\UnversionedRecord();
$record->previewLinkTestProperty = 'some-value';
$record->write();
$navigator = new SilverStripeNavigator($record);
$classes = array_map('get_class', $navigator->getItems()->toArray());
// Has the unversioned link
$this->assertContains(SilverStripeNavigatorItem_Unversioned::class, $classes);
// Does not have the other links
$this->assertNotContains(SilverStripeNavigatorItem_ArchiveLink::class, $classes);
$this->assertNotContains(SilverStripeNavigatorItem_LiveLink::class, $classes);
$this->assertNotContains(SilverStripeNavigatorItem_StageLink::class, $classes);
}
public function testCanViewPublished(): void
{
$record = new SilverStripeNavigatorTest\VersionedRecord();
$record->write();
$record->publishRecursive();
$liveLinkItem = new SilverStripeNavigatorItem_LiveLink($record);
$stagedLinkItem = new SilverStripeNavigatorItem_StageLink($record);
$archivedLinkItem = new SilverStripeNavigatorItem_ArchiveLink($record);
$unversionedLinkItem = new SilverStripeNavigatorItem_Unversioned($record);
// Cannot view staged and live links when there's no preview link
$this->assertFalse($liveLinkItem->canView());
$this->assertFalse($stagedLinkItem->canView());
$record->PreviewLinkTestProperty = 'some-value';
$record->write();
$record->publishRecursive();
// Can view staged and live links
$this->assertTrue($liveLinkItem->canView());
$this->assertTrue($stagedLinkItem->canView());
// Cannot view the other links
$this->assertFalse($archivedLinkItem->canView());
$this->assertFalse($unversionedLinkItem->canView());
}
public function testCanViewStaged(): void
{
$record = new SilverStripeNavigatorTest\VersionedRecord();
$record->write();
$liveLinkItem = new SilverStripeNavigatorItem_LiveLink($record);
$stagedLinkItem = new SilverStripeNavigatorItem_StageLink($record);
$archivedLinkItem = new SilverStripeNavigatorItem_ArchiveLink($record);
$unversionedLinkItem = new SilverStripeNavigatorItem_Unversioned($record);
// Cannot view staged link when there's no preview link
$this->assertFalse($stagedLinkItem->canView());
$record->PreviewLinkTestProperty = 'some-value';
// Can view staged link
$this->assertTrue($stagedLinkItem->canView());
// Cannot view the other links
$this->assertFalse($liveLinkItem->canView());
$this->assertFalse($archivedLinkItem->canView());
$this->assertFalse($unversionedLinkItem->canView());
}
public function testCanViewArchived(): void
{
$record = new SilverStripeNavigatorTest\VersionedRecord();
$record->write();
$record->doArchive();
$liveLinkItem = new SilverStripeNavigatorItem_LiveLink($record);
$stagedLinkItem = new SilverStripeNavigatorItem_StageLink($record);
$archivedLinkItem = new SilverStripeNavigatorItem_ArchiveLink($record);
$unversionedLinkItem = new SilverStripeNavigatorItem_Unversioned($record);
// Cannot view archived link when there's no preview link
$this->assertFalse($archivedLinkItem->canView());
$record->PreviewLinkTestProperty = 'some-value';
// Can view archived link
$this->assertTrue($archivedLinkItem->canView());
// Cannot view the other links
$this->assertFalse($liveLinkItem->canView());
$this->assertFalse($stagedLinkItem->canView());
$this->assertFalse($unversionedLinkItem->canView());
}
public function testCanViewUnstaged(): void
{
$record = new SilverStripeNavigatorTest\UnstagedRecord();
$record->write();
$liveLinkItem = new SilverStripeNavigatorItem_LiveLink($record);
$stagedLinkItem = new SilverStripeNavigatorItem_StageLink($record);
$archivedLinkItem = new SilverStripeNavigatorItem_ArchiveLink($record);
$unversionedLinkItem = new SilverStripeNavigatorItem_Unversioned($record);
// Cannot view unversioned link when there's no preview link
$this->assertFalse($unversionedLinkItem->canView());
$record->previewLinkTestProperty = 'some-value';
// Can view unversioned link
$this->assertTrue($unversionedLinkItem->canView());
// Cannot view the other links
$this->assertFalse($liveLinkItem->canView());
$this->assertFalse($stagedLinkItem->canView());
$this->assertFalse($archivedLinkItem->canView());
}
public function testCanViewUnversioned(): void
{
$record = new SilverStripeNavigatorTest\UnversionedRecord();
$record->write();
$liveLinkItem = new SilverStripeNavigatorItem_LiveLink($record);
$stagedLinkItem = new SilverStripeNavigatorItem_StageLink($record);
$archivedLinkItem = new SilverStripeNavigatorItem_ArchiveLink($record);
$unversionedLinkItem = new SilverStripeNavigatorItem_Unversioned($record);
// Cannot view unversioned link when there's no preview link
$this->assertFalse($unversionedLinkItem->canView());
$record->previewLinkTestProperty = 'some-value';
// Can view unversioned link
$this->assertTrue($unversionedLinkItem->canView());
// Cannot view the other links
$this->assertFalse($liveLinkItem->canView());
$this->assertFalse($stagedLinkItem->canView());
$this->assertFalse($archivedLinkItem->canView());
}
}

View File

@ -1,48 +0,0 @@
<?php
namespace SilverStripe\CMS\Tests\Controllers\SilverStripeNavigatorTest;
use SilverStripe\Dev\TestOnly;
use SilverStripe\ORM\CMSPreviewable;
use SilverStripe\ORM\DataObject;
use SilverStripe\Versioned\Versioned;
/**
* Versioned but not staged
*/
class UnstagedRecord extends DataObject implements TestOnly, CMSPreviewable
{
private static $table_name = 'SilverStripeNavigatorTest_UnstagedRecord';
private static $show_stage_link = true;
private static $show_live_link = true;
private static $show_unversioned_preview_link = true;
private static $extensions = [
Versioned::class . '.versioned',
];
public $previewLinkTestProperty = null;
public function PreviewLink($action = null)
{
return $this->previewLinkTestProperty;
}
/**
* To determine preview mechanism (e.g. embedded / iframe)
*
* @return string
*/
public function getMimeType()
{
return 'text/html';
}
public function CMSEditLink()
{
return null;
}
}

View File

@ -1,36 +0,0 @@
<?php
namespace SilverStripe\CMS\Tests\Controllers\SilverStripeNavigatorTest;
use SilverStripe\Dev\TestOnly;
use SilverStripe\ORM\CMSPreviewable;
use SilverStripe\ORM\DataObject;
use SilverStripe\Versioned\Versioned;
class UnversionedRecord extends DataObject implements TestOnly, CMSPreviewable
{
private static $table_name = 'SilverStripeNavigatorTest_UnversionedRecord';
private static $show_stage_link = true;
private static $show_live_link = true;
private static $show_unversioned_preview_link = true;
public $previewLinkTestProperty = null;
public function PreviewLink($action = null)
{
return $this->previewLinkTestProperty;
}
public function getMimeType()
{
return 'text/html';
}
public function CMSEditLink()
{
return null;
}
}

View File

@ -1,42 +0,0 @@
<?php
namespace SilverStripe\CMS\Tests\Controllers\SilverStripeNavigatorTest;
use SilverStripe\Dev\TestOnly;
use SilverStripe\ORM\CMSPreviewable;
use SilverStripe\ORM\DataObject;
use SilverStripe\Versioned\Versioned;
class VersionedRecord extends DataObject implements TestOnly, CMSPreviewable
{
private static $table_name = 'SilverStripeNavigatorTest_VersionedRecord';
private static $show_stage_link = true;
private static $show_live_link = true;
private static $show_unversioned_preview_link = true;
private static $db = [
'PreviewLinkTestProperty' => 'Text',
];
private static $extensions = [
Versioned::class,
];
public function PreviewLink($action = null)
{
return $this->PreviewLinkTestProperty;
}
public function getMimeType()
{
return 'text/html';
}
public function CMSEditLink()
{
return null;
}
}

View File

@ -1,19 +0,0 @@
<?php
namespace SilverStripe\CMS\Tests\Controllers;
use SilverStripe\CMS\Controllers\SilverStripeNavigatorItem;
use SilverStripe\Dev\TestOnly;
class SilverStripeNavigatorTest_TestItem extends SilverStripeNavigatorItem implements TestOnly
{
public function getTitle()
{
return self::class;
}
public function getHTML()
{
return null;
}
}

View File

@ -44,7 +44,7 @@ class LinkablePluginTest extends SapphireTest
public function testResolver() public function testResolver()
{ {
$page = SiteTree::create([ $page = new SiteTree([
'Title' => 'Test page', 'Title' => 'Test page',
'URLSegment' => 'test-page', 'URLSegment' => 'test-page',
'ParentID' => 0, 'ParentID' => 0,
@ -52,7 +52,7 @@ class LinkablePluginTest extends SapphireTest
$page->write(); $page->write();
$page->publishRecursive(); $page->publishRecursive();
$page = SiteTree::create([ $page = new SiteTree([
'Title' => 'Other test page', 'Title' => 'Other test page',
'URLSegment' => 'other-test-page', 'URLSegment' => 'other-test-page',
'ParentID' => 0, 'ParentID' => 0,

View File

@ -2,7 +2,7 @@
namespace SilverStripe\CMS\Tests\Model; namespace SilverStripe\CMS\Tests\Model;
use Page; use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\CMS\Model\RedirectorPage; use SilverStripe\CMS\Model\RedirectorPage;
use SilverStripe\CMS\Model\RedirectorPageController; use SilverStripe\CMS\Model\RedirectorPageController;
use SilverStripe\Control\Director; use SilverStripe\Control\Director;
@ -36,53 +36,65 @@ class RedirectorPageTest extends FunctionalTest
Director::config()->set('alternate_base_url', 'http://www.mysite.com/'); Director::config()->set('alternate_base_url', 'http://www.mysite.com/');
// Ensure all pages are published // Ensure all pages are published
/** @var Page $page */ /** @var SiteTree $page */
foreach (Page::get() as $page) { foreach (SiteTree::get() as $page) {
$page->publishSingle(); $page->publishSingle();
} }
} }
public function testGoodRedirectors() public function testGoodRedirectors()
{ {
/* For good redirectors, the final destination URL will be returned */ // For good redirectors, the final destination URL will be returned
$this->assertEquals("http://www.google.com", $this->objFromFixture(RedirectorPage::class, 'goodexternal')->Link()); $this->assertEquals(
$this->assertEquals("/redirection-dest/", $this->objFromFixture(RedirectorPage::class, 'goodinternal')->redirectionLink()); "http://www.google.com",
$this->assertEquals("/redirection-dest/", $this->objFromFixture(RedirectorPage::class, 'goodinternal')->Link()); $this->objFromFixture(RedirectorPage::class, 'goodexternal')->Link()
);
$this->assertEquals(
"/redirection-dest",
$this->objFromFixture(RedirectorPage::class, 'goodinternal')->redirectionLink()
);
$this->assertEquals(
"/redirection-dest",
$this->objFromFixture(RedirectorPage::class, 'goodinternal')->Link()
);
} }
public function testEmptyRedirectors() public function testEmptyRedirectors()
{ {
/* If a redirector page is misconfigured, then its link method will just return the usual URLSegment-generated value */ // If a redirector page is misconfigured, then its link method will just return the usual
// URLSegment-generated value
$page1 = $this->objFromFixture(RedirectorPage::class, 'badexternal'); $page1 = $this->objFromFixture(RedirectorPage::class, 'badexternal');
$this->assertEquals('/bad-external/', $page1->Link()); $this->assertEquals('/bad-external', $page1->Link());
/* An error message will be shown if you visit it */ // An error message will be shown if you visit it
$content = $this->get(Director::makeRelative($page1->Link()))->getBody(); $content = $this->get(Director::makeRelative($page1->Link()))->getBody();
$this->assertStringContainsString('message-setupWithoutRedirect', $content); $this->assertStringContainsString('message-setupWithoutRedirect', $content);
/* This also applies for internal links */ // This also applies for internal links
$page2 = $this->objFromFixture(RedirectorPage::class, 'badinternal'); $page2 = $this->objFromFixture(RedirectorPage::class, 'badinternal');
$this->assertEquals('/bad-internal/', $page2->Link()); $this->assertEquals('/bad-internal', $page2->Link());
$content = $this->get(Director::makeRelative($page2->Link()))->getBody(); $content = $this->get(Director::makeRelative($page2->Link()))->getBody();
$this->assertStringContainsString('message-setupWithoutRedirect', $content); $this->assertStringContainsString('message-setupWithoutRedirect', $content);
} }
public function testReflexiveAndTransitiveInternalRedirectors() public function testReflexiveAndTransitiveInternalRedirectors()
{ {
/* Reflexive redirectors are those that point to themselves. They should behave the same as an empty redirector */ // Reflexive redirectors are those that point to themselves.
// They should behave the same as an empty redirector
$page = $this->objFromFixture(RedirectorPage::class, 'reflexive'); $page = $this->objFromFixture(RedirectorPage::class, 'reflexive');
$this->assertEquals('/reflexive/', $page->Link()); $this->assertEquals('/reflexive', $page->Link());
$content = $this->get(Director::makeRelative($page->Link()))->getBody(); $content = $this->get(Director::makeRelative($page->Link()))->getBody();
$this->assertStringContainsString('message-setupWithoutRedirect', $content); $this->assertStringContainsString('message-setupWithoutRedirect', $content);
/* Transitive redirectors are those that point to another redirector page. They should send people to the URLSegment // Transitive redirectors are those that point to another redirector page.
* of the destination page - the middle-stop, so to speak. That should redirect to the final destination */ // They should send people to the URLSegment of the destination page - the middle-stop, so to speak.
// That should redirect to the final destination
$page = $this->objFromFixture(RedirectorPage::class, 'transitive'); $page = $this->objFromFixture(RedirectorPage::class, 'transitive');
$this->assertEquals('/good-internal/', $page->Link()); $this->assertEquals('/good-internal', $page->Link());
$this->autoFollowRedirection = false; $this->autoFollowRedirection = false;
$response = $this->get(Director::makeRelative($page->Link())); $response = $this->get(Director::makeRelative($page->Link()));
$this->assertEquals(Director::absoluteURL('/redirection-dest/'), $response->getHeader("Location")); $this->assertEquals(Director::absoluteURL('/redirection-dest'), $response->getHeader("Location"));
} }
public function testExternalURLGetsPrefixIfNotSet() public function testExternalURLGetsPrefixIfNotSet()
@ -90,7 +102,11 @@ class RedirectorPageTest extends FunctionalTest
$page = $this->objFromFixture(RedirectorPage::class, 'externalnoprefix'); $page = $this->objFromFixture(RedirectorPage::class, 'externalnoprefix');
$this->assertEquals($page->ExternalURL, 'http://google.com', 'onBeforeWrite has prefixed with http'); $this->assertEquals($page->ExternalURL, 'http://google.com', 'onBeforeWrite has prefixed with http');
$page->write(); $page->write();
$this->assertEquals($page->ExternalURL, 'http://google.com', 'onBeforeWrite will not double prefix if written again!'); $this->assertEquals(
$page->ExternalURL,
'http://google.com',
'onBeforeWrite will not double prefix if written again!'
);
} }
public function testAllowsProtocolRelative() public function testAllowsProtocolRelative()

View File

@ -1,4 +1,4 @@
Page: SilverStripe\CMS\Model\SiteTree:
dest: dest:
Title: Redirection Dest Title: Redirection Dest
URLSegment: redirection-dest URLSegment: redirection-dest
@ -17,7 +17,7 @@ SilverStripe\CMS\Model\RedirectorPage:
Title: Good Internal Title: Good Internal
URLSegment: good-internal URLSegment: good-internal
RedirectionType: Internal RedirectionType: Internal
LinkTo: =>Page.dest LinkTo: =>SilverStripe\CMS\Model\SiteTree.dest
badexternal: badexternal:
Title: Bad External Title: Bad External
RedirectionType: External RedirectionType: External

View File

@ -2,7 +2,6 @@
namespace SilverStripe\CMS\Tests\Model; namespace SilverStripe\CMS\Tests\Model;
use Page;
use SilverStripe\CMS\Model\SiteTree; use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Dev\FunctionalTest; use SilverStripe\Dev\FunctionalTest;
use SilverStripe\ORM\DB; use SilverStripe\ORM\DB;
@ -21,7 +20,6 @@ use SilverStripe\Versioned\Versioned;
*/ */
class SiteTreeActionsTest extends FunctionalTest class SiteTreeActionsTest extends FunctionalTest
{ {
protected static $fixture_file = 'SiteTreeActionsTest.yml'; protected static $fixture_file = 'SiteTreeActionsTest.yml';
public function testActionsReadonly() public function testActionsReadonly()
@ -38,7 +36,7 @@ class SiteTreeActionsTest extends FunctionalTest
Security::setCurrentUser($readonlyEditor); Security::setCurrentUser($readonlyEditor);
// Reload latest version // Reload latest version
$page = Page::get()->byID($page->ID); $page = SiteTree::get()->byID($page->ID);
$actions = $page->getCMSActions(); $actions = $page->getCMSActions();
$this->assertNull($actions->dataFieldByName('action_save')); $this->assertNull($actions->dataFieldByName('action_save'));
@ -84,14 +82,14 @@ class SiteTreeActionsTest extends FunctionalTest
$author = $this->objFromFixture(Member::class, 'cmseditor'); $author = $this->objFromFixture(Member::class, 'cmseditor');
Security::setCurrentUser($author); Security::setCurrentUser($author);
/** @var Page $page */ /** @var SiteTree $page */
$page = new Page(); $page = new SiteTree();
$page->CanEditType = 'LoggedInUsers'; $page->CanEditType = 'LoggedInUsers';
$page->write(); $page->write();
$page->publishRecursive(); $page->publishRecursive();
// Reload latest version // Reload latest version
$page = Page::get()->byID($page->ID); $page = SiteTree::get()->byID($page->ID);
$actions = $page->getCMSActions(); $actions = $page->getCMSActions();
@ -108,7 +106,7 @@ class SiteTreeActionsTest extends FunctionalTest
$author = $this->objFromFixture(Member::class, 'cmseditor'); $author = $this->objFromFixture(Member::class, 'cmseditor');
Security::setCurrentUser($author); Security::setCurrentUser($author);
$page = new Page(); $page = new SiteTree();
$page->CanEditType = 'LoggedInUsers'; $page->CanEditType = 'LoggedInUsers';
$page->write(); $page->write();
$this->assertTrue($page->canPublish()); $this->assertTrue($page->canPublish());
@ -135,7 +133,7 @@ class SiteTreeActionsTest extends FunctionalTest
$author = $this->objFromFixture(Member::class, 'cmseditor'); $author = $this->objFromFixture(Member::class, 'cmseditor');
Security::setCurrentUser($author); Security::setCurrentUser($author);
$page = new Page(); $page = new SiteTree();
$page->CanEditType = 'LoggedInUsers'; $page->CanEditType = 'LoggedInUsers';
$page->write(); $page->write();
$this->assertTrue($page->canPublish()); $this->assertTrue($page->canPublish());
@ -145,7 +143,7 @@ class SiteTreeActionsTest extends FunctionalTest
$page->flushCache(); $page->flushCache();
// Reload latest version // Reload latest version
$page = Page::get()->byID($page->ID); $page = SiteTree::get()->byID($page->ID);
$actions = $page->getCMSActions(); $actions = $page->getCMSActions();
$this->assertNotNull($actions->dataFieldByName('action_save')); $this->assertNotNull($actions->dataFieldByName('action_save'));
@ -158,15 +156,17 @@ class SiteTreeActionsTest extends FunctionalTest
public function testActionsViewingOldVersion() public function testActionsViewingOldVersion()
{ {
$p = new Page(); $p = new SiteTree();
$p->Content = 'test page first version'; $p->Content = 'test page first version';
$p->write(); $p->write();
$p->Content = 'new content'; $p->Content = 'new content';
$p->write(); $p->write();
// Looking at the old version, the ability to rollback to that version is available // Looking at the old version, the ability to rollback to that version is available
$version = DB::query('SELECT "Version" FROM "SiteTree_Versions" WHERE "Content" = \'test page first version\'')->value(); $version = DB::query(
$old = Versioned::get_version('Page', $p->ID, $version); 'SELECT "Version" FROM "SiteTree_Versions" WHERE "Content" = \'test page first version\''
)->value();
$old = Versioned::get_version(SiteTree::class, $p->ID, $version);
$actions = $old->getCMSActions(); $actions = $old->getCMSActions();
$this->assertNull($actions->dataFieldByName('action_save')); $this->assertNull($actions->dataFieldByName('action_save'));
$this->assertNull($actions->dataFieldByName('action_publish')); $this->assertNull($actions->dataFieldByName('action_publish'));

View File

@ -4,9 +4,9 @@ namespace SilverStripe\CMS\Tests\Model;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use SilverStripe\Security\Permission; use SilverStripe\Security\Permission;
use Page; use SilverStripe\CMS\Model\SiteTree;
class SiteTreeActionsTest_Page extends Page implements TestOnly class SiteTreeActionsTest_Page extends SiteTree implements TestOnly
{ {
public function canEdit($member = null) public function canEdit($member = null)
{ {

View File

@ -18,7 +18,7 @@ class SiteTreeBacklinksTest extends SapphireTest
protected static $required_extensions = [ protected static $required_extensions = [
SiteTree::class => [ SiteTree::class => [
SiteTreeBacklinksTest_DOD::class SiteTreeBacklinksTest_DOD::class,
], ],
]; ];
@ -34,10 +34,10 @@ class SiteTreeBacklinksTest extends SapphireTest
// testing here. // testing here.
$this->logInWithPermission('ADMIN'); $this->logInWithPermission('ADMIN');
$page3 = $this->objFromFixture('Page', 'page3'); $page3 = $this->objFromFixture(SiteTree::class, 'page3');
$page3->Content = str_replace( $page3->Content = str_replace(
'$page1.ID', '$page1.ID',
$this->objFromFixture('Page', 'page1')->ID ?? '', $this->objFromFixture(SiteTree::class, 'page1')->ID ?? '',
$page3->Content ?? '' $page3->Content ?? ''
); );
$page3->write(); $page3->write();
@ -46,18 +46,22 @@ class SiteTreeBacklinksTest extends SapphireTest
public function testSavingPageWithLinkAddsBacklink() public function testSavingPageWithLinkAddsBacklink()
{ {
// load page 1 // load page 1
$page1 = $this->objFromFixture('Page', 'page1'); $page1 = $this->objFromFixture(SiteTree::class, 'page1');
// assert backlink to page 2 doesn't exist // assert backlink to page 2 doesn't exist
$page2 = $this->objFromFixture('Page', 'page2'); $page2 = $this->objFromFixture(SiteTree::class, 'page2');
$this->assertNotContains($page2->ID, $page1->BackLinkTracking()->column('ID'), 'Assert backlink to page 2 doesn\'t exist'); $this->assertNotContains(
$page2->ID,
$page1->BackLinkTracking()->column('ID'),
'Assert backlink to page 2 doesn\'t exist'
);
// add hyperlink to page 1 on page 2 // add hyperlink to page 1 on page 2
$page2->Content .= '<p><a href="[sitetree_link,id=' . $page1->ID . ']">Testing page 1 link</a></p>'; $page2->Content .= '<p><a href="[sitetree_link,id=' . $page1->ID . ']">Testing page 1 link</a></p>';
$page2->write(); $page2->write();
// load page 1 // load page 1
$page1 = $this->objFromFixture('Page', 'page1'); $page1 = $this->objFromFixture(SiteTree::class, 'page1');
// assert backlink to page 2 exists // assert backlink to page 2 exists
$this->assertContains($page2->ID, $page1->BackLinkTracking()->column('ID'), 'Assert backlink to page 2 exists'); $this->assertContains($page2->ID, $page1->BackLinkTracking()->column('ID'), 'Assert backlink to page 2 exists');
@ -66,10 +70,10 @@ class SiteTreeBacklinksTest extends SapphireTest
public function testRemovingLinkFromPageRemovesBacklink() public function testRemovingLinkFromPageRemovesBacklink()
{ {
// load page 1 // load page 1
$page1 = $this->objFromFixture('Page', 'page1'); $page1 = $this->objFromFixture(SiteTree::class, 'page1');
// assert backlink to page 3 exits // assert backlink to page 3 exits
$page3 = $this->objFromFixture('Page', 'page3'); $page3 = $this->objFromFixture(SiteTree::class, 'page3');
$this->assertContains($page3->ID, $page1->BackLinkTracking()->column('ID'), 'Assert backlink to page 3 exists'); $this->assertContains($page3->ID, $page1->BackLinkTracking()->column('ID'), 'Assert backlink to page 3 exists');
// remove hyperlink to page 1 // remove hyperlink to page 1
@ -77,116 +81,156 @@ class SiteTreeBacklinksTest extends SapphireTest
$page3->write(); $page3->write();
// load page 1 // load page 1
$page1 = $this->objFromFixture('Page', 'page1'); $page1 = $this->objFromFixture(SiteTree::class, 'page1');
// assert backlink to page 3 exists // assert backlink to page 3 exists
$this->assertNotContains($page3->ID, $page1->BackLinkTracking()->column('ID'), 'Assert backlink to page 3 doesn\'t exist'); $this->assertNotContains(
$page3->ID,
$page1->BackLinkTracking()->column('ID'),
'Assert backlink to page 3 doesn\'t exist'
);
} }
public function testChangingUrlOnDraftSiteRewritesLink() public function testChangingUrlOnDraftSiteRewritesLink()
{ {
// load page 1 // load page 1
$page1 = $this->objFromFixture('Page', 'page1'); $page1 = $this->objFromFixture(SiteTree::class, 'page1');
// assert backlink to page 3 exists // assert backlink to page 3 exists
$page3 = $this->objFromFixture('Page', 'page3'); $page3 = $this->objFromFixture(SiteTree::class, 'page3');
$this->assertContains($page3->ID, $page1->BackLinkTracking()->column('ID'), 'Assert backlink to page 3 exists'); $this->assertContains($page3->ID, $page1->BackLinkTracking()->column('ID'), 'Assert backlink to page 3 exists');
// assert hyperlink to page 1's current url exists on page 3 // assert hyperlink to page 1's current url exists on page 3
$links = HTTP::getLinksIn($page3->obj('Content')->forTemplate()); $links = HTTP::getLinksIn($page3->obj('Content')->forTemplate());
$this->assertContains(Director::baseURL().'page1/', $links, 'Assert hyperlink to page 1\'s current url exists on page 3'); $this->assertContains(
Director::baseURL() . 'page1',
$links,
'Assert hyperlink to page 1\'s current url exists on page 3'
);
// change url of page 1 // change url of page 1
$page1->URLSegment = 'new-url-segment'; $page1->URLSegment = 'new-url-segment';
$page1->write(); $page1->write();
// load page 3 // load page 3
$page3 = $this->objFromFixture('Page', 'page3'); $page3 = $this->objFromFixture(SiteTree::class, 'page3');
// assert hyperlink to page 1's new url exists // assert hyperlink to page 1's new url exists
$links = HTTP::getLinksIn($page3->obj('Content')->forTemplate()); $links = HTTP::getLinksIn($page3->obj('Content')->forTemplate());
$this->assertContains(Director::baseURL().'new-url-segment/', $links, 'Assert hyperlink to page 1\'s new url exists on page 3'); $this->assertContains(
Director::baseURL() . 'new-url-segment',
$links,
'Assert hyperlink to page 1\'s new url exists on page 3'
);
} }
public function testChangingUrlOnLiveSiteRewritesLink() public function testChangingUrlOnLiveSiteRewritesLink()
{ {
// publish page 1 & 3 // publish page 1 & 3
$page1 = $this->objFromFixture('Page', 'page1'); $page1 = $this->objFromFixture(SiteTree::class, 'page1');
$page3 = $this->objFromFixture('Page', 'page3'); $page3 = $this->objFromFixture(SiteTree::class, 'page3');
$this->assertTrue($page1->publishRecursive()); $this->assertTrue($page1->publishRecursive());
$this->assertTrue($page3->publishRecursive()); $this->assertTrue($page3->publishRecursive());
// load pages from live // load pages from live
$page1live = Versioned::get_one_by_stage('Page', 'Live', '"SiteTree"."ID" = ' . $page1->ID); $page1live = Versioned::get_one_by_stage(SiteTree::class, 'Live', '"SiteTree"."ID" = ' . $page1->ID);
$page3live = Versioned::get_one_by_stage('Page', 'Live', '"SiteTree"."ID" = ' . $page3->ID); $page3live = Versioned::get_one_by_stage(SiteTree::class, 'Live', '"SiteTree"."ID" = ' . $page3->ID);
// assert backlink to page 3 exists // assert backlink to page 3 exists
$this->assertContains($page3live->ID, $page1live->BackLinkTracking()->column('ID'), 'Assert backlink to page 3 exists'); $this->assertContains(
$page3live->ID,
$page1live->BackLinkTracking()->column('ID'),
'Assert backlink to page 3 exists'
);
// assert hyperlink to page 1's current url exists on page 3 // assert hyperlink to page 1's current url exists on page 3
$links = HTTP::getLinksIn($page3live->obj('Content')->forTemplate()); $links = HTTP::getLinksIn($page3live->obj('Content')->forTemplate());
$this->assertContains(Director::baseURL().'page1/', $links, 'Assert hyperlink to page 1\'s current url exists on page 3'); $this->assertContains(
Director::baseURL() . 'page1',
$links,
'Assert hyperlink to page 1\'s current url exists on page 3'
);
// change url of page 1 // change url of page 1
$page1live->URLSegment = 'new-url-segment'; $page1live->URLSegment = 'new-url-segment';
$page1live->writeToStage('Live'); $page1live->writeToStage('Live');
// load page 3 from live // load page 3 from live
$page3live = Versioned::get_one_by_stage('Page', 'Live', '"SiteTree"."ID" = ' . $page3->ID); $page3live = Versioned::get_one_by_stage(SiteTree::class, 'Live', '"SiteTree"."ID" = ' . $page3->ID);
// assert hyperlink to page 1's new url exists // assert hyperlink to page 1's new url exists
Versioned::set_stage(Versioned::LIVE); Versioned::set_stage(Versioned::LIVE);
$links = HTTP::getLinksIn($page3live->obj('Content')->forTemplate()); $links = HTTP::getLinksIn($page3live->obj('Content')->forTemplate());
$this->assertContains(Director::baseURL().'new-url-segment/', $links, 'Assert hyperlink to page 1\'s new url exists on page 3'); $this->assertContains(
Director::baseURL() . 'new-url-segment',
$links,
'Assert hyperlink to page 1\'s new url exists on page 3'
);
} }
public function testPublishingPageWithModifiedUrlRewritesLink() public function testPublishingPageWithModifiedUrlRewritesLink()
{ {
// publish page 1 & 3 // publish page 1 & 3
$page1 = $this->objFromFixture('Page', 'page1'); $page1 = $this->objFromFixture(SiteTree::class, 'page1');
$page3 = $this->objFromFixture('Page', 'page3'); $page3 = $this->objFromFixture(SiteTree::class, 'page3');
$this->assertTrue($page1->publishRecursive()); $this->assertTrue($page1->publishRecursive());
$this->assertTrue($page3->publishRecursive()); $this->assertTrue($page3->publishRecursive());
// load page 3 from live // load page 3 from live
$page3live = Versioned::get_one_by_stage('Page', 'Live', '"SiteTree"."ID" = ' . $page3->ID); $page3live = Versioned::get_one_by_stage(SiteTree::class, 'Live', '"SiteTree"."ID" = ' . $page3->ID);
// assert hyperlink to page 1's current url exists // assert hyperlink to page 1's current url exists
$links = HTTP::getLinksIn($page3live->obj('Content')->forTemplate()); $links = HTTP::getLinksIn($page3live->obj('Content')->forTemplate());
$this->assertContains(Director::baseURL().'page1/', $links, 'Assert hyperlink to page 1\'s current url exists on page 3'); $this->assertContains(
Director::baseURL() . 'page1',
$links,
'Assert hyperlink to page 1\'s current url exists on page 3'
);
// rename url of page 1 on stage // rename url of page 1 on stage
$page1->URLSegment = 'new-url-segment'; $page1->URLSegment = 'new-url-segment';
$page1->write(); $page1->write();
// assert hyperlink to page 1's current publish url exists // assert hyperlink to page 1's current publish url exists
$page3live = Versioned::get_one_by_stage('Page', 'Live', '"SiteTree"."ID" = ' . $page3->ID); $page3live = Versioned::get_one_by_stage(SiteTree::class, 'Live', '"SiteTree"."ID" = ' . $page3->ID);
Versioned::set_stage(Versioned::LIVE); Versioned::set_stage(Versioned::LIVE);
$links = HTTP::getLinksIn($page3live->obj('Content')->forTemplate()); $links = HTTP::getLinksIn($page3live->obj('Content')->forTemplate());
$this->assertContains(Director::baseURL().'page1/', $links, 'Assert hyperlink to page 1\'s current published url exists on page 3'); $this->assertContains(
Director::baseURL() . 'page1',
$links,
'Assert hyperlink to page 1\'s current published url exists on page 3'
);
// publish page 1 // publish page 1
$this->assertTrue($page1->publishRecursive()); $this->assertTrue($page1->publishRecursive());
// assert hyperlink to page 1's new published url exists // assert hyperlink to page 1's new published url exists
$page3live = Versioned::get_one_by_stage('Page', 'Live', '"SiteTree"."ID" = ' . $page3->ID); $page3live = Versioned::get_one_by_stage(SiteTree::class, 'Live', '"SiteTree"."ID" = ' . $page3->ID);
$links = HTTP::getLinksIn($page3live->obj('Content')->forTemplate()); $links = HTTP::getLinksIn($page3live->obj('Content')->forTemplate());
$this->assertContains(Director::baseURL().'new-url-segment/', $links, 'Assert hyperlink to page 1\'s new published url exists on page 3'); $this->assertContains(
Director::baseURL() . 'new-url-segment',
$links,
'Assert hyperlink to page 1\'s new published url exists on page 3'
);
} }
public function testPublishingPageWithModifiedLinksRewritesLinks() public function testPublishingPageWithModifiedLinksRewritesLinks()
{ {
// publish page 1 & 3 // publish page 1 & 3
$page1 = $this->objFromFixture('Page', 'page1'); $page1 = $this->objFromFixture(SiteTree::class, 'page1');
$page3 = $this->objFromFixture('Page', 'page3'); $page3 = $this->objFromFixture(SiteTree::class, 'page3');
$this->assertTrue($page1->publishRecursive()); $this->assertTrue($page1->publishRecursive());
$this->assertTrue($page3->publishRecursive()); $this->assertTrue($page3->publishRecursive());
// assert hyperlink to page 1's current url exists // assert hyperlink to page 1's current url exists
$links = HTTP::getLinksIn($page3->obj('Content')->forTemplate()); $links = HTTP::getLinksIn($page3->obj('Content')->forTemplate());
$this->assertContains(Director::baseURL().'page1/', $links, 'Assert hyperlink to page 1\'s current published url exists on page 3'); $this->assertContains(
Director::baseURL() . 'page1',
$links,
'Assert hyperlink to page 1\'s current published url exists on page 3'
);
// change page 1 url on draft // change page 1 url on draft
$page1->URLSegment = 'new-url-segment'; $page1->URLSegment = 'new-url-segment';
@ -195,39 +239,55 @@ class SiteTreeBacklinksTest extends SapphireTest
$page1->write(); $page1->write();
// assert page 3 on draft contains new page 1 url // assert page 3 on draft contains new page 1 url
$page3 = $this->objFromFixture('Page', 'page3'); $page3 = $this->objFromFixture(SiteTree::class, 'page3');
$links = HTTP::getLinksIn($page3->obj('Content')->forTemplate()); $links = HTTP::getLinksIn($page3->obj('Content')->forTemplate());
$this->assertContains(Director::baseURL().'new-url-segment/', $links, 'Assert hyperlink to page 1\'s current draft url exists on page 3'); $this->assertContains(
Director::baseURL() . 'new-url-segment',
$links,
'Assert hyperlink to page 1\'s current draft url exists on page 3'
);
// publish page 3 // publish page 3
$this->assertTrue($page3->publishRecursive()); $this->assertTrue($page3->publishRecursive());
// assert page 3 on published site contains old page 1 url // assert page 3 on published site contains old page 1 url
$page3live = Versioned::get_one_by_stage('Page', 'Live', '"SiteTree"."ID" = ' . $page3->ID); $page3live = Versioned::get_one_by_stage(SiteTree::class, 'Live', '"SiteTree"."ID" = ' . $page3->ID);
Versioned::set_stage(Versioned::LIVE); Versioned::set_stage(Versioned::LIVE);
$links = HTTP::getLinksIn($page3live->obj('Content')->forTemplate()); $links = HTTP::getLinksIn($page3live->obj('Content')->forTemplate());
$this->assertContains(Director::baseURL().'page1/', $links, 'Assert hyperlink to page 1\'s current published url exists on page 3'); $this->assertContains(
Director::baseURL() . 'page1',
$links,
'Assert hyperlink to page 1\'s current published url exists on page 3'
);
// publish page 1 // publish page 1
$this->assertTrue($page1->publishRecursive()); $this->assertTrue($page1->publishRecursive());
// assert page 3 on published site contains new page 1 url // assert page 3 on published site contains new page 1 url
$page3live = Versioned::get_one_by_stage('Page', 'Live', '"SiteTree"."ID" = ' . $page3->ID); $page3live = Versioned::get_one_by_stage(SiteTree::class, 'Live', '"SiteTree"."ID" = ' . $page3->ID);
$links = HTTP::getLinksIn($page3live->obj('Content')->forTemplate()); $links = HTTP::getLinksIn($page3live->obj('Content')->forTemplate());
$this->assertContains(Director::baseURL().'new-url-segment/', $links, 'Assert hyperlink to page 1\'s current published url exists on page 3'); $this->assertContains(
Director::baseURL() . 'new-url-segment',
$links,
'Assert hyperlink to page 1\'s current published url exists on page 3'
);
} }
public function testLinkTrackingOnExtraContentFields() public function testLinkTrackingOnExtraContentFields()
{ {
/** @var Page $page1 */ /** @var SiteTree $page1 */
$page1 = $this->objFromFixture('Page', 'page1'); $page1 = $this->objFromFixture(SiteTree::class, 'page1');
/** @var Page $page2 */ /** @var SiteTree $page2 */
$page2 = $this->objFromFixture('Page', 'page2'); $page2 = $this->objFromFixture(SiteTree::class, 'page2');
$page1->publishRecursive(); $page1->publishRecursive();
$page2->publishRecursive(); $page2->publishRecursive();
// assert backlink to page 2 doesn't exist // assert backlink to page 2 doesn't exist
$this->assertNotContains($page2->ID, $page1->BackLinkTracking()->column('ID'), 'Assert backlink to page 2 doesn\'t exist'); $this->assertNotContains(
$page2->ID,
$page1->BackLinkTracking()->column('ID'),
'Assert backlink to page 2 doesn\'t exist'
);
// add hyperlink to page 1 on page 2 // add hyperlink to page 1 on page 2
$page2->ExtraContent .= '<p><a href="[sitetree_link,id=' . $page1->ID . ']">Testing page 1 link</a></p>'; $page2->ExtraContent .= '<p><a href="[sitetree_link,id=' . $page1->ID . ']">Testing page 1 link</a></p>';
@ -238,23 +298,32 @@ class SiteTreeBacklinksTest extends SapphireTest
$this->assertContains($page2->ID, $page1->BackLinkTracking()->column('ID'), 'Assert backlink to page 2 exists'); $this->assertContains($page2->ID, $page1->BackLinkTracking()->column('ID'), 'Assert backlink to page 2 exists');
// update page1 url // update page1 url
$page1 = $this->objFromFixture('Page', 'page1'); $page1 = $this->objFromFixture(SiteTree::class, 'page1');
$page1->URLSegment = "page1-new-url"; $page1->URLSegment = "page1-new-url";
$page1->write(); $page1->write();
// confirm that draft link on page2 has been rewritten // confirm that draft link on page2 has been rewritten
$page2 = $this->objFromFixture('Page', 'page2'); $page2 = $this->objFromFixture(SiteTree::class, 'page2');
$this->assertEquals('<p><a href="'.Director::baseURL().'page1-new-url/">Testing page 1 link</a></p>', $page2->obj('ExtraContent')->forTemplate()); $this->assertEquals(
'<p><a href="' . Director::baseURL() . 'page1-new-url">Testing page 1 link</a></p>',
$page2->obj('ExtraContent')->forTemplate()
);
// confirm that published link hasn't // confirm that published link hasn't
$page2Live = Versioned::get_one_by_stage("Page", "Live", "\"SiteTree\".\"ID\" = $page2->ID"); $page2Live = Versioned::get_one_by_stage(SiteTree::class, "Live", "\"SiteTree\".\"ID\" = $page2->ID");
Versioned::set_stage(Versioned::LIVE); Versioned::set_stage(Versioned::LIVE);
$this->assertEquals('<p><a href="'.Director::baseURL().'page1/">Testing page 1 link</a></p>', $page2Live->obj('ExtraContent')->forTemplate()); $this->assertEquals(
'<p><a href="' . Director::baseURL() . 'page1">Testing page 1 link</a></p>',
$page2Live->obj('ExtraContent')->forTemplate()
);
// publish page1 and confirm that the link on the published page2 has now been updated // publish page1 and confirm that the link on the published page2 has now been updated
$page1->publishRecursive(); $page1->publishRecursive();
$page2Live = Versioned::get_one_by_stage("Page", "Live", "\"SiteTree\".\"ID\" = $page2->ID"); $page2Live = Versioned::get_one_by_stage(SiteTree::class, "Live", "\"SiteTree\".\"ID\" = $page2->ID");
$this->assertEquals('<p><a href="'.Director::baseURL().'page1-new-url/">Testing page 1 link</a></p>', $page2Live->obj('ExtraContent')->forTemplate()); $this->assertEquals(
'<p><a href="' . Director::baseURL() . 'page1-new-url">Testing page 1 link</a></p>',
$page2Live->obj('ExtraContent')->forTemplate()
);
// Edit draft again // Edit draft again
Versioned::set_stage(Versioned::DRAFT); Versioned::set_stage(Versioned::DRAFT);
@ -262,12 +331,16 @@ class SiteTreeBacklinksTest extends SapphireTest
$page2->write(); $page2->write();
// assert backlink to page 2 no longer exists // assert backlink to page 2 no longer exists
$this->assertNotContains($page2->ID, $page1->BackLinkTracking()->column('ID'), 'Assert backlink to page 2 has been removed'); $this->assertNotContains(
$page2->ID,
$page1->BackLinkTracking()->column('ID'),
'Assert backlink to page 2 has been removed'
);
} }
public function testLinkTrackingWithUntitledObjectsDisplaysAReadableIdentifier() public function testLinkTrackingWithUntitledObjectsDisplaysAReadableIdentifier()
{ {
$page = $this->objFromFixture('Page', 'page2'); $page = $this->objFromFixture(SiteTree::class, 'page2');
$referencingObject = new SiteTreeBacklinksTestContentObject(); $referencingObject = new SiteTreeBacklinksTestContentObject();
$referencingObject->Content = '<p><a href="[sitetree_link,id=' $referencingObject->Content = '<p><a href="[sitetree_link,id='

View File

@ -1,4 +1,4 @@
Page: SilverStripe\CMS\Model\SiteTree:
page1: page1:
Title: page1 Title: page1
URLSegment: page1 URLSegment: page1
@ -11,6 +11,6 @@ Page:
Title: page3 Title: page3
URLSegment: page3 URLSegment: page3
Content: '<p><a href="[sitetree_link,id=$page1.ID]">Testing page 1 link</a></p>' Content: '<p><a href="[sitetree_link,id=$page1.ID]">Testing page 1 link</a></p>'
LinkTracking: =>Page.page1 LinkTracking: =>SilverStripe\CMS\Model\SiteTree.page1

View File

@ -2,7 +2,6 @@
namespace SilverStripe\CMS\Tests\Model; namespace SilverStripe\CMS\Tests\Model;
use Page;
use Silverstripe\Assets\Dev\TestAssetStore; use Silverstripe\Assets\Dev\TestAssetStore;
use SilverStripe\CMS\Model\RedirectorPage; use SilverStripe\CMS\Model\RedirectorPage;
use SilverStripe\CMS\Model\SiteTree; use SilverStripe\CMS\Model\SiteTree;
@ -42,15 +41,15 @@ class SiteTreeBrokenLinksTest extends SapphireTest
public function testBrokenLinksBetweenPages() public function testBrokenLinksBetweenPages()
{ {
/** @var Page $obj */ /** @var SiteTree $obj */
$obj = $this->objFromFixture('Page', 'content'); $obj = $this->objFromFixture(SiteTree::class, 'content');
$obj->Content = '<a href="[sitetree_link,id=3423423]">this is a broken link</a>'; $obj->Content = '<a href="[sitetree_link,id=3423423]">this is a broken link</a>';
$obj->syncLinkTracking(); $obj->syncLinkTracking();
$this->assertTrue($obj->HasBrokenLink, 'Page has a broken link'); $this->assertTrue($obj->HasBrokenLink, 'Page has a broken link');
$obj->Content = '<a href="[sitetree_link,id=' . $this->idFromFixture( $obj->Content = '<a href="[sitetree_link,id=' . $this->idFromFixture(
'Page', SiteTree::class,
'about' 'about'
) . ']">this is not a broken link</a>'; ) . ']">this is not a broken link</a>';
$obj->syncLinkTracking(); $obj->syncLinkTracking();
@ -62,8 +61,8 @@ class SiteTreeBrokenLinksTest extends SapphireTest
*/ */
public function testBrokenLinksNonPage() public function testBrokenLinksNonPage()
{ {
/** @var Page $aboutPage */ /** @var SiteTree $aboutPage */
$aboutPage = $this->objFromFixture('Page', 'about'); $aboutPage = $this->objFromFixture(SiteTree::class, 'about');
/** @var NotPageObject $obj */ /** @var NotPageObject $obj */
$obj = $this->objFromFixture(NotPageObject::class, 'object1'); $obj = $this->objFromFixture(NotPageObject::class, 'object1');
@ -94,7 +93,7 @@ class SiteTreeBrokenLinksTest extends SapphireTest
// About-page backlinks contains this object // About-page backlinks contains this object
$this->assertListEquals( $this->assertListEquals(
[ [
['ID' => $obj->ID] ['ID' => $obj->ID],
], ],
$aboutPage->BackLinkTracking() $aboutPage->BackLinkTracking()
); );
@ -102,9 +101,9 @@ class SiteTreeBrokenLinksTest extends SapphireTest
public function testBrokenAnchorBetweenPages() public function testBrokenAnchorBetweenPages()
{ {
/** @var Page $obj */ /** @var SiteTree $obj */
$obj = $this->objFromFixture('Page', 'content'); $obj = $this->objFromFixture(SiteTree::class, 'content');
$target = $this->objFromFixture('Page', 'about'); $target = $this->objFromFixture(SiteTree::class, 'about');
$obj->Content = "<a href=\"[sitetree_link,id={$target->ID}]#no-anchor-here\">this is a broken link</a>"; $obj->Content = "<a href=\"[sitetree_link,id={$target->ID}]#no-anchor-here\">this is a broken link</a>";
$obj->syncLinkTracking(); $obj->syncLinkTracking();
@ -117,7 +116,7 @@ class SiteTreeBrokenLinksTest extends SapphireTest
public function testBrokenVirtualPages() public function testBrokenVirtualPages()
{ {
$obj = $this->objFromFixture('Page', 'content'); $obj = $this->objFromFixture(SiteTree::class, 'content');
$vp = new VirtualPage(); $vp = new VirtualPage();
$vp->CopyContentFromID = $obj->ID; $vp->CopyContentFromID = $obj->ID;
@ -131,7 +130,7 @@ class SiteTreeBrokenLinksTest extends SapphireTest
public function testBrokenInternalRedirectorPages() public function testBrokenInternalRedirectorPages()
{ {
$obj = $this->objFromFixture('Page', 'content'); $obj = $this->objFromFixture(SiteTree::class, 'content');
$rp = new RedirectorPage(); $rp = new RedirectorPage();
$rp->RedirectionType = 'Internal'; $rp->RedirectionType = 'Internal';
@ -148,10 +147,10 @@ class SiteTreeBrokenLinksTest extends SapphireTest
public function testDeletingMarksBackLinkedPagesAsBroken() public function testDeletingMarksBackLinkedPagesAsBroken()
{ {
// Set up two published pages with a link from content -> about // Set up two published pages with a link from content -> about
$linkDest = $this->objFromFixture('Page', 'about'); $linkDest = $this->objFromFixture(SiteTree::class, 'about');
/** @var Page $linkSrc */ /** @var SiteTree $linkSrc */
$linkSrc = $this->objFromFixture('Page', 'content'); $linkSrc = $this->objFromFixture(SiteTree::class, 'content');
$linkSrc->Content = "<p><a href=\"[sitetree_link,id=$linkDest->ID]\">about us</a></p>"; $linkSrc->Content = "<p><a href=\"[sitetree_link,id=$linkDest->ID]\">about us</a></p>";
$linkSrc->write(); $linkSrc->write();
@ -163,7 +162,7 @@ class SiteTreeBrokenLinksTest extends SapphireTest
// Confirm draft has broken link // Confirm draft has broken link
$linkSrc->flushCache(); $linkSrc->flushCache();
$linkSrc = $this->objFromFixture('Page', 'content'); $linkSrc = $this->objFromFixture(SiteTree::class, 'content');
$this->assertEquals(1, (int)$linkSrc->HasBrokenLink); $this->assertEquals(1, (int)$linkSrc->HasBrokenLink);
} }
@ -173,13 +172,13 @@ class SiteTreeBrokenLinksTest extends SapphireTest
$this->logInWithPermission('ADMIN'); $this->logInWithPermission('ADMIN');
// Set up two draft pages with a link from content -> about // Set up two draft pages with a link from content -> about
/** @var Page $linkDest */ /** @var SiteTree $linkDest */
$linkDest = $this->objFromFixture('Page', 'about'); $linkDest = $this->objFromFixture(SiteTree::class, 'about');
// Ensure that it's not on the published site // Ensure that it's not on the published site
$linkDest->doUnpublish(); $linkDest->doUnpublish();
/** @var Page $linkSrc */ /** @var SiteTree $linkSrc */
$linkSrc = $this->objFromFixture('Page', 'content'); $linkSrc = $this->objFromFixture(SiteTree::class, 'content');
$linkSrc->Content = "<p><a href=\"[sitetree_link,id=$linkDest->ID]\">about us</a></p>"; $linkSrc->Content = "<p><a href=\"[sitetree_link,id=$linkDest->ID]\">about us</a></p>";
$linkSrc->write(); $linkSrc->write();
@ -197,14 +196,14 @@ class SiteTreeBrokenLinksTest extends SapphireTest
public function testRestoreFixesBrokenLinks() public function testRestoreFixesBrokenLinks()
{ {
// Create page and virtual page // Create page and virtual page
$p = new Page(); $p = new SiteTree();
$p->Title = "source"; $p->Title = "source";
$p->write(); $p->write();
$pageID = $p->ID; $pageID = $p->ID;
$this->assertTrue($p->publishRecursive()); $this->assertTrue($p->publishRecursive());
// Content links are one kind of link to pages // Content links are one kind of link to pages
$p2 = new Page(); $p2 = new SiteTree();
$p2->Title = "regular link"; $p2->Title = "regular link";
$p2->Content = "<a href=\"[sitetree_link,id=$p->ID]\">test</a>"; $p2->Content = "<a href=\"[sitetree_link,id=$p->ID]\">test</a>";
$p2->write(); $p2->write();
@ -264,14 +263,14 @@ class SiteTreeBrokenLinksTest extends SapphireTest
public function testRevertToLiveFixesBrokenLinks() public function testRevertToLiveFixesBrokenLinks()
{ {
// Create page and virutal page // Create page and virutal page
$page = new Page(); $page = new SiteTree();
$page->Title = "source"; $page->Title = "source";
$page->write(); $page->write();
$pageID = $page->ID; $pageID = $page->ID;
$this->assertTrue($page->publishRecursive()); $this->assertTrue($page->publishRecursive());
// Content links are one kind of link to pages // Content links are one kind of link to pages
$page2 = new Page(); $page2 = new SiteTree();
$page2->Title = "regular link"; $page2->Title = "regular link";
$page2->Content = "<a href=\"[sitetree_link,id={$pageID}]\">test</a>"; $page2->Content = "<a href=\"[sitetree_link,id={$pageID}]\">test</a>";
$page2->write(); $page2->write();
@ -302,7 +301,7 @@ class SiteTreeBrokenLinksTest extends SapphireTest
$this->assertEquals(1, $redirectorPage->HasBrokenLink); $this->assertEquals(1, $redirectorPage->HasBrokenLink);
// Call doRevertToLive and confirm that broken links are restored // Call doRevertToLive and confirm that broken links are restored
/** @var Page $pageLive */ /** @var SiteTree $pageLive */
$pageLive = Versioned::get_one_by_stage(SiteTree::class, 'Live', '"SiteTree"."ID" = ' . $pageID); $pageLive = Versioned::get_one_by_stage(SiteTree::class, 'Live', '"SiteTree"."ID" = ' . $pageID);
$pageLive->doRevertToLive(); $pageLive->doRevertToLive();
@ -316,15 +315,17 @@ class SiteTreeBrokenLinksTest extends SapphireTest
public function testBrokenAnchorLinksInAPage() public function testBrokenAnchorLinksInAPage()
{ {
/** @var Page $obj */ /** @var SiteTree $obj */
$obj = $this->objFromFixture('Page', 'content'); $obj = $this->objFromFixture(SiteTree::class, 'content');
$origContent = $obj->Content; $origContent = $obj->Content;
$obj->Content = $origContent . '<a href="#no-anchor-here">this links to a non-existent in-page anchor or skiplink</a>'; $obj->Content = $origContent . '<a href="#no-anchor-here">this links to a non-existent in-page anchor or ' .
'skiplink</a>';
$obj->syncLinkTracking(); $obj->syncLinkTracking();
$this->assertTrue($obj->HasBrokenLink, 'Page has a broken anchor/skiplink'); $this->assertTrue($obj->HasBrokenLink, 'Page has a broken anchor/skiplink');
$obj->Content = $origContent . '<a href="#yes-anchor-here">this links to an existent in-page anchor/skiplink</a>'; $obj->Content = $origContent . '<a href="#yes-anchor-here">this links to an existent in-page ' .
'anchor/skiplink</a>';
$obj->syncLinkTracking(); $obj->syncLinkTracking();
$this->assertFalse($obj->HasBrokenLink, 'Page doesn\'t have a broken anchor or skiplink'); $this->assertFalse($obj->HasBrokenLink, 'Page doesn\'t have a broken anchor or skiplink');
} }

View File

@ -1,4 +1,4 @@
Page: SilverStripe\CMS\Model\SiteTree:
content: content:
Title: ContentPage Title: ContentPage
Content: 'This is some partially happy content. It has one missing a skiplink, but does have another <a name="yes-anchor-here">skiplink here</a>.' Content: 'This is some partially happy content. It has one missing a skiplink, but does have another <a name="yes-anchor-here">skiplink here</a>.'
@ -13,7 +13,7 @@ Page:
workingInternalRedirector: workingInternalRedirector:
RedirectionType: Internal RedirectionType: Internal
Title: RedirectorPageToBrokenInteralPage Title: RedirectorPageToBrokenInteralPage
LinkTo: =>Page.content LinkTo: =>SilverStripe\CMS\Model\SiteTree.content
SilverStripe\CMS\Tests\Model\SiteTreeBrokenLinksTest\NotPageObject: SilverStripe\CMS\Tests\Model\SiteTreeBrokenLinksTest\NotPageObject:
object1: object1:
Content: 'Everything will be ok' Content: 'Everything will be ok'

View File

@ -2,7 +2,6 @@
namespace SilverStripe\CMS\Tests\Model; namespace SilverStripe\CMS\Tests\Model;
use Page;
use SilverStripe\Assets\Dev\TestAssetStore; use SilverStripe\Assets\Dev\TestAssetStore;
use SilverStripe\Assets\File; use SilverStripe\Assets\File;
use SilverStripe\Assets\Filesystem; use SilverStripe\Assets\Filesystem;
@ -31,8 +30,8 @@ class SiteTreeHTMLEditorFieldTest extends FunctionalTest
} }
// Ensure all pages are published // Ensure all pages are published
/** @var Page $page */ /** @var SiteTree $page */
foreach (Page::get() as $page) { foreach (SiteTree::get() as $page) {
$page->publishSingle(); $page->publishSingle();
} }
} }
@ -55,7 +54,11 @@ class SiteTreeHTMLEditorFieldTest extends FunctionalTest
$editor->setValue("<a href=\"[sitetree_link,id=$aboutID]\">Example Link</a>"); $editor->setValue("<a href=\"[sitetree_link,id=$aboutID]\">Example Link</a>");
$editor->saveInto($sitetree); $editor->saveInto($sitetree);
$sitetree->write(); $sitetree->write();
$this->assertEquals([$aboutID => $aboutID], $sitetree->LinkTracking()->getIdList(), 'Basic link tracking works.'); $this->assertEquals(
[$aboutID => $aboutID],
$sitetree->LinkTracking()->getIdList(),
'Basic link tracking works.'
);
$editor->setValue( $editor->setValue(
"<a href=\"[sitetree_link,id=$aboutID]\"></a><a href=\"[sitetree_link,id=$contactID]\"></a>" "<a href=\"[sitetree_link,id=$aboutID]\"></a><a href=\"[sitetree_link,id=$contactID]\"></a>"

View File

@ -2,7 +2,6 @@
namespace SilverStripe\CMS\Tests\Model; namespace SilverStripe\CMS\Tests\Model;
use Page;
use SilverStripe\CMS\Model\SiteTree; use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\CMS\Model\SiteTreeLinkTracking_Parser; use SilverStripe\CMS\Model\SiteTreeLinkTracking_Parser;
use SilverStripe\Control\Director; use SilverStripe\Control\Director;
@ -32,7 +31,7 @@ class SiteTreeLinkTrackingTest extends SapphireTest
public function testParser() public function testParser()
{ {
SiteTree::add_extension(Page::class, SiteTreeLinkTracking_Extension::class); SiteTree::add_extension(SiteTree::class, SiteTreeLinkTracking_Extension::class);
// Shortcodes // Shortcodes
$this->assertTrue($this->isBroken('<a href="[sitetree_link,id=123]">link</a>')); $this->assertTrue($this->isBroken('<a href="[sitetree_link,id=123]">link</a>'));
@ -55,8 +54,7 @@ class SiteTreeLinkTrackingTest extends SapphireTest
$this->assertFalse($this->isBroken('<a id="anchor">anchor</a>')); $this->assertFalse($this->isBroken('<a id="anchor">anchor</a>'));
$this->assertTrue($this->isBroken('<a href="##anchor">anchor</a>')); $this->assertTrue($this->isBroken('<a href="##anchor">anchor</a>'));
$page = new SiteTree();
$page = new Page();
$page->Content = '<a name="yes-name-anchor">name</a><a id="yes-id-anchor">id</a>'; $page->Content = '<a name="yes-name-anchor">name</a><a id="yes-id-anchor">id</a>';
$page->write(); $page->write();
@ -72,7 +70,7 @@ class SiteTreeLinkTrackingTest extends SapphireTest
protected function highlight($content) protected function highlight($content)
{ {
$page = new Page(); $page = new SiteTree();
$page->Content = $content; $page->Content = $content;
$page->write(); $page->write();
return $page->Content; return $page->Content;
@ -87,7 +85,7 @@ class SiteTreeLinkTrackingTest extends SapphireTest
$content = $this->highlight('<a href="[sitetree_link,id=123]">link</a>'); $content = $this->highlight('<a href="[sitetree_link,id=123]">link</a>');
$this->assertEquals(substr_count($content ?? '', 'ss-broken'), 1, 'ss-broken class is added to the broken link.'); $this->assertEquals(substr_count($content ?? '', 'ss-broken'), 1, 'ss-broken class is added to the broken link.');
$otherPage = new Page(); $otherPage = new SiteTree();
$otherPage->Content = ''; $otherPage->Content = '';
$otherPage->write(); $otherPage->write();

View File

@ -2,7 +2,6 @@
namespace SilverStripe\CMS\Tests\Model; namespace SilverStripe\CMS\Tests\Model;
use Page;
use SilverStripe\CMS\Model\SiteTree; use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\Control\HTTPResponse_Exception; use SilverStripe\Control\HTTPResponse_Exception;
use SilverStripe\Dev\FunctionalTest; use SilverStripe\Dev\FunctionalTest;
@ -13,10 +12,6 @@ use SilverStripe\SiteConfig\SiteConfig;
use SilverStripe\Subsites\Extensions\SiteTreeSubsites; use SilverStripe\Subsites\Extensions\SiteTreeSubsites;
use SilverStripe\Versioned\Versioned; use SilverStripe\Versioned\Versioned;
/**
* @todo Test canAddChildren()
* @todo Test canCreate()
*/
class SiteTreePermissionsTest extends FunctionalTest class SiteTreePermissionsTest extends FunctionalTest
{ {
protected static $fixture_file = "SiteTreePermissionsTest.yml"; protected static $fixture_file = "SiteTreePermissionsTest.yml";
@ -33,8 +28,8 @@ class SiteTreePermissionsTest extends FunctionalTest
$this->autoFollowRedirection = false; $this->autoFollowRedirection = false;
// Ensure all pages are published // Ensure all pages are published
/** @var Page $page */ /** @var SiteTree $page */
foreach (Page::get() as $page) { foreach (SiteTree::get() as $page) {
if ($page->URLSegment !== 'draft-only') { if ($page->URLSegment !== 'draft-only') {
$page->publishSingle(); $page->publishSingle();
} }
@ -46,8 +41,8 @@ class SiteTreePermissionsTest extends FunctionalTest
{ {
$this->autoFollowRedirection = false; $this->autoFollowRedirection = false;
/** @var Page $draftOnlyPage */ /** @var SiteTree $draftOnlyPage */
$draftOnlyPage = $this->objFromFixture(Page::class, 'draftOnlyPage'); $draftOnlyPage = $this->objFromFixture(SiteTree::class, 'draftOnlyPage');
$this->logOut(); $this->logOut();
$response = $this->get($draftOnlyPage->URLSegment . '?stage=Live'); $response = $this->get($draftOnlyPage->URLSegment . '?stage=Live');
@ -85,7 +80,7 @@ class SiteTreePermissionsTest extends FunctionalTest
{ {
// Set up fixture - a published page deleted from draft // Set up fixture - a published page deleted from draft
$this->logInWithPermission("ADMIN"); $this->logInWithPermission("ADMIN");
$page = $this->objFromFixture(Page::class, 'restrictedEditOnlySubadminGroup'); $page = $this->objFromFixture(SiteTree::class, 'restrictedEditOnlySubadminGroup');
$pageID = $page->ID; $pageID = $page->ID;
$this->assertTrue($page->publishRecursive()); $this->assertTrue($page->publishRecursive());
$page->delete(); $page->delete();
@ -112,7 +107,7 @@ class SiteTreePermissionsTest extends FunctionalTest
{ {
// Set up fixture - an unpublished page // Set up fixture - an unpublished page
$this->logInWithPermission("ADMIN"); $this->logInWithPermission("ADMIN");
$page = $this->objFromFixture(Page::class, 'restrictedEditOnlySubadminGroup'); $page = $this->objFromFixture(SiteTree::class, 'restrictedEditOnlySubadminGroup');
$pageID = $page->ID; $pageID = $page->ID;
$page->doUnpublish(); $page->doUnpublish();
@ -135,7 +130,7 @@ class SiteTreePermissionsTest extends FunctionalTest
{ {
// Find a page that exists and delete it from both stage and published // Find a page that exists and delete it from both stage and published
$this->logInWithPermission("ADMIN"); $this->logInWithPermission("ADMIN");
$page = $this->objFromFixture(Page::class, 'restrictedEditOnlySubadminGroup'); $page = $this->objFromFixture(SiteTree::class, 'restrictedEditOnlySubadminGroup');
$pageID = $page->ID; $pageID = $page->ID;
$page->doUnpublish(); $page->doUnpublish();
$page->delete(); $page->delete();
@ -153,8 +148,8 @@ class SiteTreePermissionsTest extends FunctionalTest
public function testCanViewStage() public function testCanViewStage()
{ {
// Get page & make sure it exists on Live // Get page & make sure it exists on Live
/** @var Page $page */ /** @var SiteTree $page */
$page = $this->objFromFixture(Page::class, 'standardpage'); $page = $this->objFromFixture(SiteTree::class, 'standardpage');
$page->publishSingle(); $page->publishSingle();
// Then make sure there's a new version on Stage // Then make sure there's a new version on Stage
@ -173,7 +168,7 @@ class SiteTreePermissionsTest extends FunctionalTest
public function testAccessTabOnlyDisplaysWithGrantAccessPermissions() public function testAccessTabOnlyDisplaysWithGrantAccessPermissions()
{ {
$page = $this->objFromFixture(Page::class, 'standardpage'); $page = $this->objFromFixture(SiteTree::class, 'standardpage');
$subadminuser = $this->objFromFixture(Member::class, 'subadmin'); $subadminuser = $this->objFromFixture(Member::class, 'subadmin');
Security::setCurrentUser($subadminuser); Security::setCurrentUser($subadminuser);
@ -204,7 +199,7 @@ class SiteTreePermissionsTest extends FunctionalTest
public function testRestrictedViewLoggedInUsers() public function testRestrictedViewLoggedInUsers()
{ {
$page = $this->objFromFixture(Page::class, 'restrictedViewLoggedInUsers'); $page = $this->objFromFixture(SiteTree::class, 'restrictedViewLoggedInUsers');
// unauthenticated users // unauthenticated users
$this->assertFalse( $this->assertFalse(
@ -223,21 +218,23 @@ class SiteTreePermissionsTest extends FunctionalTest
$websiteuser = $this->objFromFixture(Member::class, 'websiteuser'); $websiteuser = $this->objFromFixture(Member::class, 'websiteuser');
$this->assertTrue( $this->assertTrue(
$page->canView($websiteuser), $page->canView($websiteuser),
'Authenticated members can view a page marked as "Viewable for any logged in users" even if they dont have access to the CMS' 'Authenticated members can view a page marked as "Viewable for any logged in users" even if they dont ' .
'have access to the CMS'
); );
$this->logInAs($websiteuser); $this->logInAs($websiteuser);
$response = $this->get($page->RelativeLink()); $response = $this->get($page->RelativeLink());
$this->assertEquals( $this->assertEquals(
$response->getStatusCode(), $response->getStatusCode(),
200, 200,
'Authenticated members can view a page marked as "Viewable for any logged in users" even if they dont have access to the CMS' 'Authenticated members can view a page marked as "Viewable for any logged in users" even if they dont ' .
'have access to the CMS'
); );
$this->logOut(); $this->logOut();
} }
public function testRestrictedViewOnlyTheseUsers() public function testRestrictedViewOnlyTheseUsers()
{ {
$page = $this->objFromFixture(Page::class, 'restrictedViewOnlyWebsiteUsers'); $page = $this->objFromFixture(SiteTree::class, 'restrictedViewOnlyWebsiteUsers');
// unauthenticcated users // unauthenticcated users
$this->assertFalse( $this->assertFalse(
@ -256,14 +253,16 @@ class SiteTreePermissionsTest extends FunctionalTest
$subadminuser = $this->objFromFixture(Member::class, 'subadmin'); $subadminuser = $this->objFromFixture(Member::class, 'subadmin');
$this->assertFalse( $this->assertFalse(
$page->canView($subadminuser), $page->canView($subadminuser),
'Authenticated members cant view a page marked as "Viewable by these groups" if theyre not in the listed groups' 'Authenticated members cant view a page marked as "Viewable by these groups" if theyre not in the listed ' .
'groups'
); );
$this->LogInAs($subadminuser); $this->LogInAs($subadminuser);
$response = $this->get($page->RelativeLink()); $response = $this->get($page->RelativeLink());
$this->assertEquals( $this->assertEquals(
$response->getStatusCode(), $response->getStatusCode(),
403, 403,
'Authenticated members cant view a page marked as "Viewable by these groups" if theyre not in the listed groups' 'Authenticated members cant view a page marked as "Viewable by these groups" if theyre not in the listed ' .
'groups'
); );
$this->logOut(); $this->logOut();
@ -285,7 +284,7 @@ class SiteTreePermissionsTest extends FunctionalTest
public function testRestrictedEditLoggedInUsers() public function testRestrictedEditLoggedInUsers()
{ {
$page = $this->objFromFixture(Page::class, 'restrictedEditLoggedInUsers'); $page = $this->objFromFixture(SiteTree::class, 'restrictedEditLoggedInUsers');
// unauthenticcated users // unauthenticcated users
$this->assertFalse( $this->assertFalse(
@ -298,20 +297,22 @@ class SiteTreePermissionsTest extends FunctionalTest
Security::setCurrentUser($websiteuser); Security::setCurrentUser($websiteuser);
$this->assertFalse( $this->assertFalse(
$page->canEdit($websiteuser), $page->canEdit($websiteuser),
'Authenticated members cant edit a page marked as "Editable by logged in users" if they dont have cms permissions' 'Authenticated members cant edit a page marked as "Editable by logged in users" if they dont have cms ' .
'permissions'
); );
// subadmin users // subadmin users
$subadminuser = $this->objFromFixture(Member::class, 'subadmin'); $subadminuser = $this->objFromFixture(Member::class, 'subadmin');
$this->assertTrue( $this->assertTrue(
$page->canEdit($subadminuser), $page->canEdit($subadminuser),
'Authenticated members can edit a page marked as "Editable by logged in users" if they have cms permissions and belong to any of these groups' 'Authenticated members can edit a page marked as "Editable by logged in users" if they have cms ' .
'permissions and belong to any of these groups'
); );
} }
public function testRestrictedEditOnlySubadminGroup() public function testRestrictedEditOnlySubadminGroup()
{ {
$page = $this->objFromFixture(Page::class, 'restrictedEditOnlySubadminGroup'); $page = $this->objFromFixture(SiteTree::class, 'restrictedEditOnlySubadminGroup');
// unauthenticated users // unauthenticated users
$this->assertFalse( $this->assertFalse(
@ -330,14 +331,15 @@ class SiteTreePermissionsTest extends FunctionalTest
$websiteuser = $this->objFromFixture(Member::class, 'websiteuser'); $websiteuser = $this->objFromFixture(Member::class, 'websiteuser');
$this->assertFalse( $this->assertFalse(
$page->canEdit($websiteuser), $page->canEdit($websiteuser),
'Authenticated members cant edit a page marked as "Editable by these groups" if theyre not in the listed groups' 'Authenticated members cant edit a page marked as "Editable by these groups" if theyre not in the listed ' .
'groups'
); );
} }
public function testRestrictedViewInheritance() public function testRestrictedViewInheritance()
{ {
$parentPage = $this->objFromFixture(Page::class, 'parent_restrictedViewOnlySubadminGroup'); $parentPage = $this->objFromFixture(SiteTree::class, 'parent_restrictedViewOnlySubadminGroup');
$childPage = $this->objFromFixture(Page::class, 'child_restrictedViewOnlySubadminGroup'); $childPage = $this->objFromFixture(SiteTree::class, 'child_restrictedViewOnlySubadminGroup');
// unauthenticated users // unauthenticated users
$this->assertFalse( $this->assertFalse(
@ -356,22 +358,24 @@ class SiteTreePermissionsTest extends FunctionalTest
$subadminuser = $this->objFromFixture(Member::class, 'subadmin'); $subadminuser = $this->objFromFixture(Member::class, 'subadmin');
$this->assertTrue( $this->assertTrue(
$childPage->canView($subadminuser), $childPage->canView($subadminuser),
'Authenticated members can view a page marked as "Viewable by these groups" if theyre in the listed groups by inherited permission' 'Authenticated members can view a page marked as "Viewable by these groups" if theyre in the listed ' .
'groups by inherited permission'
); );
$this->logInAs($subadminuser); $this->logInAs($subadminuser);
$response = $this->get($childPage->RelativeLink()); $response = $this->get($childPage->RelativeLink());
$this->assertEquals( $this->assertEquals(
$response->getStatusCode(), $response->getStatusCode(),
200, 200,
'Authenticated members can view a page marked as "Viewable by these groups" if theyre in the listed groups by inherited permission' 'Authenticated members can view a page marked as "Viewable by these groups" if theyre in the listed ' .
'groups by inherited permission'
); );
$this->logOut(); $this->logOut();
} }
public function testRestrictedEditInheritance() public function testRestrictedEditInheritance()
{ {
$parentPage = $this->objFromFixture(Page::class, 'parent_restrictedEditOnlySubadminGroup'); $parentPage = $this->objFromFixture(SiteTree::class, 'parent_restrictedEditOnlySubadminGroup');
$childPage = $this->objFromFixture(Page::class, 'child_restrictedEditOnlySubadminGroup'); $childPage = $this->objFromFixture(SiteTree::class, 'child_restrictedEditOnlySubadminGroup');
// unauthenticated users // unauthenticated users
$this->assertFalse( $this->assertFalse(
@ -383,14 +387,15 @@ class SiteTreePermissionsTest extends FunctionalTest
$subadminuser = $this->objFromFixture(Member::class, 'subadmin'); $subadminuser = $this->objFromFixture(Member::class, 'subadmin');
$this->assertTrue( $this->assertTrue(
$childPage->canEdit($subadminuser), $childPage->canEdit($subadminuser),
'Authenticated members can edit a page marked as "Editable by these groups" if theyre in the listed groups by inherited permission' 'Authenticated members can edit a page marked as "Editable by these groups" if theyre in the listed ' .
'groups by inherited permission'
); );
} }
public function testDeleteRestrictedChild() public function testDeleteRestrictedChild()
{ {
$parentPage = $this->objFromFixture(Page::class, 'deleteTestParentPage'); $parentPage = $this->objFromFixture(SiteTree::class, 'deleteTestParentPage');
$childPage = $this->objFromFixture(Page::class, 'deleteTestChildPage'); $childPage = $this->objFromFixture(SiteTree::class, 'deleteTestChildPage');
// unauthenticated users // unauthenticated users
$this->assertFalse( $this->assertFalse(
@ -405,7 +410,7 @@ class SiteTreePermissionsTest extends FunctionalTest
public function testRestrictedEditLoggedInUsersDeletedFromStage() public function testRestrictedEditLoggedInUsersDeletedFromStage()
{ {
$page = $this->objFromFixture(Page::class, 'restrictedEditLoggedInUsers'); $page = $this->objFromFixture(SiteTree::class, 'restrictedEditLoggedInUsers');
$pageID = $page->ID; $pageID = $page->ID;
$this->logInWithPermission("ADMIN"); $this->logInWithPermission("ADMIN");
@ -421,39 +426,60 @@ class SiteTreePermissionsTest extends FunctionalTest
$subadminuser = $this->objFromFixture(Member::class, 'subadmin'); $subadminuser = $this->objFromFixture(Member::class, 'subadmin');
$this->assertTrue( $this->assertTrue(
$page->canEdit($subadminuser), $page->canEdit($subadminuser),
'Authenticated members can edit a page that was deleted from stage and marked as "Editable by logged in users" if they have cms permissions and belong to any of these groups' 'Authenticated members can edit a page that was deleted from stage and marked as "Editable by logged ' .
'in users" if they have cms permissions and belong to any of these groups'
); );
} }
public function testInheritCanViewFromSiteConfig() public function testInheritCanViewFromSiteConfig()
{ {
$page = $this->objFromFixture(Page::class, 'inheritWithNoParent'); $page = $this->objFromFixture(SiteTree::class, 'inheritWithNoParent');
$siteconfig = $this->objFromFixture(SiteConfig::class, 'default'); $siteconfig = $this->objFromFixture(SiteConfig::class, 'default');
$editor = $this->objFromFixture(Member::class, 'editor'); $editor = $this->objFromFixture(Member::class, 'editor');
$editorGroup = $this->objFromFixture(Group::class, 'editorgroup'); $editorGroup = $this->objFromFixture(Group::class, 'editorgroup');
$siteconfig->CanViewType = 'Anyone'; $siteconfig->CanViewType = 'Anyone';
$siteconfig->write(); $siteconfig->write();
$this->assertTrue($page->canView(false), 'Anyone can view a page when set to inherit from the SiteConfig, and SiteConfig has canView set to LoggedInUsers'); $this->assertTrue(
$page->canView(false),
'Anyone can view a page when set to inherit from the SiteConfig, and SiteConfig has canView set to ' .
'LoggedInUsers'
);
$siteconfig->CanViewType = 'LoggedInUsers'; $siteconfig->CanViewType = 'LoggedInUsers';
$siteconfig->write(); $siteconfig->write();
$this->assertFalse($page->canView(false), 'Anonymous can\'t view a page when set to inherit from the SiteConfig, and SiteConfig has canView set to LoggedInUsers'); $this->assertFalse(
$page->canView(false),
'Anonymous can\'t view a page when set to inherit from the SiteConfig, and SiteConfig has canView set to ' .
'LoggedInUsers'
);
$siteconfig->CanViewType = 'LoggedInUsers'; $siteconfig->CanViewType = 'LoggedInUsers';
$siteconfig->write(); $siteconfig->write();
$this->assertTrue($page->canView($editor), 'Users can view a page when set to inherit from the SiteConfig, and SiteConfig has canView set to LoggedInUsers'); $this->assertTrue(
$page->canView($editor),
'Users can view a page when set to inherit from the SiteConfig, and SiteConfig has canView set to ' .
'LoggedInUsers'
);
$siteconfig->CanViewType = 'OnlyTheseUsers'; $siteconfig->CanViewType = 'OnlyTheseUsers';
$siteconfig->ViewerGroups()->add($editorGroup); $siteconfig->ViewerGroups()->add($editorGroup);
$siteconfig->write(); $siteconfig->write();
$this->assertTrue($page->canView($editor), 'Editors can view a page when set to inherit from the SiteConfig, and SiteConfig has canView set to OnlyTheseUsers'); $this->assertTrue(
$this->assertFalse($page->canView(false), 'Anonymous can\'t view a page when set to inherit from the SiteConfig, and SiteConfig has canView set to OnlyTheseUsers'); $page->canView($editor),
'Editors can view a page when set to inherit from the SiteConfig, and SiteConfig has canView set to ' .
'OnlyTheseUsers'
);
$this->assertFalse(
$page->canView(false),
'Anonymous can\'t view a page when set to inherit from the SiteConfig, and SiteConfig has canView set ' .
'to OnlyTheseUsers'
);
} }
public function testInheritCanEditFromSiteConfig() public function testInheritCanEditFromSiteConfig()
{ {
$page = $this->objFromFixture(Page::class, 'inheritWithNoParent'); $page = $this->objFromFixture(SiteTree::class, 'inheritWithNoParent');
$siteconfig = $this->objFromFixture(SiteConfig::class, 'default'); $siteconfig = $this->objFromFixture(SiteConfig::class, 'default');
$editor = $this->objFromFixture(Member::class, 'editor'); $editor = $this->objFromFixture(Member::class, 'editor');
$user = $this->objFromFixture(Member::class, 'websiteuser'); $user = $this->objFromFixture(Member::class, 'websiteuser');
@ -462,17 +488,99 @@ class SiteTreePermissionsTest extends FunctionalTest
$siteconfig->CanEditType = 'LoggedInUsers'; $siteconfig->CanEditType = 'LoggedInUsers';
$siteconfig->write(); $siteconfig->write();
$this->assertFalse($page->canEdit(false), 'Anonymous can\'t edit a page when set to inherit from the SiteConfig, and SiteConfig has canEdit set to LoggedInUsers'); $this->assertFalse(
$page->canEdit(false),
'Anonymous can\'t edit a page when set to inherit from the SiteConfig, and SiteConfig has canEdit set ' .
'to LoggedInUsers'
);
Security::setCurrentUser($editor); Security::setCurrentUser($editor);
$this->assertTrue($page->canEdit(), 'Users can edit a page when set to inherit from the SiteConfig, and SiteConfig has canEdit set to LoggedInUsers'); $this->assertTrue(
$page->canEdit(),
'Users can edit a page when set to inherit from the SiteConfig, and SiteConfig has canEdit set to ' .
'LoggedInUsers'
);
$siteconfig->CanEditType = 'OnlyTheseUsers'; $siteconfig->CanEditType = 'OnlyTheseUsers';
$siteconfig->EditorGroups()->add($editorGroup); $siteconfig->EditorGroups()->add($editorGroup);
$siteconfig->write(); $siteconfig->write();
$this->assertTrue($page->canEdit($editor), 'Editors can edit a page when set to inherit from the SiteConfig, and SiteConfig has canEdit set to OnlyTheseUsers'); $this->assertTrue(
$page->canEdit($editor),
'Editors can edit a page when set to inherit from the SiteConfig, and SiteConfig has canEdit set to ' .
'OnlyTheseUsers'
);
Security::setCurrentUser(null); Security::setCurrentUser(null);
$this->assertFalse($page->canEdit(false), 'Anonymous can\'t edit a page when set to inherit from the SiteConfig, and SiteConfig has canEdit set to OnlyTheseUsers'); $this->assertFalse(
$page->canEdit(false),
'Anonymous can\'t edit a page when set to inherit from the SiteConfig, and SiteConfig has canEdit set ' .
'to OnlyTheseUsers'
);
Security::setCurrentUser($user); Security::setCurrentUser($user);
$this->assertFalse($page->canEdit($user), 'Website user can\'t edit a page when set to inherit from the SiteConfig, and SiteConfig has canEdit set to OnlyTheseUsers'); $this->assertFalse(
$page->canEdit($user),
'Website user can\'t edit a page when set to inherit from the SiteConfig, and SiteConfig has canEdit set ' .
'to OnlyTheseUsers'
);
}
/**
* Test permissions on duplicate page
* @dataProvider groupWithPermissions
*/
public function testDuplicatePageWithGroupPermissions(string $userName, string $method, bool $expected)
{
$originalPage = $this->objFromFixture(SiteTree::class, 'originalpage');
$user = $this->objFromFixture(Member::class, $userName);
$dupe = $originalPage->duplicate();
$this->assertEquals($originalPage->Title, $dupe->Title);
$this->assertEquals($dupe->CanViewType, 'OnlyTheseUsers');
$this->assertEquals($dupe->CanEditType, 'OnlyTheseUsers');
$this->assertSame($dupe->{$method}($user), $expected);
}
public function groupWithPermissions(): array
{
return [
'Subadmin can view page duplicate.' => [
'subadmin',
'canView',
true,
],
'Subadmin can edit page duplicate.' => [
'subadmin',
'canEdit',
true,
],
'Editor can view page duplicate.' => [
'editor',
'canView',
true,
],
'Editor can edit page duplicate.' => [
'editor',
'canEdit',
true,
],
'User with "allsections" permission can view page duplicate.' => [
'allsections',
'canView',
true,
],
'User with "allsections" permission cannot edit page duplicate.' => [
'allsections',
'canEdit',
false,
],
'Websiteuser permission cannot view page duplicate.' => [
'websiteuser',
'canView',
false,
],
'Websiteuser permission cannot edit page duplicate.' => [
'websiteuser',
'canEdit',
false,
],
];
} }
} }

View File

@ -11,6 +11,8 @@ SilverStripe\Security\Permission:
Code: CMS_ACCESS_CMSMain Code: CMS_ACCESS_CMSMain
grantaccess: grantaccess:
Code: SITETREE_GRANT_ACCESS Code: SITETREE_GRANT_ACCESS
allsections:
Code: CMS_ACCESS_LeftAndMain
SilverStripe\Security\Group: SilverStripe\Security\Group:
subadmingroup: subadmingroup:
Title: Create, edit and delete pages Title: Create, edit and delete pages
@ -20,6 +22,9 @@ SilverStripe\Security\Group:
Title: Edit existing pages Title: Edit existing pages
Code: editorgroup Code: editorgroup
Permissions: =>SilverStripe\Security\Permission.cmsmain2 Permissions: =>SilverStripe\Security\Permission.cmsmain2
allsectionsgroup:
Title: All Section Editors
Permissions: =>SilverStripe\Security\Permission.allsections
websiteusers: websiteusers:
Title: View certain restricted pages Title: View certain restricted pages
SilverStripe\Security\Member: SilverStripe\Security\Member:
@ -31,11 +36,15 @@ SilverStripe\Security\Member:
Email: editor@test.com Email: editor@test.com
Password: test Password: test
Groups: =>SilverStripe\Security\Group.editorgroup Groups: =>SilverStripe\Security\Group.editorgroup
allsections:
Email: allsections@test.com
Password: test
Groups: =>SilverStripe\Security\Group.allsectionsgroup
websiteuser: websiteuser:
Email: websiteuser@test.com Email: websiteuser@test.com
Password: test Password: test
Groups: =>SilverStripe\Security\Group.websiteusers Groups: =>SilverStripe\Security\Group.websiteusers
Page: SilverStripe\CMS\Model\SiteTree:
standardpage: standardpage:
URLSegment: standardpage URLSegment: standardpage
restrictedViewLoggedInUsers: restrictedViewLoggedInUsers:
@ -66,7 +75,7 @@ Page:
URLSegment: parent-restrictedViewOnlySubadminGroup URLSegment: parent-restrictedViewOnlySubadminGroup
child_restrictedViewOnlySubadminGroup: child_restrictedViewOnlySubadminGroup:
CanViewType: Inherit CanViewType: Inherit
Parent: =>Page.parent_restrictedViewOnlySubadminGroup Parent: =>SilverStripe\CMS\Model\SiteTree.parent_restrictedViewOnlySubadminGroup
URLSegment: child-restrictedViewOnlySubadminGroup URLSegment: child-restrictedViewOnlySubadminGroup
parent_restrictedEditOnlySubadminGroup: parent_restrictedEditOnlySubadminGroup:
CanEditType: OnlyTheseUsers CanEditType: OnlyTheseUsers
@ -74,7 +83,7 @@ Page:
URLSegment: parent-restrictedEditOnlySubadminGroup URLSegment: parent-restrictedEditOnlySubadminGroup
child_restrictedEditOnlySubadminGroup: child_restrictedEditOnlySubadminGroup:
CanEditType: Inherit CanEditType: Inherit
Parent: =>Page.parent_restrictedEditOnlySubadminGroup Parent: =>SilverStripe\CMS\Model\SiteTree.parent_restrictedEditOnlySubadminGroup
URLSegment: child-restrictedEditOnlySubadminGroup URLSegment: child-restrictedEditOnlySubadminGroup
deleteTestParentPage: deleteTestParentPage:
CanEditType: Inherit CanEditType: Inherit
@ -86,3 +95,9 @@ Page:
draftOnlyPage: draftOnlyPage:
CanViewType: Anyone CanViewType: Anyone
URLSegment: draft-only URLSegment: draft-only
originalpage:
Title: Original Page for duplicate
CanEditType: OnlyTheseUsers
CanViewType: OnlyTheseUsers
EditorGroups: =>SilverStripe\Security\Group.subadmingroup,=>SilverStripe\Security\Group.editorgroup
ViewerGroups: =>SilverStripe\Security\Group.subadmingroup,=>SilverStripe\Security\Group.editorgroup,=>SilverStripe\Security\Group.allsectionsgroup

View File

@ -3,7 +3,6 @@
namespace SilverStripe\CMS\Tests\Model; namespace SilverStripe\CMS\Tests\Model;
use LogicException; use LogicException;
use Page;
use Psr\SimpleCache\CacheInterface; use Psr\SimpleCache\CacheInterface;
use ReflectionMethod; use ReflectionMethod;
use SilverStripe\CMS\Model\RedirectorPage; use SilverStripe\CMS\Model\RedirectorPage;
@ -34,16 +33,15 @@ use SilverStripe\Security\Security;
use SilverStripe\SiteConfig\SiteConfig; use SilverStripe\SiteConfig\SiteConfig;
use SilverStripe\Subsites\Extensions\SiteTreeSubsites; use SilverStripe\Subsites\Extensions\SiteTreeSubsites;
use SilverStripe\Versioned\Versioned; use SilverStripe\Versioned\Versioned;
use SilverStripe\View\Parsers\Diff; use SilverStripe\View\Parsers\HtmlDiff;
use SilverStripe\View\Parsers\ShortcodeParser; use SilverStripe\View\Parsers\ShortcodeParser;
use SilverStripe\View\Parsers\URLSegmentFilter; use SilverStripe\View\Parsers\URLSegmentFilter;
use SilverStripe\View\Shortcodes\EmbedShortcodeProvider; use SilverStripe\View\Shortcodes\EmbedShortcodeProvider;
use TractorCow\Fluent\Extension\FluentSiteTreeExtension; use TractorCow\Fluent\Extension\FluentSiteTreeExtension;
use Page;
use PageController;
use const RESOURCES_DIR; use const RESOURCES_DIR;
use SilverStripe\Dev\Deprecation;
use SilverStripe\HTML5\HTML5Value;
use SilverStripe\View\Parsers\HTMLValue;
use SilverStripe\View\Parsers\HTML4Value;
class SiteTreeTest extends SapphireTest class SiteTreeTest extends SapphireTest
{ {
@ -137,7 +135,7 @@ class SiteTreeTest extends SapphireTest
]; ];
foreach ($expectedURLs as $fixture => $urlSegment) { foreach ($expectedURLs as $fixture => $urlSegment) {
$obj = $this->objFromFixture('Page', $fixture); $obj = $this->objFromFixture(SiteTree::class, $fixture);
$this->assertEquals($urlSegment, $obj->URLSegment); $this->assertEquals($urlSegment, $obj->URLSegment);
} }
} }
@ -148,9 +146,9 @@ class SiteTreeTest extends SapphireTest
*/ */
public function testDisallowedURLGeneration($title, $urlSegment) public function testDisallowedURLGeneration($title, $urlSegment)
{ {
$page = Page::create(['Title' => $title]); $page = new SiteTree(['Title' => $title]);
$id = $page->write(); $id = $page->write();
$page = Page::get()->byID($id); $page = SiteTree::get()->byID($id);
$this->assertEquals($urlSegment, $page->URLSegment); $this->assertEquals($urlSegment, $page->URLSegment);
} }
@ -163,9 +161,9 @@ class SiteTreeTest extends SapphireTest
{ {
// Using the same dataprovider, strip out the -2 from the admin and dev segment // Using the same dataprovider, strip out the -2 from the admin and dev segment
$urlSegment = str_replace('-2', '', $urlSegment ?? ''); $urlSegment = str_replace('-2', '', $urlSegment ?? '');
$page = Page::create(['Title' => $title, 'ParentID' => 1]); $page = new SiteTree(['Title' => $title, 'ParentID' => 1]);
$id = $page->write(); $id = $page->write();
$page = Page::get()->byID($id); $page = SiteTree::get()->byID($id);
$this->assertEquals($urlSegment, $page->URLSegment); $this->assertEquals($urlSegment, $page->URLSegment);
} }
@ -180,7 +178,7 @@ class SiteTreeTest extends SapphireTest
$this->markTestSkipped('This legacy test requires RESOURCES_DIR to be "resources"'); $this->markTestSkipped('This legacy test requires RESOURCES_DIR to be "resources"');
} }
$page = SiteTree::create(['Title' => 'Resources']); $page = new SiteTree(['Title' => 'Resources']);
$id = $page->write(); $id = $page->write();
$page = SiteTree::get()->byID($id); $page = SiteTree::get()->byID($id);
$this->assertSame('resources-2', $page->URLSegment); $this->assertSame('resources-2', $page->URLSegment);
@ -198,7 +196,7 @@ class SiteTreeTest extends SapphireTest
$this->markTestSkipped('This test requires RESOURCES_DIR to be something other than "resources"'); $this->markTestSkipped('This test requires RESOURCES_DIR to be something other than "resources"');
} }
$page = SiteTree::create(['Title' => '_Resources']); $page = new SiteTree(['Title' => '_Resources']);
$id = $page->write(); $id = $page->write();
$page = SiteTree::get()->byID($id); $page = SiteTree::get()->byID($id);
$this->assertSame('resources', $page->URLSegment); $this->assertSame('resources', $page->URLSegment);
@ -209,10 +207,12 @@ class SiteTreeTest extends SapphireTest
*/ */
public function testPublishCopiesToLiveTable() public function testPublishCopiesToLiveTable()
{ {
$obj = $this->objFromFixture('Page', 'about'); $obj = $this->objFromFixture(SiteTree::class, 'about');
$obj->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE); $obj->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
$createdID = DB::query("SELECT \"ID\" FROM \"SiteTree_Live\" WHERE \"URLSegment\" = '$obj->URLSegment'")->value(); $createdID = DB::query(
"SELECT \"ID\" FROM \"SiteTree_Live\" WHERE \"URLSegment\" = '$obj->URLSegment'"
)->value();
$this->assertEquals($obj->ID, $createdID); $this->assertEquals($obj->ID, $createdID);
} }
@ -223,12 +223,15 @@ class SiteTreeTest extends SapphireTest
{ {
$this->logInWithPermission('ADMIN'); $this->logInWithPermission('ADMIN');
$obj = $this->objFromFixture('Page', 'about'); $obj = $this->objFromFixture(SiteTree::class, 'about');
$obj->Title = "asdfasdf"; $obj->Title = "asdfasdf";
$obj->write(); $obj->write();
$this->assertTrue($obj->publishRecursive()); $this->assertTrue($obj->publishRecursive());
$this->assertEquals('asdfasdf', DB::query("SELECT \"Title\" FROM \"SiteTree_Live\" WHERE \"ID\" = '$obj->ID'")->value()); $this->assertEquals(
'asdfasdf',
DB::query("SELECT \"Title\" FROM \"SiteTree_Live\" WHERE \"ID\" = '$obj->ID'")->value()
);
$obj->Title = null; $obj->Title = null;
$obj->write(); $obj->write();
@ -275,7 +278,7 @@ class SiteTreeTest extends SapphireTest
Versioned::set_stage(Versioned::LIVE); Versioned::set_stage(Versioned::LIVE);
$checkSiteTree = DataObject::get_one(SiteTree::class, [ $checkSiteTree = DataObject::get_one(SiteTree::class, [
'"SiteTree"."URLSegment"' => 'get-one-test-page' '"SiteTree"."URLSegment"' => 'get-one-test-page',
]); ]);
$this->assertEquals("V1", $checkSiteTree->Title); $this->assertEquals("V1", $checkSiteTree->Title);
@ -314,10 +317,13 @@ class SiteTreeTest extends SapphireTest
{ {
/* DataObject::write() should save to a has_one relationship if you set a field called (relname)ID */ /* DataObject::write() should save to a has_one relationship if you set a field called (relname)ID */
$page = new SiteTree(); $page = new SiteTree();
$parentID = $this->idFromFixture('Page', 'home'); $parentID = $this->idFromFixture(SiteTree::class, 'home');
$page->ParentID = $parentID; $page->ParentID = $parentID;
$page->write(); $page->write();
$this->assertEquals($parentID, DB::query("SELECT \"ParentID\" FROM \"SiteTree\" WHERE \"ID\" = $page->ID")->value()); $this->assertEquals(
$parentID,
DB::query("SELECT \"ParentID\" FROM \"SiteTree\" WHERE \"ID\" = $page->ID")->value()
);
/* You should then be able to save a null/0/'' value to the relation */ /* You should then be able to save a null/0/'' value to the relation */
$page->ParentID = null; $page->ParentID = null;
@ -401,23 +407,23 @@ class SiteTreeTest extends SapphireTest
*/ */
public function testRestoreToStage() public function testRestoreToStage()
{ {
$page = $this->objFromFixture('Page', 'about'); $page = $this->objFromFixture(SiteTree::class, 'about');
$pageID = $page->ID; $pageID = $page->ID;
$page->delete(); $page->delete();
$this->assertTrue(!DataObject::get_by_id("Page", $pageID)); $this->assertTrue(!DataObject::get_by_id(SiteTree::class, $pageID));
$deletedPage = Versioned::get_latest_version(SiteTree::class, $pageID); $deletedPage = Versioned::get_latest_version(SiteTree::class, $pageID);
$resultPage = $deletedPage->doRestoreToStage(); $resultPage = $deletedPage->doRestoreToStage();
$requeriedPage = DataObject::get_by_id("Page", $pageID); $requeriedPage = DataObject::get_by_id(SiteTree::class, $pageID);
$this->assertEquals($pageID, $resultPage->ID); $this->assertEquals($pageID, $resultPage->ID);
$this->assertEquals($pageID, $requeriedPage->ID); $this->assertEquals($pageID, $requeriedPage->ID);
$this->assertEquals('About Us', $requeriedPage->Title); $this->assertEquals('About Us', $requeriedPage->Title);
$this->assertInstanceOf('Page', $requeriedPage); $this->assertInstanceOf(SiteTree::class, $requeriedPage);
$page2 = $this->objFromFixture('Page', 'products'); $page2 = $this->objFromFixture(SiteTree::class, 'products');
$page2ID = $page2->ID; $page2ID = $page2->ID;
$page2->doUnpublish(); $page2->doUnpublish();
$page2->delete(); $page2->delete();
@ -427,12 +433,14 @@ class SiteTreeTest extends SapphireTest
Versioned::set_stage(Versioned::LIVE); Versioned::set_stage(Versioned::LIVE);
$deletedPage = Versioned::get_latest_version(SiteTree::class, $page2ID); $deletedPage = Versioned::get_latest_version(SiteTree::class, $page2ID);
$deletedPage->doRestoreToStage(); $deletedPage->doRestoreToStage();
$this->assertFalse((bool)Versioned::get_one_by_stage(SiteTree::class, Versioned::LIVE, "\"SiteTree\".\"ID\" = " . $page2ID)); $this->assertFalse(
(bool)Versioned::get_one_by_stage(SiteTree::class, Versioned::LIVE, "\"SiteTree\".\"ID\" = " . $page2ID)
);
Versioned::set_stage(Versioned::DRAFT); Versioned::set_stage(Versioned::DRAFT);
$requeriedPage = DataObject::get_by_id("Page", $page2ID); $requeriedPage = DataObject::get_by_id(SiteTree::class, $page2ID);
$this->assertEquals('Products', $requeriedPage->Title); $this->assertEquals('Products', $requeriedPage->Title);
$this->assertInstanceOf('Page', $requeriedPage); $this->assertInstanceOf(SiteTree::class, $requeriedPage);
} }
public function testNoCascadingDeleteWithoutID() public function testNoCascadingDeleteWithoutID()
@ -456,11 +464,11 @@ class SiteTreeTest extends SapphireTest
public function testGetByLink() public function testGetByLink()
{ {
$home = $this->objFromFixture('Page', 'home'); $home = $this->objFromFixture(SiteTree::class, 'home');
$about = $this->objFromFixture('Page', 'about'); $about = $this->objFromFixture(SiteTree::class, 'about');
$staff = $this->objFromFixture('Page', 'staff'); $staff = $this->objFromFixture(SiteTree::class, 'staff');
$product = $this->objFromFixture('Page', 'product1'); $product = $this->objFromFixture(SiteTree::class, 'product1');
$numeric0 = $this->objFromFixture('Page', 'numeric0'); $numeric0 = $this->objFromFixture(SiteTree::class, 'numeric0');
SiteTree::config()->nested_urls = false; SiteTree::config()->nested_urls = false;
@ -489,11 +497,11 @@ class SiteTreeTest extends SapphireTest
public function testGetByLinkAbsolute() public function testGetByLinkAbsolute()
{ {
$home = $this->objFromFixture('Page', 'home'); $home = $this->objFromFixture(SiteTree::class, 'home');
$about = $this->objFromFixture('Page', 'about'); $about = $this->objFromFixture(SiteTree::class, 'about');
$staff = $this->objFromFixture('Page', 'staff'); $staff = $this->objFromFixture(SiteTree::class, 'staff');
$product = $this->objFromFixture('Page', 'product1'); $product = $this->objFromFixture(SiteTree::class, 'product1');
$numeric0 = $this->objFromFixture('Page', 'numeric0'); $numeric0 = $this->objFromFixture(SiteTree::class, 'numeric0');
$base = 'https://example.test/'; $base = 'https://example.test/';
$this->assertEquals($home->ID, SiteTree::get_by_link(Controller::join_links($base, '/'), false)->ID); $this->assertEquals($home->ID, SiteTree::get_by_link(Controller::join_links($base, '/'), false)->ID);
@ -506,31 +514,51 @@ class SiteTreeTest extends SapphireTest
public function testRelativeLink() public function testRelativeLink()
{ {
$about = $this->objFromFixture('Page', 'about'); $about = $this->objFromFixture(SiteTree::class, 'about');
$staff = $this->objFromFixture('Page', 'staff'); $staff = $this->objFromFixture(SiteTree::class, 'staff');
$numeric0 = $this->objFromFixture('Page', 'numeric0'); $numeric0 = $this->objFromFixture(SiteTree::class, 'numeric0');
Config::modify()->set(SiteTree::class, 'nested_urls', true); Config::modify()->set(SiteTree::class, 'nested_urls', true);
$this->assertEquals('about-us/', $about->RelativeLink(), 'Matches URLSegment on top level without parameters'); $this->assertEquals(
$this->assertEquals('about-us/my-staff/', $staff->RelativeLink(), 'Matches URLSegment plus parent on second level without parameters'); 'about-us',
$this->assertEquals('about-us/edit', $about->RelativeLink('edit'), 'Matches URLSegment plus parameter on top level'); $about->RelativeLink(),
$this->assertEquals('about-us/tom&jerry', $about->RelativeLink('tom&jerry'), 'Doesnt url encode parameter'); 'Matches URLSegment on top level without parameters'
$this->assertEquals('0/', $numeric0->RelativeLink(), 'Matches URLSegment for segment = 0'); );
$this->assertEquals(
'about-us/my-staff',
$staff->RelativeLink(),
'Matches URLSegment plus parent on second level without parameters'
);
$this->assertEquals(
Controller::normaliseTrailingSlash('0/'),
$numeric0->RelativeLink(),
'Matches URLSegment for segment = 0'
);
$this->assertEquals(
'about-us/edit',
$about->RelativeLink('edit'),
'Matches URLSegment plus parameter on top level'
);
$this->assertEquals(
'about-us/tom&jerry',
$about->RelativeLink('tom&jerry'),
'Doesnt url encode parameter'
);
} }
public function testPageLevel() public function testPageLevel()
{ {
$about = $this->objFromFixture('Page', 'about'); $about = $this->objFromFixture(SiteTree::class, 'about');
$staff = $this->objFromFixture('Page', 'staff'); $staff = $this->objFromFixture(SiteTree::class, 'staff');
$this->assertEquals(1, $about->getPageLevel()); $this->assertEquals(1, $about->getPageLevel());
$this->assertEquals(2, $staff->getPageLevel()); $this->assertEquals(2, $staff->getPageLevel());
} }
public function testAbsoluteLiveLink() public function testAbsoluteLiveLink()
{ {
$parent = $this->objFromFixture('Page', 'about'); $parent = $this->objFromFixture(SiteTree::class, 'about');
$child = $this->objFromFixture('Page', 'staff'); $child = $this->objFromFixture(SiteTree::class, 'staff');
Config::modify()->set(SiteTree::class, 'nested_urls', true); Config::modify()->set(SiteTree::class, 'nested_urls', true);
@ -541,23 +569,23 @@ class SiteTreeTest extends SapphireTest
$parent->URLSegment = 'changed-on-draft'; $parent->URLSegment = 'changed-on-draft';
$parent->write(); $parent->write();
$this->assertStringEndsWith('changed-on-live/my-staff/', $child->getAbsoluteLiveLink(false)); $this->assertStringEndsWith('changed-on-live/my-staff', $child->getAbsoluteLiveLink(false));
$this->assertStringEndsWith('changed-on-live/my-staff/?stage=Live', $child->getAbsoluteLiveLink()); $this->assertStringEndsWith('changed-on-live/my-staff?stage=Live', $child->getAbsoluteLiveLink());
} }
public function testDuplicateChildrenRetainSort() public function testDuplicateChildrenRetainSort()
{ {
$parent = new Page(); $parent = new SiteTree();
$parent->Title = 'Parent'; $parent->Title = 'Parent';
$parent->write(); $parent->write();
$child1 = new Page(); $child1 = new SiteTree();
$child1->ParentID = $parent->ID; $child1->ParentID = $parent->ID;
$child1->Title = 'Child 1'; $child1->Title = 'Child 1';
$child1->Sort = 2; $child1->Sort = 2;
$child1->write(); $child1->write();
$child2 = new Page(); $child2 = new SiteTree();
$child2->ParentID = $parent->ID; $child2->ParentID = $parent->ID;
$child2->Title = 'Child 2'; $child2->Title = 'Child 2';
$child2->Sort = 1; $child2->Sort = 1;
@ -581,34 +609,34 @@ class SiteTreeTest extends SapphireTest
public function testDeleteFromStageOperatesRecursively() public function testDeleteFromStageOperatesRecursively()
{ {
Config::modify()->set(SiteTree::class, 'enforce_strict_hierarchy', false); Config::modify()->set(SiteTree::class, 'enforce_strict_hierarchy', false);
$pageAbout = $this->objFromFixture('Page', 'about'); $pageAbout = $this->objFromFixture(SiteTree::class, 'about');
$pageStaff = $this->objFromFixture('Page', 'staff'); $pageStaff = $this->objFromFixture(SiteTree::class, 'staff');
$pageStaffDuplicate = $this->objFromFixture('Page', 'staffduplicate'); $pageStaffDuplicate = $this->objFromFixture(SiteTree::class, 'staffduplicate');
$pageAbout->delete(); $pageAbout->delete();
$this->assertNull(DataObject::get_by_id('Page', $pageAbout->ID)); $this->assertNull(DataObject::get_by_id(SiteTree::class, $pageAbout->ID));
$this->assertTrue(DataObject::get_by_id('Page', $pageStaff->ID) instanceof Page); $this->assertTrue(DataObject::get_by_id(SiteTree::class, $pageStaff->ID) instanceof SiteTree);
$this->assertTrue(DataObject::get_by_id('Page', $pageStaffDuplicate->ID) instanceof Page); $this->assertTrue(DataObject::get_by_id(SiteTree::class, $pageStaffDuplicate->ID) instanceof SiteTree);
Config::modify()->set(SiteTree::class, 'enforce_strict_hierarchy', true); Config::modify()->set(SiteTree::class, 'enforce_strict_hierarchy', true);
} }
public function testDeleteFromStageOperatesRecursivelyStrict() public function testDeleteFromStageOperatesRecursivelyStrict()
{ {
$pageAbout = $this->objFromFixture('Page', 'about'); $pageAbout = $this->objFromFixture(SiteTree::class, 'about');
$pageStaff = $this->objFromFixture('Page', 'staff'); $pageStaff = $this->objFromFixture(SiteTree::class, 'staff');
$pageStaffDuplicate = $this->objFromFixture('Page', 'staffduplicate'); $pageStaffDuplicate = $this->objFromFixture(SiteTree::class, 'staffduplicate');
$pageAbout->delete(); $pageAbout->delete();
$this->assertNull(DataObject::get_by_id('Page', $pageAbout->ID)); $this->assertNull(DataObject::get_by_id(SiteTree::class, $pageAbout->ID));
$this->assertNull(DataObject::get_by_id('Page', $pageStaff->ID)); $this->assertNull(DataObject::get_by_id(SiteTree::class, $pageStaff->ID));
$this->assertNull(DataObject::get_by_id('Page', $pageStaffDuplicate->ID)); $this->assertNull(DataObject::get_by_id(SiteTree::class, $pageStaffDuplicate->ID));
} }
public function testDuplicate() public function testDuplicate()
{ {
$pageAbout = $this->objFromFixture('Page', 'about'); $pageAbout = $this->objFromFixture(SiteTree::class, 'about');
$dupe = $pageAbout->duplicate(); $dupe = $pageAbout->duplicate();
$this->assertEquals($pageAbout->Title, $dupe->Title); $this->assertEquals($pageAbout->Title, $dupe->Title);
$this->assertNotEquals($pageAbout->URLSegment, $dupe->URLSegment); $this->assertNotEquals($pageAbout->URLSegment, $dupe->URLSegment);
@ -620,22 +648,22 @@ class SiteTreeTest extends SapphireTest
Config::modify()->set(SiteTree::class, 'enforce_strict_hierarchy', false); Config::modify()->set(SiteTree::class, 'enforce_strict_hierarchy', false);
$this->logInWithPermission('ADMIN'); $this->logInWithPermission('ADMIN');
$pageAbout = $this->objFromFixture('Page', 'about'); $pageAbout = $this->objFromFixture(SiteTree::class, 'about');
$pageAbout->publishRecursive(); $pageAbout->publishRecursive();
$pageStaff = $this->objFromFixture('Page', 'staff'); $pageStaff = $this->objFromFixture(SiteTree::class, 'staff');
$pageStaff->publishRecursive(); $pageStaff->publishRecursive();
$pageStaffDuplicate = $this->objFromFixture('Page', 'staffduplicate'); $pageStaffDuplicate = $this->objFromFixture(SiteTree::class, 'staffduplicate');
$pageStaffDuplicate->publishRecursive(); $pageStaffDuplicate->publishRecursive();
$parentPage = $this->objFromFixture('Page', 'about'); $parentPage = $this->objFromFixture(SiteTree::class, 'about');
$parentPage->doUnpublish(); $parentPage->doUnpublish();
Versioned::set_stage(Versioned::LIVE); Versioned::set_stage(Versioned::LIVE);
$this->assertNull(DataObject::get_by_id('Page', $pageAbout->ID)); $this->assertNull(DataObject::get_by_id(SiteTree::class, $pageAbout->ID));
$this->assertTrue(DataObject::get_by_id('Page', $pageStaff->ID) instanceof Page); $this->assertTrue(DataObject::get_by_id(SiteTree::class, $pageStaff->ID) instanceof SiteTree);
$this->assertTrue(DataObject::get_by_id('Page', $pageStaffDuplicate->ID) instanceof Page); $this->assertTrue(DataObject::get_by_id(SiteTree::class, $pageStaffDuplicate->ID) instanceof SiteTree);
Versioned::set_stage(Versioned::DRAFT); Versioned::set_stage(Versioned::DRAFT);
Config::modify()->set(SiteTree::class, 'enforce_strict_hierarchy', true); Config::modify()->set(SiteTree::class, 'enforce_strict_hierarchy', true);
} }
@ -645,20 +673,20 @@ class SiteTreeTest extends SapphireTest
Config::modify()->set(SiteTree::class, 'enforce_strict_hierarchy', false); Config::modify()->set(SiteTree::class, 'enforce_strict_hierarchy', false);
$this->logInWithPermission('ADMIN'); $this->logInWithPermission('ADMIN');
$pageAbout = $this->objFromFixture('Page', 'about'); $pageAbout = $this->objFromFixture(SiteTree::class, 'about');
$pageAbout->publishRecursive(); $pageAbout->publishRecursive();
$pageStaff = $this->objFromFixture('Page', 'staff'); $pageStaff = $this->objFromFixture(SiteTree::class, 'staff');
$pageStaff->publishRecursive(); $pageStaff->publishRecursive();
$pageStaffDuplicate = $this->objFromFixture('Page', 'staffduplicate'); $pageStaffDuplicate = $this->objFromFixture(SiteTree::class, 'staffduplicate');
$pageStaffDuplicate->publishRecursive(); $pageStaffDuplicate->publishRecursive();
$parentPage = $this->objFromFixture('Page', 'about'); $parentPage = $this->objFromFixture(SiteTree::class, 'about');
$parentPage->doUnpublish(); $parentPage->doUnpublish();
Versioned::set_stage(Versioned::LIVE); Versioned::set_stage(Versioned::LIVE);
$this->assertNull(DataObject::get_by_id('Page', $pageAbout->ID)); $this->assertNull(DataObject::get_by_id(SiteTree::class, $pageAbout->ID));
$this->assertTrue(DataObject::get_by_id('Page', $pageStaff->ID) instanceof Page); $this->assertTrue(DataObject::get_by_id(SiteTree::class, $pageStaff->ID) instanceof SiteTree);
$this->assertTrue(DataObject::get_by_id('Page', $pageStaffDuplicate->ID) instanceof Page); $this->assertTrue(DataObject::get_by_id(SiteTree::class, $pageStaffDuplicate->ID) instanceof SiteTree);
Versioned::set_stage(Versioned::DRAFT); Versioned::set_stage(Versioned::DRAFT);
Config::modify()->set(SiteTree::class, 'enforce_strict_hierarchy', true); Config::modify()->set(SiteTree::class, 'enforce_strict_hierarchy', true);
} }
@ -667,20 +695,20 @@ class SiteTreeTest extends SapphireTest
{ {
$this->logInWithPermission('ADMIN'); $this->logInWithPermission('ADMIN');
$pageAbout = $this->objFromFixture('Page', 'about'); $pageAbout = $this->objFromFixture(SiteTree::class, 'about');
$pageAbout->publishRecursive(); $pageAbout->publishRecursive();
$pageStaff = $this->objFromFixture('Page', 'staff'); $pageStaff = $this->objFromFixture(SiteTree::class, 'staff');
$pageStaff->publishRecursive(); $pageStaff->publishRecursive();
$pageStaffDuplicate = $this->objFromFixture('Page', 'staffduplicate'); $pageStaffDuplicate = $this->objFromFixture(SiteTree::class, 'staffduplicate');
$pageStaffDuplicate->publishRecursive(); $pageStaffDuplicate->publishRecursive();
$parentPage = $this->objFromFixture('Page', 'about'); $parentPage = $this->objFromFixture(SiteTree::class, 'about');
$parentPage->doUnpublish(); $parentPage->doUnpublish();
Versioned::set_stage(Versioned::LIVE); Versioned::set_stage(Versioned::LIVE);
$this->assertNull(DataObject::get_by_id('Page', $pageAbout->ID)); $this->assertNull(DataObject::get_by_id(SiteTree::class, $pageAbout->ID));
$this->assertNull(DataObject::get_by_id('Page', $pageStaff->ID)); $this->assertNull(DataObject::get_by_id(SiteTree::class, $pageStaff->ID));
$this->assertNull(DataObject::get_by_id('Page', $pageStaffDuplicate->ID)); $this->assertNull(DataObject::get_by_id(SiteTree::class, $pageStaffDuplicate->ID));
Versioned::set_stage(Versioned::DRAFT); Versioned::set_stage(Versioned::DRAFT);
} }
@ -691,7 +719,7 @@ class SiteTreeTest extends SapphireTest
public function testReadArchiveDate() public function testReadArchiveDate()
{ {
DBDatetime::set_mock_now('2009-07-02 14:05:07'); DBDatetime::set_mock_now('2009-07-02 14:05:07');
$oldPage = SiteTree::create(); $oldPage = new SiteTree();
$oldPage->Title = 'A really old page'; $oldPage->Title = 'A really old page';
$oldPage->write(); $oldPage->write();
DBDatetime::clear_mock_now(); DBDatetime::clear_mock_now();
@ -699,7 +727,7 @@ class SiteTreeTest extends SapphireTest
$date = '2009-07-02 14:05:07'; $date = '2009-07-02 14:05:07';
Versioned::reading_archived_date($date); Versioned::reading_archived_date($date);
$result = SiteTree::get()->where([ $result = SiteTree::get()->where([
'"SiteTree"."ParentID"' => 0 '"SiteTree"."ParentID"' => 0,
]); ]);
$this->assertCount(1, $result, '"A really old page" should be returned'); $this->assertCount(1, $result, '"A really old page" should be returned');
} }
@ -708,11 +736,11 @@ class SiteTreeTest extends SapphireTest
{ {
$editor = $this->objFromFixture(Member::class, "editor"); $editor = $this->objFromFixture(Member::class, "editor");
$home = $this->objFromFixture("Page", "home"); $home = $this->objFromFixture(SiteTree::class, "home");
$staff = $this->objFromFixture("Page", "staff"); $staff = $this->objFromFixture(SiteTree::class, "staff");
$products = $this->objFromFixture("Page", "products"); $products = $this->objFromFixture(SiteTree::class, "products");
$product1 = $this->objFromFixture("Page", "product1"); $product1 = $this->objFromFixture(SiteTree::class, "product1");
$product4 = $this->objFromFixture("Page", "product4"); $product4 = $this->objFromFixture(SiteTree::class, "product4");
// Test logged out users cannot edit // Test logged out users cannot edit
$this->logOut(); $this->logOut();
@ -733,7 +761,7 @@ class SiteTreeTest extends SapphireTest
public function testCanEditWithAccessToAllSections() public function testCanEditWithAccessToAllSections()
{ {
$page = new Page(); $page = new SiteTree();
$page->write(); $page->write();
$allSectionMember = $this->objFromFixture(Member::class, 'allsections'); $allSectionMember = $this->objFromFixture(Member::class, 'allsections');
$securityAdminMember = $this->objFromFixture(Member::class, 'securityadmin'); $securityAdminMember = $this->objFromFixture(Member::class, 'securityadmin');
@ -758,7 +786,7 @@ class SiteTreeTest extends SapphireTest
$this->assertTrue(singleton(SiteTree::class)->canCreate()); $this->assertTrue(singleton(SiteTree::class)->canCreate());
// Test creation underneath a parent which this user doesn't have access to // Test creation underneath a parent which this user doesn't have access to
$parent = $this->objFromFixture('Page', 'about'); $parent = $this->objFromFixture(SiteTree::class, 'about');
$this->assertFalse(singleton(SiteTree::class)->canCreate(null, ['Parent' => $parent])); $this->assertFalse(singleton(SiteTree::class)->canCreate(null, ['Parent' => $parent]));
// Test creation underneath a parent which doesn't allow a certain child // Test creation underneath a parent which doesn't allow a certain child
@ -774,13 +802,18 @@ class SiteTreeTest extends SapphireTest
$this->assertTrue(singleton(SiteTree::class)->canCreate(null, ['Parent' => singleton(SiteTree::class)])); $this->assertTrue(singleton(SiteTree::class)->canCreate(null, ['Parent' => singleton(SiteTree::class)]));
//Test we don't check for allowedChildren on parent context if it's not SiteTree instance //Test we don't check for allowedChildren on parent context if it's not SiteTree instance
$this->assertTrue(singleton(SiteTree::class)->canCreate(null, ['Parent' => $this->objFromFixture(SiteTreeTest_DataObject::class, 'relations')])); $this->assertTrue(
singleton(SiteTree::class)->canCreate(
null,
['Parent' => $this->objFromFixture(SiteTreeTest_DataObject::class, 'relations')]
)
);
} }
public function testEditPermissionsOnDraftVsLive() public function testEditPermissionsOnDraftVsLive()
{ {
// Create an inherit-permission page // Create an inherit-permission page
$page = new Page(); $page = new SiteTree();
$page->write(); $page->write();
$page->CanEditType = "Inherit"; $page->CanEditType = "Inherit";
$page->publishRecursive(); $page->publishRecursive();
@ -828,10 +861,10 @@ class SiteTreeTest extends SapphireTest
public function testCompareVersions() public function testCompareVersions()
{ {
// Necessary to avoid // Necessary to avoid
$oldCleanerClass = Diff::$html_cleaner_class; $oldCleanerClass = HtmlDiff::$html_cleaner_class;
Diff::$html_cleaner_class = SiteTreeTest_NullHtmlCleaner::class; HtmlDiff::$html_cleaner_class = SiteTreeTest_NullHtmlCleaner::class;
$page = new Page(); $page = new SiteTree();
$page->write(); $page->write();
$this->assertEquals(1, $page->Version); $this->assertEquals(1, $page->Version);
@ -849,7 +882,7 @@ class SiteTreeTest extends SapphireTest
$processedContent = preg_replace('/>\s*/', '>', $processedContent ?? ''); $processedContent = preg_replace('/>\s*/', '>', $processedContent ?? '');
$this->assertEquals("<ins><span>This is a test</span></ins>", $processedContent); $this->assertEquals("<ins><span>This is a test</span></ins>", $processedContent);
Diff::$html_cleaner_class = $oldCleanerClass; HtmlDiff::$html_cleaner_class = $oldCleanerClass;
} }
public function testAuthorIDAndPublisherIDFilledOutOnPublish() public function testAuthorIDAndPublisherIDFilledOutOnPublish()
@ -859,7 +892,7 @@ class SiteTreeTest extends SapphireTest
$this->logInAs($member); $this->logInAs($member);
// Write the page // Write the page
$about = $this->objFromFixture('Page', 'about'); $about = $this->objFromFixture(SiteTree::class, 'about');
$about->Title = "Another title"; $about->Title = "Another title";
$about->write(); $about->write();
@ -868,7 +901,7 @@ class SiteTreeTest extends SapphireTest
"SELECT \"AuthorID\", \"PublisherID\" FROM \"SiteTree_Versions\" "SELECT \"AuthorID\", \"PublisherID\" FROM \"SiteTree_Versions\"
WHERE \"RecordID\" = ? ORDER BY \"Version\" DESC", WHERE \"RecordID\" = ? ORDER BY \"Version\" DESC",
[$about->ID] [$about->ID]
)->first(); )->record();
$this->assertEquals($member->ID, $savedVersion['AuthorID']); $this->assertEquals($member->ID, $savedVersion['AuthorID']);
$this->assertEquals(0, $savedVersion['PublisherID']); $this->assertEquals(0, $savedVersion['PublisherID']);
@ -878,7 +911,7 @@ class SiteTreeTest extends SapphireTest
"SELECT \"AuthorID\", \"PublisherID\" FROM \"SiteTree_Versions\" "SELECT \"AuthorID\", \"PublisherID\" FROM \"SiteTree_Versions\"
WHERE \"RecordID\" = ? ORDER BY \"Version\" DESC", WHERE \"RecordID\" = ? ORDER BY \"Version\" DESC",
[$about->ID] [$about->ID]
)->first(); )->record();
// Check the version created // Check the version created
$this->assertEquals($member->ID, $publishedVersion['AuthorID']); $this->assertEquals($member->ID, $publishedVersion['AuthorID']);
@ -887,7 +920,7 @@ class SiteTreeTest extends SapphireTest
public function testLinkShortcodeHandler() public function testLinkShortcodeHandler()
{ {
$aboutPage = $this->objFromFixture('Page', 'about'); $aboutPage = $this->objFromFixture(SiteTree::class, 'about');
$redirectPage = $this->objFromFixture(RedirectorPage::class, 'external'); $redirectPage = $this->objFromFixture(RedirectorPage::class, 'external');
$parser = new ShortcodeParser(); $parser = new ShortcodeParser();
@ -899,12 +932,24 @@ class SiteTreeTest extends SapphireTest
$aboutShortcodeExpected = $aboutPage->Link(); $aboutShortcodeExpected = $aboutPage->Link();
$aboutEnclosedExpected = sprintf('<a href="%s">Example Content</a>', $aboutPage->Link()); $aboutEnclosedExpected = sprintf('<a href="%s">Example Content</a>', $aboutPage->Link());
$this->assertEquals($aboutShortcodeExpected, $parser->parse($aboutShortcode), 'Test that simple linking works.'); $this->assertEquals(
$this->assertEquals($aboutEnclosedExpected, $parser->parse($aboutEnclosed), 'Test enclosed content is linked.'); $aboutShortcodeExpected,
$parser->parse($aboutShortcode),
'Test that simple linking works.'
);
$this->assertEquals(
$aboutEnclosedExpected,
$parser->parse($aboutEnclosed),
'Test enclosed content is linked.'
);
$aboutPage->delete(); $aboutPage->delete();
$this->assertEquals($aboutShortcodeExpected, $parser->parse($aboutShortcode), 'Test that deleted pages still link.'); $this->assertEquals(
$aboutShortcodeExpected,
$parser->parse($aboutShortcode),
'Test that deleted pages still link.'
);
$this->assertEquals($aboutEnclosedExpected, $parser->parse($aboutEnclosed)); $this->assertEquals($aboutEnclosedExpected, $parser->parse($aboutEnclosed));
$aboutShortcode = '[sitetree_link,id="-1"]'; $aboutShortcode = '[sitetree_link,id="-1"]';
@ -918,7 +963,10 @@ class SiteTreeTest extends SapphireTest
$redirectExpected = 'http://www.google.com?a&amp;b'; $redirectExpected = 'http://www.google.com?a&amp;b';
$this->assertEquals($redirectExpected, $parser->parse($redirectShortcode)); $this->assertEquals($redirectExpected, $parser->parse($redirectShortcode));
$this->assertEquals(sprintf('<a href="%s">Example Content</a>', $redirectExpected), $parser->parse($redirectEnclosed)); $this->assertEquals(
sprintf('<a href="%s">Example Content</a>', $redirectExpected),
$parser->parse($redirectEnclosed)
);
$this->assertEquals('', $parser->parse('[sitetree_link]'), 'Test that invalid ID attributes are not parsed.'); $this->assertEquals('', $parser->parse('[sitetree_link]'), 'Test that invalid ID attributes are not parsed.');
$this->assertEquals('', $parser->parse('[sitetree_link,id="text"]')); $this->assertEquals('', $parser->parse('[sitetree_link,id="text"]'));
@ -927,8 +975,8 @@ class SiteTreeTest extends SapphireTest
public function testIsCurrent() public function testIsCurrent()
{ {
$aboutPage = $this->objFromFixture('Page', 'about'); $aboutPage = $this->objFromFixture(SiteTree::class, 'about');
$productPage = $this->objFromFixture('Page', 'products'); $productPage = $this->objFromFixture(SiteTree::class, 'products');
Director::set_current_page($aboutPage); Director::set_current_page($aboutPage);
$this->assertTrue($aboutPage->isCurrent(), 'Assert that basic isCurrent checks works.'); $this->assertTrue($aboutPage->isCurrent(), 'Assert that basic isCurrent checks works.');
@ -936,7 +984,7 @@ class SiteTreeTest extends SapphireTest
$this->assertTrue( $this->assertTrue(
DataObject::get_one(SiteTree::class, [ DataObject::get_one(SiteTree::class, [
'"SiteTree"."Title"' => 'About Us' '"SiteTree"."Title"' => 'About Us',
])->isCurrent(), ])->isCurrent(),
'Assert that isCurrent works on another instance with the same ID.' 'Assert that isCurrent works on another instance with the same ID.'
); );
@ -947,9 +995,9 @@ class SiteTreeTest extends SapphireTest
public function testIsSection() public function testIsSection()
{ {
$about = $this->objFromFixture('Page', 'about'); $about = $this->objFromFixture(SiteTree::class, 'about');
$staff = $this->objFromFixture('Page', 'staff'); $staff = $this->objFromFixture(SiteTree::class, 'staff');
$ceo = $this->objFromFixture('Page', 'ceo'); $ceo = $this->objFromFixture(SiteTree::class, 'ceo');
Director::set_current_page($about); Director::set_current_page($about);
$this->assertTrue($about->isSection()); $this->assertTrue($about->isSection());
@ -969,7 +1017,7 @@ class SiteTreeTest extends SapphireTest
public function testURLSegmentReserved() public function testURLSegmentReserved()
{ {
$siteTree = SiteTree::create(['URLSegment' => 'admin']); $siteTree = new SiteTree(['URLSegment' => 'admin']);
$segment = $siteTree->validURLSegment(); $segment = $siteTree->validURLSegment();
$this->assertFalse($segment); $this->assertFalse($segment);
@ -1057,7 +1105,7 @@ class SiteTreeTest extends SapphireTest
$sitetree->URLSegment = 'home-noconflict'; $sitetree->URLSegment = 'home-noconflict';
$this->assertTrue($sitetree->validURLSegment()); $this->assertTrue($sitetree->validURLSegment());
$sitetree->ParentID = $this->idFromFixture('Page', 'about'); $sitetree->ParentID = $this->idFromFixture(SiteTree::class, 'about');
$sitetree->URLSegment = 'home'; $sitetree->URLSegment = 'home';
$this->assertFalse($sitetree->validURLSegment(), 'Conflicts are still recognised with a ParentID value'); $this->assertFalse($sitetree->validURLSegment(), 'Conflicts are still recognised with a ParentID value');
@ -1067,7 +1115,7 @@ class SiteTreeTest extends SapphireTest
$sitetree->URLSegment = 'home'; $sitetree->URLSegment = 'home';
$this->assertFalse($sitetree->validURLSegment(), 'URLSegment conflicts are recognised'); $this->assertFalse($sitetree->validURLSegment(), 'URLSegment conflicts are recognised');
$sitetree->ParentID = $this->idFromFixture('Page', 'about'); $sitetree->ParentID = $this->idFromFixture(SiteTree::class, 'about');
$this->assertTrue($sitetree->validURLSegment(), 'URLSegments can be the same across levels'); $this->assertTrue($sitetree->validURLSegment(), 'URLSegments can be the same across levels');
$sitetree->URLSegment = 'my-staff'; $sitetree->URLSegment = 'my-staff';
@ -1137,13 +1185,18 @@ class SiteTreeTest extends SapphireTest
$sitetree->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE); $sitetree->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
$sitetree = DataObject::get_by_id(SiteTree::class, $sitetree->ID, false); $sitetree = DataObject::get_by_id(SiteTree::class, $sitetree->ID, false);
$this->assertEquals($sitetree->URLSegment, rawurlencode('brötchen')); $this->assertEquals($sitetree->URLSegment, rawurlencode('brötchen'));
$sitetreeLive = Versioned::get_one_by_stage(SiteTree::class, Versioned::LIVE, '"SiteTree"."ID" = ' .$sitetree->ID, false); $sitetreeLive = Versioned::get_one_by_stage(
SiteTree::class,
Versioned::LIVE,
'"SiteTree"."ID" = ' . $sitetree->ID,
false
);
$this->assertEquals($sitetreeLive->URLSegment, rawurlencode('brötchen')); $this->assertEquals($sitetreeLive->URLSegment, rawurlencode('brötchen'));
} }
public function testVersionsAreCreated() public function testVersionsAreCreated()
{ {
$p = new Page(); $p = new SiteTree();
$p->Content = "one"; $p->Content = "one";
$p->write(); $p->write();
$this->assertEquals(1, $p->Version); $this->assertEquals(1, $p->Version);
@ -1231,23 +1284,23 @@ class SiteTreeTest extends SapphireTest
// Expected // Expected
[ SiteTreeTest_ClassB::class ], [ SiteTreeTest_ClassB::class ],
// Assertion message // Assertion message
'Direct setting of allowed children' 'Direct setting of allowed children',
], ],
[ [
SiteTreeTest_ClassB::class, SiteTreeTest_ClassB::class,
[ SiteTreeTest_ClassC::class, SiteTreeTest_ClassCext::class ], [ SiteTreeTest_ClassC::class, SiteTreeTest_ClassCext::class ],
'Includes subclasses' 'Includes subclasses',
], ],
[ [
SiteTreeTest_ClassC::class, SiteTreeTest_ClassC::class,
[], [],
'Null setting' 'Null setting',
], ],
[ [
SiteTreeTest_ClassD::class, SiteTreeTest_ClassD::class,
[SiteTreeTest_ClassC::class], [SiteTreeTest_ClassC::class],
'Excludes subclasses if class is prefixed by an asterisk' 'Excludes subclasses if class is prefixed by an asterisk',
] ],
]; ];
} }
@ -1288,7 +1341,10 @@ class SiteTreeTest extends SapphireTest
$classCext->ParentID = $classD->ID; $classCext->ParentID = $classD->ID;
$valid = $classCext->validate(); $valid = $classCext->validate();
$this->assertFalse($valid->isValid(), "Doesnt allow child where only parent class is allowed on parent node, and asterisk prefixing is used"); $this->assertFalse(
$valid->isValid(),
"Doesnt allow child where only parent class is allowed on parent node, and asterisk prefixing is used"
);
} }
public function testClassDropdown() public function testClassDropdown()
@ -1307,8 +1363,8 @@ class SiteTreeTest extends SapphireTest
$this->assertArrayHasKey(SiteTreeTest_ClassA::class, $method->invoke($sitetree)); $this->assertArrayHasKey(SiteTreeTest_ClassA::class, $method->invoke($sitetree));
$this->logInWithPermission('ADMIN'); $this->logInWithPermission('ADMIN');
$rootPage = $this->objFromFixture(Page::class, 'home'); $rootPage = $this->objFromFixture(SiteTree::class, 'home');
$nonRootPage = $this->objFromFixture(Page::class, 'staff'); $nonRootPage = $this->objFromFixture(SiteTree::class, 'staff');
$this->assertArrayNotHasKey(SiteTreeTest_NotRoot::class, $method->invoke($rootPage)); $this->assertArrayNotHasKey(SiteTreeTest_NotRoot::class, $method->invoke($rootPage));
$this->assertArrayHasKey(SiteTreeTest_NotRoot::class, $method->invoke($nonRootPage)); $this->assertArrayHasKey(SiteTreeTest_NotRoot::class, $method->invoke($nonRootPage));
@ -1404,11 +1460,11 @@ class SiteTreeTest extends SapphireTest
public function testGetBreadcrumbItems() public function testGetBreadcrumbItems()
{ {
$page = $this->objFromFixture("Page", "breadcrumbs"); $page = $this->objFromFixture(SiteTree::class, "breadcrumbs");
$this->assertEquals(1, $page->getBreadcrumbItems()->count(), "Only display current page."); $this->assertEquals(1, $page->getBreadcrumbItems()->count(), "Only display current page.");
// Test breadcrumb order // Test breadcrumb order
$page = $this->objFromFixture("Page", "breadcrumbs5"); $page = $this->objFromFixture(SiteTree::class, "breadcrumbs5");
$breadcrumbs = $page->getBreadcrumbItems(); $breadcrumbs = $page->getBreadcrumbItems();
$this->assertEquals($breadcrumbs->count(), 5, "Display all breadcrumbs"); $this->assertEquals($breadcrumbs->count(), 5, "Display all breadcrumbs");
$this->assertEquals($breadcrumbs->first()->Title, "Breadcrumbs", "Breadcrumbs should be the first item."); $this->assertEquals($breadcrumbs->first()->Title, "Breadcrumbs", "Breadcrumbs should be the first item.");
@ -1428,7 +1484,7 @@ class SiteTreeTest extends SapphireTest
public function testMetaTags() public function testMetaTags()
{ {
$this->logInWithPermission('ADMIN'); $this->logInWithPermission('ADMIN');
$page = $this->objFromFixture('Page', 'metapage'); $page = $this->objFromFixture(SiteTree::class, 'metapage');
// Test with title // Test with title
$meta = $page->MetaTags(); $meta = $page->MetaTags();
@ -1452,7 +1508,7 @@ class SiteTreeTest extends SapphireTest
{ {
$this->logInWithPermission('ADMIN'); $this->logInWithPermission('ADMIN');
/** @var SiteTree $page */ /** @var SiteTree $page */
$page = $this->objFromFixture('Page', 'metapage'); $page = $this->objFromFixture(SiteTree::class, 'metapage');
$charset = Config::inst()->get(ContentNegotiator::class, 'encoding'); $charset = Config::inst()->get(ContentNegotiator::class, 'encoding');
@ -1534,8 +1590,8 @@ class SiteTreeTest extends SapphireTest
// both pages are viewable in stage // both pages are viewable in stage
Versioned::set_stage(Versioned::DRAFT); Versioned::set_stage(Versioned::DRAFT);
$about = $this->objFromFixture('Page', 'about'); $about = $this->objFromFixture(SiteTree::class, 'about');
$staff = $this->objFromFixture('Page', 'staff'); $staff = $this->objFromFixture(SiteTree::class, 'staff');
$this->assertFalse($about->isOrphaned()); $this->assertFalse($about->isOrphaned());
$this->assertFalse($staff->isOrphaned()); $this->assertFalse($staff->isOrphaned());
$this->assertTrue($about->canView($member)); $this->assertTrue($about->canView($member));
@ -1546,23 +1602,23 @@ class SiteTreeTest extends SapphireTest
$this->assertFalse($staff->isOrphaned()); $this->assertFalse($staff->isOrphaned());
$this->assertTrue($staff->canView($member)); $this->assertTrue($staff->canView($member));
Versioned::set_stage(Versioned::LIVE); Versioned::set_stage(Versioned::LIVE);
$staff = $this->objFromFixture('Page', 'staff'); // Live copy of page $staff = $this->objFromFixture(SiteTree::class, 'staff'); // Live copy of page
$this->assertTrue($staff->isOrphaned()); // because parent isn't published $this->assertTrue($staff->isOrphaned()); // because parent isn't published
$this->assertFalse($staff->canView($member)); $this->assertFalse($staff->canView($member));
// Publishing the parent page should restore visibility // Publishing the parent page should restore visibility
Versioned::set_stage(Versioned::DRAFT); Versioned::set_stage(Versioned::DRAFT);
$about = $this->objFromFixture('Page', 'about'); $about = $this->objFromFixture(SiteTree::class, 'about');
$about->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE); $about->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
Versioned::set_stage(Versioned::LIVE); Versioned::set_stage(Versioned::LIVE);
$staff = $this->objFromFixture('Page', 'staff'); $staff = $this->objFromFixture(SiteTree::class, 'staff');
$this->assertFalse($staff->isOrphaned()); $this->assertFalse($staff->isOrphaned());
$this->assertTrue($staff->canView($member)); $this->assertTrue($staff->canView($member));
// Removing staging page should not prevent live page being visible // Removing staging page should not prevent live page being visible
$about->deleteFromStage('Stage'); $about->deleteFromStage('Stage');
$staff->deleteFromStage('Stage'); $staff->deleteFromStage('Stage');
$staff = $this->objFromFixture('Page', 'staff'); $staff = $this->objFromFixture(SiteTree::class, 'staff');
$this->assertFalse($staff->isOrphaned()); $this->assertFalse($staff->isOrphaned());
$this->assertTrue($staff->canView($member)); $this->assertTrue($staff->canView($member));
@ -1577,8 +1633,8 @@ class SiteTreeTest extends SapphireTest
{ {
$this->logInWithPermission('ADMIN'); $this->logInWithPermission('ADMIN');
/** @var Page $page */ /** @var SiteTree $page */
$page = $this->objFromFixture('Page', 'home'); $page = $this->objFromFixture(SiteTree::class, 'home');
$this->assertTrue($page->canAddChildren()); $this->assertTrue($page->canAddChildren());
$this->assertTrue($page->isOnDraft()); $this->assertTrue($page->isOnDraft());
$this->assertFalse($page->isPublished()); $this->assertFalse($page->isPublished());
@ -1655,23 +1711,24 @@ class SiteTreeTest extends SapphireTest
} }
/** /**
* Test that the controller name for a SiteTree instance can be gathered by appending "Controller" to the SiteTree * Test that the controller name for a Page instance can be gathered by appending "Controller" to the Page
* class name in a PSR-2 compliant manner. * class name in a PSR-2 compliant manner.
*/ */
public function testGetControllerName() public function testGetControllerName()
{ {
$class = new Page; $page = new Page();
$this->assertSame('PageController', $class->getControllerName()); $this->assertSame(PageController::class, $page->getControllerName());
} }
/** /**
* Test that the controller name for a SiteTree instance can be gathered when set directly via config var * Test that the controller name for a SiteTree instance can be gathered when set directly via config var
*/ */
public function testGetControllerNameFromConfig() public function testGetControllerNameFromConfig()
{ {
Config::inst()->set(Page::class, 'controller_name', 'This\\Is\\A\\New\\Controller'); Config::inst()->set(SiteTree::class, 'controller_name', 'This\\Is\\A\\New\\Controller');
$class = new Page; $page = new SiteTree();
$this->assertSame('This\\Is\\A\\New\\Controller', $class->getControllerName()); $this->assertSame('This\\Is\\A\\New\\Controller', $page->getControllerName());
} }
/** /**
@ -1687,21 +1744,9 @@ class SiteTreeTest extends SapphireTest
$this->assertSame(SiteTreeTest_NamespaceMapTestController::class, $namespacedSiteTree->getControllerName()); $this->assertSame(SiteTreeTest_NamespaceMapTestController::class, $namespacedSiteTree->getControllerName());
} }
/**
* Test that underscored class names (legacy) are still supported (deprecation notice is issued though).
*/
public function testGetControllerNameWithUnderscoresIsSupported()
{
if (Deprecation::isEnabled()) {
$this->markTestSkipped('Test calls deprecated code');
}
$class = new SiteTreeTest_LegacyControllerName;
$this->assertEquals(SiteTreeTest_LegacyControllerName_Controller::class, $class->getControllerName());
}
public function testTreeTitleCache() public function testTreeTitleCache()
{ {
$siteTree = SiteTree::create(); $siteTree = new SiteTree();
$user = $this->objFromFixture(Member::class, 'allsections'); $user = $this->objFromFixture(Member::class, 'allsections');
Security::setCurrentUser($user); Security::setCurrentUser($user);
$pageClass = array_values(SiteTree::page_type_classes())[0]; $pageClass = array_values(SiteTree::page_type_classes())[0];
@ -1788,7 +1833,7 @@ class SiteTreeTest extends SapphireTest
} }
// Create new page on DRAFT // Create new page on DRAFT
$page = SiteTree::create(); $page = new SiteTree();
$page->Content = $content; $page->Content = $content;
$page->write(); $page->write();
@ -1804,7 +1849,7 @@ class SiteTreeTest extends SapphireTest
public function testGetCMSActions() public function testGetCMSActions()
{ {
// Create new page on DRAFT // Create new page on DRAFT
$page = SiteTree::create(); $page = new SiteTree();
$page->Content = md5(rand(0, PHP_INT_MAX)); $page->Content = md5(rand(0, PHP_INT_MAX));
$page->write(); $page->write();
@ -1934,7 +1979,7 @@ class SiteTreeTest extends SapphireTest
public function testGetCMSActionsWithoutForms() public function testGetCMSActionsWithoutForms()
{ {
// Create new page on DRAFT // Create new page on DRAFT
$page = SiteTree::create(); $page = new SiteTree();
$page->Content = md5(rand(0, PHP_INT_MAX)); $page->Content = md5(rand(0, PHP_INT_MAX));
$page->write(); $page->write();
@ -2040,21 +2085,11 @@ class SiteTreeTest extends SapphireTest
*/ */
public function testSanitiseExtraMeta(string $extraMeta, string $expected, string $message): void public function testSanitiseExtraMeta(string $extraMeta, string $expected, string $message): void
{ {
// If using HTML5Value then the 'somethingdodgy' test won't be converted to valid html
// However if using the default HTMLValue, then it will be converted to valid html
$isDodgyAndUsingHTML5 = strpos($expected, 'somethingdodgy') !== false &&
(HTMLValue::create() instanceof HTML5Value);
if ($isDodgyAndUsingHTML5) {
$this->expectException(ValidationException::class);
$this->expectExceptionMessage('Custom Meta Tags does not contain valid HTML');
}
$siteTree = new SiteTree(); $siteTree = new SiteTree();
$siteTree->ExtraMeta = $extraMeta; $siteTree->ExtraMeta = $extraMeta;
$siteTree->write(); $siteTree->write();
if (!$isDodgyAndUsingHTML5) {
$this->assertSame($expected, $siteTree->ExtraMeta, $message); $this->assertSame($expected, $siteTree->ExtraMeta, $message);
} }
}
public function provideSanitiseExtraMeta(): array public function provideSanitiseExtraMeta(): array
{ {
@ -2083,50 +2118,12 @@ class SiteTreeTest extends SapphireTest
'<link rel="canonical" accesskey="X" onclick="alert(1)" name="x" />', '<link rel="canonical" accesskey="X" onclick="alert(1)" name="x" />',
'<link rel="canonical" name="x">', '<link rel="canonical" name="x">',
'Multiple attributes are removed' 'Multiple attributes are removed'
] ],
];
}
/**
* @dataProvider provideSanatiseInvalidExtraMeta
*/
public function testSanatiseInvalidExtraMetaHTML4Value(string $extraMeta, string $expected): void
{
Injector::inst()->registerService(HTML4Value::create(), HTMLValue::class);
$siteTree = new SiteTree();
$siteTree->ExtraMeta = $extraMeta;
$siteTree->write();
$this->assertSame(
$expected,
$siteTree->ExtraMeta,
'Invalid HTML is converted to valid HTML and parsed'
);
}
/**
* @dataProvider provideSanatiseInvalidExtraMeta
*/
public function testSanatiseInvalidExtraMetaHTML5Value(string $extraMeta): void
{
// HTML5Value comes from the module silverstripe/html5
if (!class_exists(HTML5Value::class)) {
$this->markTestSkipped('HTML5Value class does not exist');
}
Injector::inst()->registerService(HTML5Value::create(), HTMLValue::class);
$this->expectException(ValidationException::class);
$this->expectExceptionMessage('Custom Meta Tags does not contain valid HTML');
$siteTree = new SiteTree();
$siteTree->ExtraMeta = $extraMeta;
$siteTree->write();
}
public function provideSanatiseInvalidExtraMeta(): array
{
return [
[ [
'<link rel="canonical" href="valid" ;;// somethingdodgy < onmouseover=alert(1)', '<link rel="canonical" href="valid" ;;// somethingdodgy <onmouseover=alert(1)>',
'<link rel="canonical" href="valid" somethingdodgy="">' '<link rel="canonical" href="valid" somethingdodgy=""><onmouseover></onmouseover>',
] 'Invalid HTML is converted to valid HTML and parsed'
],
]; ];
} }

26
tests/php/Model/SiteTreeTest.yml Executable file → Normal file
View File

@ -44,7 +44,7 @@ SilverStripe\Security\Member:
securityadmin: securityadmin:
Groups: =>SilverStripe\Security\Group.securityadmins Groups: =>SilverStripe\Security\Group.securityadmins
Page: SilverStripe\CMS\Model\SiteTree:
home: home:
Title: Home Title: Home
CanEditType: OnlyTheseUsers CanEditType: OnlyTheseUsers
@ -56,14 +56,14 @@ Page:
staff: staff:
Title: Staff Title: Staff
URLSegment: my-staff URLSegment: my-staff
Parent: =>Page.about Parent: =>SilverStripe\CMS\Model\SiteTree.about
ceo: ceo:
Title: CEO Title: CEO
Parent: =>Page.staff Parent: =>SilverStripe\CMS\Model\SiteTree.staff
staffduplicate: staffduplicate:
Title: Staff Title: Staff
URLSegment: my-staff URLSegment: my-staff
Parent: =>Page.about Parent: =>SilverStripe\CMS\Model\SiteTree.about
ShowInMenus: 0 ShowInMenus: 0
products: products:
Title: Products Title: Products
@ -71,19 +71,19 @@ Page:
EditorGroups: =>SilverStripe\Security\Group.editors EditorGroups: =>SilverStripe\Security\Group.editors
product1: product1:
Title: 1.1 Test Product Title: 1.1 Test Product
Parent: =>Page.products Parent: =>SilverStripe\CMS\Model\SiteTree.products
CanEditType: Inherit CanEditType: Inherit
product2: product2:
Title: Another Product Title: Another Product
Parent: =>Page.products Parent: =>SilverStripe\CMS\Model\SiteTree.products
CanEditType: Inherit CanEditType: Inherit
product3: product3:
Title: Another Product Title: Another Product
Parent: =>Page.products Parent: =>SilverStripe\CMS\Model\SiteTree.products
CanEditType: Inherit CanEditType: Inherit
product4: product4:
Title: Another Product Title: Another Product
Parent: =>Page.products Parent: =>SilverStripe\CMS\Model\SiteTree.products
CanEditType: OnlyTheseUsers CanEditType: OnlyTheseUsers
EditorGroups: =>SilverStripe\Security\Group.admins EditorGroups: =>SilverStripe\Security\Group.admins
contact: contact:
@ -102,16 +102,16 @@ Page:
Title: 'Breadcrumbs' Title: 'Breadcrumbs'
breadcrumbs2: breadcrumbs2:
Title: 'Breadcrumbs 2' Title: 'Breadcrumbs 2'
Parent: =>Page.breadcrumbs Parent: =>SilverStripe\CMS\Model\SiteTree.breadcrumbs
breadcrumbs3: breadcrumbs3:
Title: 'Breadcrumbs 3' Title: 'Breadcrumbs 3'
Parent: =>Page.breadcrumbs2 Parent: =>SilverStripe\CMS\Model\SiteTree.breadcrumbs2
breadcrumbs4: breadcrumbs4:
Title: 'Breadcrumbs 4' Title: 'Breadcrumbs 4'
Parent: =>Page.breadcrumbs3 Parent: =>SilverStripe\CMS\Model\SiteTree.breadcrumbs3
breadcrumbs5: breadcrumbs5:
Title: 'Breadcrumbs 5' Title: 'Breadcrumbs 5'
Parent: =>Page.breadcrumbs4 Parent: =>SilverStripe\CMS\Model\SiteTree.breadcrumbs4
numeric0: numeric0:
Title: 'urlsegment is 0' Title: 'urlsegment is 0'
URLSegment: '0' URLSegment: '0'
@ -130,7 +130,7 @@ SilverStripe\CMS\Model\RedirectorPage:
SilverStripe\CMS\Tests\Model\SiteTreeTest_DataObject: SilverStripe\CMS\Tests\Model\SiteTreeTest_DataObject:
relations: relations:
Title: 'Linked DataObject' Title: 'Linked DataObject'
Pages: =>Page.home,=>Page.about,=>Page.staff Pages: =>SilverStripe\CMS\Model\SiteTree.home,=>SilverStripe\CMS\Model\SiteTree.about,=>SilverStripe\CMS\Model\SiteTree.staff
SilverStripe\CMS\Tests\Model\SiteTreeBrokenLinksTest\NotPageObject: SilverStripe\CMS\Tests\Model\SiteTreeBrokenLinksTest\NotPageObject:
object1: object1:

View File

@ -3,9 +3,9 @@
namespace SilverStripe\CMS\Tests\Model; namespace SilverStripe\CMS\Tests\Model;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use Page; use SilverStripe\CMS\Model\SiteTree;
class SiteTreeTest_AdminDenied extends Page implements TestOnly class SiteTreeTest_AdminDenied extends SiteTree implements TestOnly
{ {
private static $table_name = 'SiteTreeTest_AdminDenied'; private static $table_name = 'SiteTreeTest_AdminDenied';

View File

@ -3,18 +3,18 @@
namespace SilverStripe\CMS\Tests\Model; namespace SilverStripe\CMS\Tests\Model;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use Page; use SilverStripe\CMS\Model\SiteTree;
class SiteTreeTest_ClassA extends Page implements TestOnly class SiteTreeTest_ClassA extends SiteTree implements TestOnly
{ {
private static $table_name = 'SiteTreeTest_ClassA'; private static $table_name = 'SiteTreeTest_ClassA';
private static $need_permission = [ private static $need_permission = [
'ADMIN', 'ADMIN',
'CMS_ACCESS_CMSMain' 'CMS_ACCESS_CMSMain',
]; ];
private static $allowed_children = [ private static $allowed_children = [
SiteTreeTest_ClassB::class SiteTreeTest_ClassB::class,
]; ];
} }

View File

@ -3,14 +3,14 @@
namespace SilverStripe\CMS\Tests\Model; namespace SilverStripe\CMS\Tests\Model;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use Page; use SilverStripe\CMS\Model\SiteTree;
class SiteTreeTest_ClassB extends Page implements TestOnly class SiteTreeTest_ClassB extends SiteTree implements TestOnly
{ {
private static $table_name = 'SiteTreeTest_ClassB'; private static $table_name = 'SiteTreeTest_ClassB';
// Also allowed subclasses // Also allowed subclasses
private static $allowed_children = [ private static $allowed_children = [
SiteTreeTest_ClassC::class SiteTreeTest_ClassC::class,
]; ];
} }

View File

@ -3,9 +3,9 @@
namespace SilverStripe\CMS\Tests\Model; namespace SilverStripe\CMS\Tests\Model;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use Page; use SilverStripe\CMS\Model\SiteTree;
class SiteTreeTest_ClassC extends Page implements TestOnly class SiteTreeTest_ClassC extends SiteTree implements TestOnly
{ {
private static $table_name = 'SiteTreeTest_ClassC'; private static $table_name = 'SiteTreeTest_ClassC';

View File

@ -10,6 +10,6 @@ class SiteTreeTest_ClassCext extends SiteTreeTest_ClassC implements TestOnly
// Override SiteTreeTest_ClassC definitions // Override SiteTreeTest_ClassC definitions
private static $allowed_children = [ private static $allowed_children = [
SiteTreeTest_ClassB::class SiteTreeTest_ClassB::class,
]; ];
} }

View File

@ -3,9 +3,9 @@
namespace SilverStripe\CMS\Tests\Model; namespace SilverStripe\CMS\Tests\Model;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use Page; use SilverStripe\CMS\Model\SiteTree;
class SiteTreeTest_ClassD extends Page implements TestOnly class SiteTreeTest_ClassD extends SiteTree implements TestOnly
{ {
private static $table_name = 'SiteTreeTest_ClassD'; private static $table_name = 'SiteTreeTest_ClassD';

View File

@ -4,9 +4,9 @@ namespace SilverStripe\CMS\Tests\Model;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use SilverStripe\ORM\HiddenClass; use SilverStripe\ORM\HiddenClass;
use Page; use SilverStripe\CMS\Model\SiteTree;
class SiteTreeTest_ClassE extends Page implements TestOnly, HiddenClass class SiteTreeTest_ClassE extends SiteTree implements TestOnly, HiddenClass
{ {
private static $table_name = 'SiteTreeTest_ClassE'; private static $table_name = 'SiteTreeTest_ClassE';
} }

View File

@ -3,9 +3,9 @@
namespace SilverStripe\CMS\Tests\Model; namespace SilverStripe\CMS\Tests\Model;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use Page; use SilverStripe\CMS\Model\SiteTree;
class SiteTreeTest_Conflicted extends Page implements TestOnly class SiteTreeTest_Conflicted extends SiteTree implements TestOnly
{ {
private static $table_name = 'SiteTreeTest_Conflicted'; private static $table_name = 'SiteTreeTest_Conflicted';
} }

View File

@ -3,12 +3,12 @@
namespace SilverStripe\CMS\Tests\Model; namespace SilverStripe\CMS\Tests\Model;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use PageController; use SilverStripe\CMS\Controllers\ContentController;
class SiteTreeTest_ConflictedController extends PageController implements TestOnly class SiteTreeTest_ConflictedController extends ContentController implements TestOnly
{ {
private static $allowed_actions = [ private static $allowed_actions = [
'conflicted-action' 'conflicted-action',
]; ];
public function hasActionTemplate($template) public function hasActionTemplate($template)

View File

@ -3,12 +3,12 @@
namespace SilverStripe\CMS\Tests\Model; namespace SilverStripe\CMS\Tests\Model;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use Page; use SilverStripe\CMS\Model\SiteTree;
/** /**
* An empty SiteTree instance with a controller to test that legacy controller names can still be loaded * An empty SiteTree instance with a controller to test that legacy controller names can still be loaded
*/ */
class SiteTreeTest_LegacyControllerName extends Page implements TestOnly class SiteTreeTest_LegacyControllerName extends SiteTree implements TestOnly
{ {
private static $table_name = 'SiteTreeTest_LegacyControllerName'; private static $table_name = 'SiteTreeTest_LegacyControllerName';
} }

View File

@ -3,9 +3,8 @@
namespace SilverStripe\CMS\Tests\Model; namespace SilverStripe\CMS\Tests\Model;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use PageController; use SilverStripe\CMS\Controllers\ContentController;
class SiteTreeTest_LegacyControllerName_Controller extends PageController implements TestOnly class SiteTreeTest_LegacyControllerName_Controller extends ContentController implements TestOnly
{ {
} }

View File

@ -3,9 +3,9 @@
namespace SilverStripe\CMS\Tests\Model; namespace SilverStripe\CMS\Tests\Model;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use Page; use SilverStripe\CMS\Model\SiteTree;
class SiteTreeTest_NotRoot extends Page implements TestOnly class SiteTreeTest_NotRoot extends SiteTree implements TestOnly
{ {
private static $table_name = 'SiteTreeTest_NotRoot'; private static $table_name = 'SiteTreeTest_NotRoot';

View File

@ -3,9 +3,9 @@
namespace SilverStripe\CMS\Tests\Model; namespace SilverStripe\CMS\Tests\Model;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use Page; use SilverStripe\CMS\Model\SiteTree;
class SiteTreeTest_PageNode extends Page implements TestOnly class SiteTreeTest_PageNode extends SiteTree implements TestOnly
{ {
private static $table_name = 'SiteTreeTest_PageNode'; private static $table_name = 'SiteTreeTest_PageNode';
} }

View File

@ -3,8 +3,8 @@
namespace SilverStripe\CMS\Tests\Model; namespace SilverStripe\CMS\Tests\Model;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use PageController; use SilverStripe\CMS\Controllers\ContentController;
class SiteTreeTest_PageNodeController extends PageController implements TestOnly class SiteTreeTest_PageNodeController extends ContentController implements TestOnly
{ {
} }

View File

@ -2,7 +2,6 @@
namespace SilverStripe\CMS\Tests\Model; namespace SilverStripe\CMS\Tests\Model;
use Page;
use SilverStripe\CMS\Controllers\ModelAsController; use SilverStripe\CMS\Controllers\ModelAsController;
use SilverStripe\CMS\Model\RedirectorPage; use SilverStripe\CMS\Model\RedirectorPage;
use SilverStripe\CMS\Model\SiteTree; use SilverStripe\CMS\Model\SiteTree;
@ -43,8 +42,8 @@ class VirtualPageTest extends FunctionalTest
protected static $required_extensions = [ protected static $required_extensions = [
SiteTree::class => [ SiteTree::class => [
VirtualPageTest_PageExtension::class VirtualPageTest_PageExtension::class,
] ],
]; ];
protected function setUp(): void protected function setUp(): void
@ -63,8 +62,8 @@ class VirtualPageTest extends FunctionalTest
); );
// Ensure all pages are published // Ensure all pages are published
/** @var Page $page */ /** @var SiteTree $page */
foreach (Page::get() as $page) { foreach (SiteTree::get() as $page) {
$page->publishSingle(); $page->publishSingle();
} }
} }
@ -75,8 +74,8 @@ class VirtualPageTest extends FunctionalTest
*/ */
public function testEditingSourcePageUpdatesVirtualPages() public function testEditingSourcePageUpdatesVirtualPages()
{ {
/** @var Page $master */ /** @var SiteTree $master */
$master = $this->objFromFixture('Page', 'master'); $master = $this->objFromFixture(SiteTree::class, 'master');
$master->Title = "New title"; $master->Title = "New title";
$master->MenuTitle = "New menutitle"; $master->MenuTitle = "New menutitle";
$master->Content = "<p>New content</p>"; $master->Content = "<p>New content</p>";
@ -97,7 +96,7 @@ class VirtualPageTest extends FunctionalTest
public function testMetaTags() public function testMetaTags()
{ {
$this->logInWithPermission('ADMIN'); $this->logInWithPermission('ADMIN');
$master = $this->objFromFixture('Page', 'master'); $master = $this->objFromFixture(SiteTree::class, 'master');
$vp1 = $this->objFromFixture(VirtualPage::class, 'vp1'); $vp1 = $this->objFromFixture(VirtualPage::class, 'vp1');
// Test with title // Test with title
@ -118,8 +117,8 @@ class VirtualPageTest extends FunctionalTest
{ {
$this->logInWithPermission('ADMIN'); $this->logInWithPermission('ADMIN');
/** @var Page $master */ /** @var SiteTree $master */
$master = $this->objFromFixture('Page', 'master'); $master = $this->objFromFixture(SiteTree::class, 'master');
$master->publishRecursive(); $master->publishRecursive();
$master->Title = "New title"; $master->Title = "New title";
@ -160,13 +159,13 @@ class VirtualPageTest extends FunctionalTest
$vp = new VirtualPage(); $vp = new VirtualPage();
$vp->write(); $vp->write();
$vp->CopyContentFromID = $this->idFromFixture('Page', 'master'); $vp->CopyContentFromID = $this->idFromFixture(SiteTree::class, 'master');
$vp->write(); $vp->write();
$this->assertEquals("My Page", $vp->Title); $this->assertEquals("My Page", $vp->Title);
$this->assertEquals("My Page Nav", $vp->MenuTitle); $this->assertEquals("My Page Nav", $vp->MenuTitle);
$vp->CopyContentFromID = $this->idFromFixture('Page', 'master2'); $vp->CopyContentFromID = $this->idFromFixture(SiteTree::class, 'master2');
$vp->write(); $vp->write();
$this->assertEquals("My Other Page", $vp->Title); $this->assertEquals("My Other Page", $vp->Title);
@ -180,7 +179,7 @@ class VirtualPageTest extends FunctionalTest
*/ */
public function testPublishingAVirtualPageCopiedPublishedContentNotDraftContent() public function testPublishingAVirtualPageCopiedPublishedContentNotDraftContent()
{ {
$p = new Page(); $p = new SiteTree();
$p->Content = "published content"; $p->Content = "published content";
$p->write(); $p->write();
$p->publishRecursive(); $p->publishRecursive();
@ -220,7 +219,7 @@ class VirtualPageTest extends FunctionalTest
public function testCantPublishVirtualPagesBeforeTheirSource() public function testCantPublishVirtualPagesBeforeTheirSource()
{ {
// An unpublished source page // An unpublished source page
$p = new Page(); $p = new SiteTree();
$p->Content = "test content"; $p->Content = "test content";
$p->write(); $p->write();
@ -241,7 +240,7 @@ class VirtualPageTest extends FunctionalTest
public function testCanEdit() public function testCanEdit()
{ {
$parentPage = $this->objFromFixture('Page', 'master3'); $parentPage = $this->objFromFixture(SiteTree::class, 'master3');
$virtualPage = $this->objFromFixture(VirtualPage::class, 'vp3'); $virtualPage = $this->objFromFixture(VirtualPage::class, 'vp3');
$bob = $this->objFromFixture(Member::class, 'bob'); $bob = $this->objFromFixture(Member::class, 'bob');
$andrew = $this->objFromFixture(Member::class, 'andrew'); $andrew = $this->objFromFixture(Member::class, 'andrew');
@ -259,8 +258,8 @@ class VirtualPageTest extends FunctionalTest
public function testCanView() public function testCanView()
{ {
/** @var Page $parentPage */ /** @var SiteTree $parentPage */
$parentPage = $this->objFromFixture('Page', 'master3'); $parentPage = $this->objFromFixture(SiteTree::class, 'master3');
$parentPage->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE); $parentPage->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
/** @var VirtualPage $virtualPage */ /** @var VirtualPage $virtualPage */
@ -283,7 +282,7 @@ class VirtualPageTest extends FunctionalTest
public function testVirtualPagesArentInappropriatelyPublished() public function testVirtualPagesArentInappropriatelyPublished()
{ {
// Fixture // Fixture
$p = new Page(); $p = new SiteTree();
$p->Content = "test content"; $p->Content = "test content";
$p->write(); $p->write();
$vp = new VirtualPage(); $vp = new VirtualPage();
@ -332,7 +331,7 @@ class VirtualPageTest extends FunctionalTest
public function testUnpublishingSourcePageOfAVirtualPageAlsoUnpublishesVirtualPage() public function testUnpublishingSourcePageOfAVirtualPageAlsoUnpublishesVirtualPage()
{ {
// Create page and virutal page // Create page and virutal page
$p = new Page(); $p = new SiteTree();
$p->Title = "source"; $p->Title = "source";
$p->write(); $p->write();
$this->assertTrue($p->publishRecursive()); $this->assertTrue($p->publishRecursive());
@ -364,7 +363,7 @@ class VirtualPageTest extends FunctionalTest
public function testDeletingFromLiveSourcePageOfAVirtualPageAlsoUnpublishesVirtualPage() public function testDeletingFromLiveSourcePageOfAVirtualPageAlsoUnpublishesVirtualPage()
{ {
// Create page and virutal page // Create page and virutal page
$p = new Page(); $p = new SiteTree();
$p->Title = "source"; $p->Title = "source";
$p->write(); $p->write();
$this->assertTrue($p->publishRecursive()); $this->assertTrue($p->publishRecursive());
@ -384,7 +383,7 @@ class VirtualPageTest extends FunctionalTest
->byID($pID); ->byID($pID);
$this->assertNull($vpDraft); $this->assertNull($vpDraft);
// Delete the source page form live, confirm that the virtual page has also been unpublished // Delete the source page form live, confirm that the virtual page has also been unpublished
/** @var Page $pLive */ /** @var SiteTree $pLive */
$pLive = Versioned::get_by_stage(SiteTree::class, Versioned::LIVE) $pLive = Versioned::get_by_stage(SiteTree::class, Versioned::LIVE)
->byID($pID); ->byID($pID);
$this->assertTrue($pLive->doUnpublish()); $this->assertTrue($pLive->doUnpublish());

View File

@ -31,7 +31,7 @@ SilverStripe\Security\Member:
alice: alice:
Email: alice@alice.com Email: alice@alice.com
Groups: =>SilverStripe\Security\Group.alicegroup Groups: =>SilverStripe\Security\Group.alicegroup
Page: SilverStripe\CMS\Model\SiteTree:
master: master:
Title: My Page Title: My Page
MenuTitle: My Page Nav MenuTitle: My Page Nav
@ -52,15 +52,15 @@ SilverStripe\CMS\Tests\Model\VirtualPageTest_ClassA:
SilverStripe\CMS\Model\VirtualPage: SilverStripe\CMS\Model\VirtualPage:
vp1: vp1:
Title: vp1 Title: vp1
CopyContentFrom: =>Page.master CopyContentFrom: =>SilverStripe\CMS\Model\SiteTree.master
Parent: =>Page.holder Parent: =>SilverStripe\CMS\Model\SiteTree.holder
vp2: vp2:
Title: vp2 Title: vp2
CopyContentFrom: =>Page.master CopyContentFrom: =>SilverStripe\CMS\Model\SiteTree.master
Parent: =>Page.holder Parent: =>SilverStripe\CMS\Model\SiteTree.holder
vp3: vp3:
CopyContentFrom: =>Page.master3 CopyContentFrom: =>SilverStripe\CMS\Model\SiteTree.master3
Parent: =>Page.holder Parent: =>SilverStripe\CMS\Model\SiteTree.holder
CanEditType: OnlyTheseUsers CanEditType: OnlyTheseUsers
CanViewType: OnlyTheseUsers CanViewType: OnlyTheseUsers
EditorGroups: =>SilverStripe\Security\Group.andrewgroup EditorGroups: =>SilverStripe\Security\Group.andrewgroup

View File

@ -3,9 +3,9 @@
namespace SilverStripe\CMS\Tests\Model; namespace SilverStripe\CMS\Tests\Model;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use Page; use SilverStripe\CMS\Model\SiteTree;
class VirtualPageTest_ClassA extends Page implements TestOnly class VirtualPageTest_ClassA extends SiteTree implements TestOnly
{ {
private static $table_name = 'VirtualPageTest_ClassA'; private static $table_name = 'VirtualPageTest_ClassA';

View File

@ -3,12 +3,12 @@
namespace SilverStripe\CMS\Tests\Model; namespace SilverStripe\CMS\Tests\Model;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use PageController; use SilverStripe\CMS\Controllers\ContentController;
class VirtualPageTest_ClassAController extends PageController implements TestOnly class VirtualPageTest_ClassAController extends ContentController implements TestOnly
{ {
private static $allowed_actions = [ private static $allowed_actions = [
'testaction' 'testaction',
]; ];
public function testMethod() public function testMethod()

View File

@ -3,9 +3,9 @@
namespace SilverStripe\CMS\Tests\Model; namespace SilverStripe\CMS\Tests\Model;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use Page; use SilverStripe\CMS\Model\SiteTree;
class VirtualPageTest_ClassB extends Page implements TestOnly class VirtualPageTest_ClassB extends SiteTree implements TestOnly
{ {
private static $table_name = 'VirtualPageTest_ClassB'; private static $table_name = 'VirtualPageTest_ClassB';

View File

@ -3,9 +3,9 @@
namespace SilverStripe\CMS\Tests\Model; namespace SilverStripe\CMS\Tests\Model;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use Page; use SilverStripe\CMS\Model\SiteTree;
class VirtualPageTest_ClassC extends Page implements TestOnly class VirtualPageTest_ClassC extends SiteTree implements TestOnly
{ {
private static $table_name = 'VirtualPageTest_ClassC'; private static $table_name = 'VirtualPageTest_ClassC';

View File

@ -3,9 +3,9 @@
namespace SilverStripe\CMS\Tests\Model; namespace SilverStripe\CMS\Tests\Model;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use Page; use SilverStripe\CMS\Model\SiteTree;
class VirtualPageTest_NotRoot extends Page implements TestOnly class VirtualPageTest_NotRoot extends SiteTree implements TestOnly
{ {
private static $table_name = 'VirtualPageTest_NotRoot'; private static $table_name = 'VirtualPageTest_NotRoot';

View File

@ -9,7 +9,8 @@ class VirtualPageTest_PageExtension extends DataExtension implements TestOnly
{ {
private static $db = [ private static $db = [
// These fields are just on an extension to simulate shared properties between Page and VirtualPage. // These fields are just on an extension to simulate shared properties between Page and VirtualPage.
// Not possible through direct $db definitions due to VirtualPage inheriting from Page, and Page being defined elsewhere. // Not possible through direct $db definitions due to VirtualPage inheriting from Page,
// and Page being defined elsewhere.
'MySharedVirtualField' => 'Text', 'MySharedVirtualField' => 'Text',
'MySharedNonVirtualField' => 'Text', 'MySharedNonVirtualField' => 'Text',
]; ];

View File

@ -4,9 +4,9 @@ namespace SilverStripe\CMS\Tests\Model;
use SilverStripe\CMS\Model\VirtualPage; use SilverStripe\CMS\Model\VirtualPage;
use SilverStripe\Dev\TestOnly; use SilverStripe\Dev\TestOnly;
use Page; use SilverStripe\CMS\Model\SiteTree;
class VirtualPageTest_PageWithAllowedChildren extends Page implements TestOnly class VirtualPageTest_PageWithAllowedChildren extends SiteTree implements TestOnly
{ {
private static $table_name = 'VirtualPageTest_PageWithAllowedChildren'; private static $table_name = 'VirtualPageTest_PageWithAllowedChildren';

View File

@ -2,24 +2,22 @@
namespace SilverStripe\CMS\Tests\Reports; namespace SilverStripe\CMS\Tests\Reports;
use SilverStripe\Assets\File;
use SilverStripe\CMS\Model\RedirectorPage;
use SilverStripe\CMS\Model\SiteTree; use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\CMS\Model\VirtualPage;
use SilverStripe\CMS\Reports\BrokenFilesReport;
use SilverStripe\CMS\Reports\BrokenLinksReport;
use SilverStripe\CMS\Reports\BrokenRedirectorPagesReport;
use SilverStripe\CMS\Reports\BrokenVirtualPagesReport;
use SilverStripe\CMS\Reports\RecentlyEditedReport;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\ORM\DB; use SilverStripe\ORM\DB;
use SilverStripe\ORM\FieldType\DBDatetime; use SilverStripe\ORM\FieldType\DBDatetime;
use SilverStripe\CMS\Reports\RecentlyEditedReport;
use SilverStripe\CMS\Reports\BrokenLinksReport;
use SilverStripe\CMS\Reports\BrokenFilesReport;
use SilverStripe\CMS\Model\VirtualPage;
use SilverStripe\CMS\Reports\BrokenVirtualPagesReport;
use SilverStripe\CMS\Model\RedirectorPage;
use SilverStripe\CMS\Reports\BrokenRedirectorPagesReport;
use SilverStripe\Reports\Report; use SilverStripe\Reports\Report;
use SilverStripe\Assets\File;
use SilverStripe\Dev\SapphireTest;
use Page;
class CmsReportsTest extends SapphireTest class CmsReportsTest extends SapphireTest
{ {
protected static $fixture_file = 'CmsReportsTest.yml'; protected static $fixture_file = 'CmsReportsTest.yml';
private static $daysAgo = 14; private static $daysAgo = 14;
@ -34,9 +32,14 @@ class CmsReportsTest extends SapphireTest
$after = $this->objFromFixture(SiteTree::class, 'after'); $after = $this->objFromFixture(SiteTree::class, 'after');
$before = $this->objFromFixture(SiteTree::class, 'before'); $before = $this->objFromFixture(SiteTree::class, 'before');
DB::query(
DB::query("UPDATE \"SiteTree\" SET \"Created\"='2009-01-01 00:00:00', \"LastEdited\"='".date('Y-m-d H:i:s', $afterThreshold)."' WHERE \"ID\"='".$after->ID."'"); "UPDATE \"SiteTree\" SET \"Created\"='2009-01-01 00:00:00', \"LastEdited\"='" .
DB::query("UPDATE \"SiteTree\" SET \"Created\"='2009-01-01 00:00:00', \"LastEdited\"='".date('Y-m-d H:i:s', $beforeThreshold)."' WHERE \"ID\"='".$before->ID."'"); date('Y-m-d H:i:s', $afterThreshold) . "' WHERE \"ID\"='" . $after->ID . "'"
);
DB::query(
"UPDATE \"SiteTree\" SET \"Created\"='2009-01-01 00:00:00', \"LastEdited\"='" .
date('Y-m-d H:i:s', $beforeThreshold) . "' WHERE \"ID\"='" . $before->ID . "'"
);
} }
/** /**
@ -52,13 +55,27 @@ class CmsReportsTest extends SapphireTest
// ASSERT that the "draft" report is returning the correct results. // ASSERT that the "draft" report is returning the correct results.
$parameters = ['CheckSite' => 'Draft']; $parameters = ['CheckSite' => 'Draft'];
$results = count($report->sourceRecords($parameters, null, null) ?? []) > 0; $results = count($report->sourceRecords($parameters, null, null)) > 0;
$isDraftBroken ? $this->assertTrue($results, "{$class} has NOT returned the correct DRAFT results, as NO pages were found.") : $this->assertFalse($results, "{$class} has NOT returned the correct DRAFT results, as pages were found."); $isDraftBroken
? $this->assertTrue(
$results,
"{$class} has NOT returned the correct DRAFT results, as NO pages were found."
) : $this->assertFalse(
$results,
"{$class} has NOT returned the correct DRAFT results, as pages were found."
);
// ASSERT that the "published" report is returning the correct results. // ASSERT that the "published" report is returning the correct results.
$parameters = ['CheckSite' => 'Published', 'OnLive' => 1]; $parameters = ['CheckSite' => 'Published', 'OnLive' => 1];
$results = count($report->sourceRecords($parameters, null, null) ?? []) > 0; $results = count($report->sourceRecords($parameters, null, null) ?? []) > 0;
$isPublishedBroken ? $this->assertTrue($results, "{$class} has NOT returned the correct PUBLISHED results, as NO pages were found.") : $this->assertFalse($results, "{$class} has NOT returned the correct PUBLISHED results, as pages were found."); $isPublishedBroken
? $this->assertTrue(
$results,
"{$class} has NOT returned the correct PUBLISHED results, as NO pages were found."
) : $this->assertFalse(
$results,
"{$class} has NOT returned the correct PUBLISHED results, as pages were found."
);
} }
public function testRecentlyEdited() public function testRecentlyEdited()
@ -81,18 +98,14 @@ class CmsReportsTest extends SapphireTest
/** /**
* Test the broken links side report. * Test the broken links side report.
*/ */
public function testBrokenLinks() public function testBrokenLinks()
{ {
// Create a "draft" page with a broken link. // Create a "draft" page with a broken link.
$page = new SiteTree();
$page = Page::create();
$page->Content = "<a href='[sitetree_link,id=987654321]'>This</a> is a broken link."; $page->Content = "<a href='[sitetree_link,id=987654321]'>This</a> is a broken link.";
$page->writeToStage('Stage'); $page->writeToStage('Stage');
// Retrieve the broken links side report. // Retrieve the broken links side report.
$reports = Report::get_reports(); $reports = Report::get_reports();
$brokenLinksReport = null; $brokenLinksReport = null;
foreach ($reports as $report) { foreach ($reports as $report) {
@ -109,12 +122,11 @@ class CmsReportsTest extends SapphireTest
} }
// ASSERT that the "draft" report has detected the page having a broken link. // ASSERT that the "draft" report has detected the page having a broken link.
// ASSERT that the "published" report has NOT detected the page having a broken link, as the page has not been "published" yet. // ASSERT that the "published" report has NOT detected the page having a broken link,
// as the page has not been "published" yet.
$this->isReportBroken($brokenLinksReport, true, false); $this->isReportBroken($brokenLinksReport, true, false);
// Make sure the page is now "published". // Make sure the page is now "published".
$page->writeToStage('Live'); $page->writeToStage('Live');
// ASSERT that the "draft" report has detected the page having a broken link. // ASSERT that the "draft" report has detected the page having a broken link.
@ -123,17 +135,15 @@ class CmsReportsTest extends SapphireTest
$this->isReportBroken($brokenLinksReport, true, true); $this->isReportBroken($brokenLinksReport, true, true);
// Correct the "draft" broken link. // Correct the "draft" broken link.
$page->Content = str_replace('987654321', $page->ID ?? '', $page->Content ?? ''); $page->Content = str_replace('987654321', $page->ID ?? '', $page->Content ?? '');
$page->writeToStage('Stage'); $page->writeToStage('Stage');
// ASSERT that the "draft" report has NOT detected the page having a broken link. // ASSERT that the "draft" report has NOT detected the page having a broken link.
// ASSERT that the "published" report has detected the page having a broken link, as the previous content remains "published". // ASSERT that the "published" report has detected the page having a broken link,
// as the previous content remains "published".
$this->isReportBroken($brokenLinksReport, false, true); $this->isReportBroken($brokenLinksReport, false, true);
// Make sure the change has now been "published". // Make sure the change has now been "published".
$page->writeToStage('Live'); $page->writeToStage('Live');
// ASSERT that the "draft" report has NOT detected the page having a broken link. // ASSERT that the "draft" report has NOT detected the page having a broken link.
@ -145,18 +155,14 @@ class CmsReportsTest extends SapphireTest
/** /**
* Test the broken files side report. * Test the broken files side report.
*/ */
public function testBrokenFiles() public function testBrokenFiles()
{ {
// Create a "draft" page with a broken file. // Create a "draft" page with a broken file.
$page = new SiteTree();
$page = Page::create();
$page->Content = "<a href='[file_link,id=987654321]'>This</a> is a broken file."; $page->Content = "<a href='[file_link,id=987654321]'>This</a> is a broken file.";
$page->writeToStage('Stage'); $page->writeToStage('Stage');
// Retrieve the broken files side report. // Retrieve the broken files side report.
$reports = Report::get_reports(); $reports = Report::get_reports();
$brokenFilesReport = null; $brokenFilesReport = null;
foreach ($reports as $report) { foreach ($reports as $report) {
@ -173,21 +179,18 @@ class CmsReportsTest extends SapphireTest
} }
// ASSERT that the "draft" report has detected the page having a broken file. // ASSERT that the "draft" report has detected the page having a broken file.
// ASSERT that the "published" report has NOT detected the page having a broken file, as the page has not been "published" yet. // ASSERT that the "published" report has NOT detected the page having a broken file,
// as the page has not been "published" yet.
$this->isReportBroken($brokenFilesReport, true, false); $this->isReportBroken($brokenFilesReport, true, false);
// Make sure the page is now "published". // Make sure the page is now "published".
$page->writeToStage('Live'); $page->writeToStage('Live');
// ASSERT that the "draft" report has detected the page having a broken file. // ASSERT that the "draft" report has detected the page having a broken file.
// ASSERT that the "published" report has detected the page having a broken file. // ASSERT that the "published" report has detected the page having a broken file.
$this->isReportBroken($brokenFilesReport, true, true); $this->isReportBroken($brokenFilesReport, true, true);
// Correct the "draft" broken file. // Correct the "draft" broken file.
$file = File::create(); $file = File::create();
$file->Filename = 'name.pdf'; $file->Filename = 'name.pdf';
$file->write(); $file->write();
@ -195,17 +198,15 @@ class CmsReportsTest extends SapphireTest
$page->writeToStage('Stage'); $page->writeToStage('Stage');
// ASSERT that the "draft" report has NOT detected the page having a broken file. // ASSERT that the "draft" report has NOT detected the page having a broken file.
// ASSERT that the "published" report has detected the page having a broken file, as the previous content remains "published". // ASSERT that the "published" report has detected the page having a broken file,
// as the previous content remains "published".
$this->isReportBroken($brokenFilesReport, false, true); $this->isReportBroken($brokenFilesReport, false, true);
// Make sure the change has now been "published". // Make sure the change has now been "published".
$page->writeToStage('Live'); $page->writeToStage('Live');
// ASSERT that the "draft" report has NOT detected the page having a broken file. // ASSERT that the "draft" report has NOT detected the page having a broken file.
// ASSERT that the "published" report has NOT detected the page having a broken file. // ASSERT that the "published" report has NOT detected the page having a broken file.
$this->isReportBroken($brokenFilesReport, false, false); $this->isReportBroken($brokenFilesReport, false, false);
} }
@ -215,15 +216,12 @@ class CmsReportsTest extends SapphireTest
public function testBrokenVirtualPages() public function testBrokenVirtualPages()
{ {
// Create a "draft" virtual page with a broken link. // Create a "draft" virtual page with a broken link.
$page = VirtualPage::create(); $page = VirtualPage::create();
$page->CopyContentFromID = 987654321; $page->CopyContentFromID = 987654321;
$page->writeToStage('Stage'); $page->writeToStage('Stage');
// Retrieve the broken virtual pages side report. // Retrieve the broken virtual pages side report.
$reports = Report::get_reports(); $reports = Report::get_reports();
$brokenVirtualPagesReport = null; $brokenVirtualPagesReport = null;
foreach ($reports as $report) { foreach ($reports as $report) {
@ -240,22 +238,19 @@ class CmsReportsTest extends SapphireTest
} }
// ASSERT that the "draft" report has detected the page having a broken link. // ASSERT that the "draft" report has detected the page having a broken link.
// ASSERT that the "published" report has NOT detected the page having a broken link, as the page has not been "published" yet. // ASSERT that the "published" report has NOT detected the page having a broken link,
// as the page has not been "published" yet.
$this->isReportBroken($brokenVirtualPagesReport, true, false); $this->isReportBroken($brokenVirtualPagesReport, true, false);
// Make sure the page is now "published". // Make sure the page is now "published".
$page->writeToStage('Live'); $page->writeToStage('Live');
// ASSERT that the "draft" report has detected the page having a broken link. // ASSERT that the "draft" report has detected the page having a broken link.
// ASSERT that the "published" report has detected the page having a broken link. // ASSERT that the "published" report has detected the page having a broken link.
$this->isReportBroken($brokenVirtualPagesReport, true, true); $this->isReportBroken($brokenVirtualPagesReport, true, true);
// Correct the "draft" broken link. // Correct the "draft" broken link.
$contentPage = new SiteTree();
$contentPage = Page::create();
$contentPage->Content = 'This is some content.'; $contentPage->Content = 'This is some content.';
$contentPage->writeToStage('Stage'); $contentPage->writeToStage('Stage');
$contentPage->writeToStage('Live'); $contentPage->writeToStage('Live');
@ -263,36 +258,30 @@ class CmsReportsTest extends SapphireTest
$page->writeToStage('Stage'); $page->writeToStage('Stage');
// ASSERT that the "draft" report has NOT detected the page having a broken link. // ASSERT that the "draft" report has NOT detected the page having a broken link.
// ASSERT that the "published" report has detected the page having a broken link, as the previous content remains "published". // ASSERT that the "published" report has detected the page having a broken link,
// as the previous content remains "published".
$this->isReportBroken($brokenVirtualPagesReport, false, true); $this->isReportBroken($brokenVirtualPagesReport, false, true);
// Make sure the change has now been "published". // Make sure the change has now been "published".
$page->writeToStage('Live'); $page->writeToStage('Live');
// ASSERT that the "draft" report has NOT detected the page having a broken link. // ASSERT that the "draft" report has NOT detected the page having a broken link.
// ASSERT that the "published" report has NOT detected the page having a broken link. // ASSERT that the "published" report has NOT detected the page having a broken link.
$this->isReportBroken($brokenVirtualPagesReport, false, false); $this->isReportBroken($brokenVirtualPagesReport, false, false);
} }
/** /**
* Test the broken redirector pages side report. * Test the broken redirector pages side report.
*/ */
public function testBrokenRedirectorPages() public function testBrokenRedirectorPages()
{ {
// Create a "draft" redirector page with a broken link. // Create a "draft" redirector page with a broken link.
$page = RedirectorPage::create(); $page = RedirectorPage::create();
$page->RedirectionType = 'Internal'; $page->RedirectionType = 'Internal';
$page->LinkToID = 987654321; $page->LinkToID = 987654321;
$page->writeToStage('Stage'); $page->writeToStage('Stage');
// Retrieve the broken redirector pages side report. // Retrieve the broken redirector pages side report.
$reports = Report::get_reports(); $reports = Report::get_reports();
$brokenRedirectorPagesReport = null; $brokenRedirectorPagesReport = null;
foreach ($reports as $report) { foreach ($reports as $report) {
@ -309,22 +298,19 @@ class CmsReportsTest extends SapphireTest
} }
// ASSERT that the "draft" report has detected the page having a broken link. // ASSERT that the "draft" report has detected the page having a broken link.
// ASSERT that the "published" report has NOT detected the page having a broken link, as the page has not been "published" yet. // ASSERT that the "published" report has NOT detected the page having a broken link,
// as the page has not been "published" yet.
$this->isReportBroken($brokenRedirectorPagesReport, true, false); $this->isReportBroken($brokenRedirectorPagesReport, true, false);
// Make sure the page is now "published". // Make sure the page is now "published".
$page->writeToStage('Live'); $page->writeToStage('Live');
// ASSERT that the "draft" report has detected the page having a broken link. // ASSERT that the "draft" report has detected the page having a broken link.
// ASSERT that the "published" report has detected the page having a broken link. // ASSERT that the "published" report has detected the page having a broken link.
$this->isReportBroken($brokenRedirectorPagesReport, true, true); $this->isReportBroken($brokenRedirectorPagesReport, true, true);
// Correct the "draft" broken link. // Correct the "draft" broken link.
$contentPage = new SiteTree();
$contentPage = Page::create();
$contentPage->Content = 'This is some content.'; $contentPage->Content = 'This is some content.';
$contentPage->writeToStage('Stage'); $contentPage->writeToStage('Stage');
$contentPage->writeToStage('Live'); $contentPage->writeToStage('Live');
@ -332,17 +318,15 @@ class CmsReportsTest extends SapphireTest
$page->writeToStage('Stage'); $page->writeToStage('Stage');
// ASSERT that the "draft" report has NOT detected the page having a broken link. // ASSERT that the "draft" report has NOT detected the page having a broken link.
// ASSERT that the "published" report has detected the page having a broken link, as the previous content remains "published". // ASSERT that the "published" report has detected the page having a broken link,
// as the previous content remains "published".
$this->isReportBroken($brokenRedirectorPagesReport, false, true); $this->isReportBroken($brokenRedirectorPagesReport, false, true);
// Make sure the change has now been "published". // Make sure the change has now been "published".
$page->writeToStage('Live'); $page->writeToStage('Live');
// ASSERT that the "draft" report has NOT detected the page having a broken link. // ASSERT that the "draft" report has NOT detected the page having a broken link.
// ASSERT that the "published" report has NOT detected the page having a broken link. // ASSERT that the "published" report has NOT detected the page having a broken link.
$this->isReportBroken($brokenRedirectorPagesReport, false, false); $this->isReportBroken($brokenRedirectorPagesReport, false, false);
} }
} }

View File

@ -20,7 +20,7 @@ class CMSMainSearchFormTest extends FunctionalTest
'q' => [ 'q' => [
'Term' => 'Page 10', 'Term' => 'Page 10',
'FilterClass' => CMSSiteTreeFilter_Search::class, 'FilterClass' => CMSSiteTreeFilter_Search::class,
] ],
]) ])
); );

View File

@ -2,7 +2,6 @@
namespace SilverStripe\CMS\Tests\Search; namespace SilverStripe\CMS\Tests\Search;
use Page;
use SilverStripe\Assets\File; use SilverStripe\Assets\File;
use SilverStripe\CMS\Controllers\ContentController; use SilverStripe\CMS\Controllers\ContentController;
use SilverStripe\CMS\Controllers\ModelAsController; use SilverStripe\CMS\Controllers\ModelAsController;
@ -22,14 +21,10 @@ use SilverStripe\Versioned\Versioned;
use TractorCow\Fluent\Extension\FluentSiteTreeExtension; use TractorCow\Fluent\Extension\FluentSiteTreeExtension;
/** /**
* @todo Fix unpublished pages check in testPublishedPagesMatchedByTitle()
* @todo All tests run on unpublished pages at the moment, due to the searchform not distinguishing between them
*
* Because this manipulates the test database in severe ways, I've renamed the test to force it to run last... * Because this manipulates the test database in severe ways, I've renamed the test to force it to run last...
*/ */
class ZZZSearchFormTest extends FunctionalTest class ZZZSearchFormTest extends FunctionalTest
{ {
protected static $fixture_file = 'ZZZSearchFormTest.yml'; protected static $fixture_file = 'ZZZSearchFormTest.yml';
protected static $illegal_extensions = [ protected static $illegal_extensions = [
@ -97,9 +92,6 @@ class ZZZSearchFormTest extends FunctionalTest
return $supports; return $supports;
} }
/**
* @skipUpgrade
*/
public function testSearchFormTemplateCanBeChanged() public function testSearchFormTemplateCanBeChanged()
{ {
if (!$this->checkFulltextSupport()) { if (!$this->checkFulltextSupport()) {
@ -116,9 +108,6 @@ class ZZZSearchFormTest extends FunctionalTest
); );
} }
/**
* @skipUpgrade
*/
public function testPublishedPagesMatchedByTitle() public function testPublishedPagesMatchedByTitle()
{ {
if (!$this->checkFulltextSupport()) { if (!$this->checkFulltextSupport()) {
@ -149,9 +138,6 @@ class ZZZSearchFormTest extends FunctionalTest
); );
} }
/**
* @skipUpgrade
*/
public function testDoubleQuotesPublishedPagesMatchedByTitle() public function testDoubleQuotesPublishedPagesMatchedByTitle()
{ {
if (!$this->checkFulltextSupport()) { if (!$this->checkFulltextSupport()) {
@ -184,9 +170,6 @@ class ZZZSearchFormTest extends FunctionalTest
); );
} }
/**
* @skipUpgrade
*/
public function testUnpublishedPagesNotIncluded() public function testUnpublishedPagesNotIncluded()
{ {
if (!$this->checkFulltextSupport()) { if (!$this->checkFulltextSupport()) {

View File

@ -1,91 +0,0 @@
<?php
namespace SilverStripe\CMS\Tests\Tasks;
use SilverStripe\CMS\Model\SiteTree;
use SilverStripe\CMS\Tasks\MigrateSiteTreeLinkingTask;
use SilverStripe\Dev\SapphireTest;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DB;
use SilverStripe\Dev\Deprecation;
class MigrateSiteTreeLinkingTaskTest extends SapphireTest
{
protected static $fixture_file = 'MigrateSiteTreeLinkingTaskTest.yml';
public static function setUpBeforeClass(): void
{
parent::setUpBeforeClass();
// Cover db reset in case parent did not start
if (!static::getExtraDataObjects()) {
DataObject::reset();
static::resetDBSchema(true, true);
}
// Ensure legacy SiteTree_LinkTracking table exists
DB::get_schema()->schemaUpdate(function () {
DB::require_table('SiteTree_LinkTracking', [
'SiteTreeID' => 'Int',
'ChildID' => 'Int',
'FieldName' => 'Varchar',
]);
});
}
protected function setUp(): void
{
if (Deprecation::isEnabled()) {
$this->markTestSkipped('Test calls deprecated code');
}
parent::setUp();
// Manually bootstrap all Content blocks with soft coded IDs (raw sql to avoid save hooks)
$replacements = [
'$$ABOUTID$$' => $this->idFromFixture(SiteTree::class, 'about'),
'$$HOMEID$$' => $this->idFromFixture(SiteTree::class, 'home'),
'$$STAFFID$$' => $this->idFromFixture(SiteTree::class, 'staff'),
];
foreach (DB::query('SELECT "ID", "Content" FROM "SiteTree"') as $row) {
$id = (int)$row['ID'];
$content = str_replace(array_keys($replacements ?? []), array_values($replacements ?? []), $row['Content'] ?? '');
DB::prepared_query('UPDATE "SiteTree" SET "Content" = ? WHERE "ID" = ?', [$content, $id]);
}
DataObject::reset();
}
public function testLinkingMigration()
{
ob_start();
DB::quiet(false);
$task = new MigrateSiteTreeLinkingTask();
$task->run(null);
$this->assertStringContainsString(
"Migrated page links on 5 Pages",
ob_get_contents(),
'Rewritten links are correctly reported'
);
DB::quiet(true);
ob_end_clean();
// Query links for pages
/** @var SiteTree $home */
$home = $this->objFromFixture(SiteTree::class, 'home');
/** @var SiteTree $about */
$about = $this->objFromFixture(SiteTree::class, 'about');
/** @var SiteTree $staff */
$staff = $this->objFromFixture(SiteTree::class, 'staff');
/** @var SiteTree $action */
$action = $this->objFromFixture(SiteTree::class, 'action');
/** @var SiteTree $hash */
$hash = $this->objFromFixture(SiteTree::class, 'hash_link');
// Ensure all links are created
$this->assertListEquals([['ID' => $about->ID], ['ID' => $staff->ID]], $home->LinkTracking());
$this->assertListEquals([['ID' => $home->ID], ['ID' => $staff->ID]], $about->LinkTracking());
$this->assertListEquals([['ID' => $home->ID], ['ID' => $about->ID]], $staff->LinkTracking());
$this->assertListEquals([['ID' => $home->ID]], $action->LinkTracking());
$this->assertListEquals([['ID' => $home->ID], ['ID' => $about->ID]], $hash->LinkTracking());
}
}

View File

@ -1,67 +0,0 @@
SilverStripe\CMS\Model\SiteTree:
home:
Title: Home Page
URLSegment: home
Content: '<a href="[sitetree_link,id=$$ABOUTID$$]">About</a><a href="[sitetree_link,id=$$STAFFID$$]">Staff</a><a href="http://silverstripe.org/">External Link</a><a name="anchor"></a>'
about:
Title: About Us
URLSegment: about
Content: '<a href="[sitetree_link,id=$$HOMEID$$]">Home</a><a href="[sitetree_link,id=$$STAFFID$$]">Staff</a><a name="second-anchor"></a>'
staff:
Title: Staff
URLSegment: staff
Content: '<a href="[sitetree_link,id=$$HOMEID$$]">Home</a><a href="[sitetree_link,id=$$ABOUTID$$]">About</a>'
Parent: =>SilverStripe\CMS\Model\SiteTree.about
action:
Title: Action Link
URLSegment: action
Content: '<a href="[sitetree_link,id=$$HOMEID$$]SearchForm">Search Form</a>'
hash_link:
Title: Hash Link
URLSegment: hash-link
Content: '<a href="[sitetree_link,id=$$HOMEID$$]#anchor">Home</a><a href="[sitetree_link,id=$$ABOUTID$$]#second-anchor">About</a>'
admin_link:
Title: Admin Link
URLSegment: admin-link
Content: '<a href="admin">Admin</a>'
no_links:
Title: No Links
URLSegment: No Links
SiteTree_LinkTracking:
home_about:
SiteTreeID: =>SilverStripe\CMS\Model\SiteTree.home
ChildID: =>SilverStripe\CMS\Model\SiteTree.about
FieldName: Content
home_staff:
SiteTreeID: =>SilverStripe\CMS\Model\SiteTree.home
ChildID: =>SilverStripe\CMS\Model\SiteTree.staff
FieldName: Content
about_home:
SiteTreeID: =>SilverStripe\CMS\Model\SiteTree.about
ChildID: =>SilverStripe\CMS\Model\SiteTree.home
FieldName: Content
about_staff:
SiteTreeID: =>SilverStripe\CMS\Model\SiteTree.about
ChildID: =>SilverStripe\CMS\Model\SiteTree.staff
FieldName: Content
staff_home:
SiteTreeID: =>SilverStripe\CMS\Model\SiteTree.staff
ChildID: =>SilverStripe\CMS\Model\SiteTree.home
FieldName: Content
staff_about:
SiteTreeID: =>SilverStripe\CMS\Model\SiteTree.staff
ChildID: =>SilverStripe\CMS\Model\SiteTree.about
FieldName: Content
action_home:
SiteTreeID: =>SilverStripe\CMS\Model\SiteTree.action
ChildID: =>SilverStripe\CMS\Model\SiteTree.home
FieldName: Content
hash_link_home:
SiteTreeID: =>SilverStripe\CMS\Model\SiteTree.hash_link
ChildID: =>SilverStripe\CMS\Model\SiteTree.home
FieldName: Content
hash_link_about:
SiteTreeID: =>SilverStripe\CMS\Model\SiteTree.hash_link
ChildID: =>SilverStripe\CMS\Model\SiteTree.about
FieldName: Content

View File

@ -1,113 +0,0 @@
<?php
namespace SilverStripe\CMS\Tests\Tasks;
use SilverStripe\CMS\Tasks\RemoveOrphanedPagesTask;
use SilverStripe\Versioned\Versioned;
use SilverStripe\Dev\FunctionalTest;
use SilverStripe\Dev\Deprecation;
/**
* <h2>Fixture tree</h2>
* <code>
* parent1_published
* child1_1_published
* grandchild1_1_1
* grandchild1_1_2_published
* grandchild1_1_3_orphaned
* grandchild1_1_4_orphaned_published
* child1_2_published
* child1_3_orphaned
* child1_4_orphaned_published
* parent2
* child2_1_published_orphaned // is orphaned because parent is not published
* </code>
*
* <h2>Cleaned up tree</h2>
* <code>
* parent1_published
* child1_1_published
* grandchild1_1_1
* grandchild1_1_2_published
* child2_1_published_orphaned
* parent2
* </code>
*
* @author Ingo Schommer (<firstname>@silverstripe.com), SilverStripe Ltd.
*/
class RemoveOrphanedPagesTaskTest extends FunctionalTest
{
protected static $fixture_file = 'RemoveOrphanedPagesTaskTest.yml';
protected function setUp(): void
{
if (Deprecation::isEnabled()) {
$this->markTestSkipped('Test calls deprecated code');
}
parent::setUp();
$parent1_published = $this->objFromFixture('Page', 'parent1_published');
$parent1_published->publishSingle();
$child1_1_published = $this->objFromFixture('Page', 'child1_1_published');
$child1_1_published->publishSingle();
$child1_2_published = $this->objFromFixture('Page', 'child1_2_published');
$child1_2_published->publishSingle();
$child1_3_orphaned = $this->objFromFixture('Page', 'child1_3_orphaned');
$child1_3_orphaned->ParentID = 9999;
$child1_3_orphaned->write();
$child1_4_orphaned_published = $this->objFromFixture('Page', 'child1_4_orphaned_published');
$child1_4_orphaned_published->ParentID = 9999;
$child1_4_orphaned_published->write();
$child1_4_orphaned_published->publishSingle();
$grandchild1_1_2_published = $this->objFromFixture('Page', 'grandchild1_1_2_published');
$grandchild1_1_2_published->publishSingle();
$grandchild1_1_3_orphaned = $this->objFromFixture('Page', 'grandchild1_1_3_orphaned');
$grandchild1_1_3_orphaned->ParentID = 9999;
$grandchild1_1_3_orphaned->write();
$grandchild1_1_4_orphaned_published = $this->objFromFixture(
'Page',
'grandchild1_1_4_orphaned_published'
);
$grandchild1_1_4_orphaned_published->ParentID = 9999;
$grandchild1_1_4_orphaned_published->write();
$grandchild1_1_4_orphaned_published->publishSingle();
$child2_1_published_orphaned = $this->objFromFixture('Page', 'child2_1_published_orphaned');
$child2_1_published_orphaned->publishSingle();
}
public function testGetOrphansByStage()
{
// all orphans
$child1_3_orphaned = $this->objFromFixture('Page', 'child1_3_orphaned');
$child1_4_orphaned_published = $this->objFromFixture('Page', 'child1_4_orphaned_published');
$grandchild1_1_3_orphaned = $this->objFromFixture('Page', 'grandchild1_1_3_orphaned');
$grandchild1_1_4_orphaned_published = $this->objFromFixture(
'Page',
'grandchild1_1_4_orphaned_published'
);
$child2_1_published_orphaned = $this->objFromFixture('Page', 'child2_1_published_orphaned');
$task = singleton(RemoveOrphanedPagesTask::class);
$orphans = $task->getOrphanedPages();
$orphanIDs = $orphans->column('ID');
sort($orphanIDs);
$compareIDs = [
$child1_3_orphaned->ID,
$child1_4_orphaned_published->ID,
$grandchild1_1_3_orphaned->ID,
$grandchild1_1_4_orphaned_published->ID,
$child2_1_published_orphaned->ID
];
sort($compareIDs);
$this->assertEquals($orphanIDs, $compareIDs);
}
}

View File

@ -1,32 +0,0 @@
Page:
parent1_published:
Title: Parent1
child1_1_published:
Title: Child1.1
Parent: =>Page.parent1_published
child1_2_published:
Title: Child1.2
Parent: =>Page.parent1_published
child1_3_orphaned:
Title: Child1.3
Parent: =>Page.parent1_published
child1_4_orphaned_published:
Title: Child1.4
Parent: =>Page.parent1_published
grandchild1_1_1:
Title: Grandchild1.1.1
Parent: =>Page.child1_1_published
grandchild1_1_2_published:
Title: Grandchild1.1.2
Parent: =>Page.child1_1_published
grandchild1_1_3_orphaned:
Title: Grandchild1.1.3
Parent: =>Page.child1_1_published
grandchild1_1_4_orphaned_published:
Title: Grandchild1.1.4
Parent: =>Page.child1_1_published
parent2:
Title: Parent2
child2_1_published_orphaned:
Title: Child2.1
Parent: =>Page.parent2

View File

@ -1,19 +1,8 @@
const Path = require('path'); const Path = require('path');
const webpackConfig = require('@silverstripe/webpack-config'); const { JavascriptWebpackConfig, CssWebpackConfig } = require('@silverstripe/webpack-config');
const CopyWebpackPlugin = require('copy-webpack-plugin'); const CopyWebpackPlugin = require('copy-webpack-plugin');
const {
resolveJS,
externalJS,
moduleJS,
pluginJS,
moduleCSS,
pluginCSS,
} = webpackConfig;
const ENV = process.env.NODE_ENV;
const PATHS = { const PATHS = {
MODULES: 'node_modules',
FILES_PATH: '../',
ROOT: Path.resolve(), ROOT: Path.resolve(),
SRC: Path.resolve('client/src'), SRC: Path.resolve('client/src'),
DIST: Path.resolve('client/dist'), DIST: Path.resolve('client/dist'),
@ -21,46 +10,37 @@ const PATHS = {
}; };
const config = [ const config = [
{ // Main JS bundles
name: 'js', new JavascriptWebpackConfig('js', PATHS, 'silverstripe/cms')
entry: { .setEntry({
bundle: `${PATHS.SRC}/bundles/bundle.js`, bundle: `${PATHS.SRC}/bundles/bundle.js`,
// See https://github.com/webpack/webpack/issues/300#issuecomment-45313650
SilverStripeNavigator: `${PATHS.LEGACY_SRC}/SilverStripeNavigator.js`, SilverStripeNavigator: `${PATHS.LEGACY_SRC}/SilverStripeNavigator.js`,
'TinyMCE_sslink-internal': `${PATHS.LEGACY_SRC}/TinyMCE_sslink-internal.js`, 'TinyMCE_sslink-internal': `${PATHS.LEGACY_SRC}/TinyMCE_sslink-internal.js`,
'TinyMCE_sslink-anchor': `${PATHS.LEGACY_SRC}/TinyMCE_sslink-anchor.js`, 'TinyMCE_sslink-anchor': `${PATHS.LEGACY_SRC}/TinyMCE_sslink-anchor.js`,
}, })
output: { .mergeConfig({
path: PATHS.DIST, plugins: [
filename: 'js/[name].js', new CopyWebpackPlugin({
}, patterns: [
devtool: (ENV !== 'production') ? 'source-map' : '',
resolve: resolveJS(ENV, PATHS),
externals: externalJS(ENV, PATHS),
module: moduleJS(ENV, PATHS),
plugins: pluginJS(ENV, PATHS).concat([
new CopyWebpackPlugin([
{ from: 'client/src/images', to: 'images' },
])
])
},
{ {
name: 'css', from: `${PATHS.SRC}/images`,
entry: { to: `${PATHS.DIST}/images`
},
]
}),
],
})
.getConfig(),
// sass to css
new CssWebpackConfig('css', PATHS)
.setEntry({
bundle: `${PATHS.SRC}/styles/bundle.scss`, bundle: `${PATHS.SRC}/styles/bundle.scss`,
SilverStripeNavigator: `${PATHS.SRC}/styles/SilverStripeNavigator.scss`, SilverStripeNavigator: `${PATHS.SRC}/styles/SilverStripeNavigator.scss`,
}, })
output: { .getConfig(),
path: PATHS.DIST,
filename: 'styles/[name].css',
},
devtool: (ENV !== 'production') ? 'source-map' : '',
module: moduleCSS(ENV, PATHS),
plugins: pluginCSS(ENV, PATHS),
},
]; ];
// Use WEBPACK_CHILD=js or WEBPACK_CHILD=css env var to run a single config // Use WEBPACK_CHILD=js or WEBPACK_CHILD=css env var to run a single config
module.exports = (process.env.WEBPACK_CHILD) module.exports = (process.env.WEBPACK_CHILD)
? config.find((entry) => entry.name === process.env.WEBPACK_CHILD) ? config.find((entry) => entry.name === process.env.WEBPACK_CHILD)
: module.exports = config; : config;

14910
yarn.lock

File diff suppressed because it is too large Load Diff