Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'master' of git://github.com/silverstripe/sapphire

Conflicts:
	.gitignore
  • Loading branch information...
commit 3bf5f6be2da553372e4cad3c52c40a33a7b04fbc 2 parents eb5961d + 450bc25
@pitchandtone pitchandtone authored
Showing with 8,071 additions and 6,965 deletions.
  1. +3 −0  .gitignore
  2. +4 −4 README.md
  3. +7 −13 _config.php
  4. +16 −0 _config/PasswordEncryptor.yml
  5. +4 −2 _register_database.php
  6. +4 −4 admin/_config.php
  7. +1 −1  admin/code/CMSBatchAction.php
  8. +16 −10 admin/code/CMSBatchActionHandler.php
  9. +11 −12 admin/code/CMSMenu.php
  10. +0 −1  admin/code/CMSMenuItem.php
  11. +1 −1  admin/code/CMSPreviewable.php
  12. +35 −0 admin/code/CMSProfileController.php
  13. +16 −14 admin/code/GroupImportForm.php
  14. +290 −218 admin/code/LeftAndMain.php
  15. +2 −2 admin/code/LeftAndMainDecorator.php
  16. +1 −1  admin/code/LeftAndMainExtension.php
  17. +19 −17 admin/code/MemberImportForm.php
  18. +0 −371 admin/code/MemberTableField.php
  19. +162 −782 admin/code/ModelAdmin.php
  20. +84 −190 admin/code/SecurityAdmin.php
  21. +65 −0 admin/css/ie7.css
  22. +37 −0 admin/css/ie8.css
  23. +420 −231 admin/css/screen.css
  24. BIN  admin/images/16x16-s8aab2a0ce2.png
  25. BIN  admin/images/24x24-s5aa96abf84.png
  26. BIN  admin/images/arrows.png
  27. BIN  admin/images/btn-icon-s41050dc384.png
  28. BIN  admin/images/btn-icon-s9416553f5b.png
  29. 0  admin/images/{btn_icons → btn-icon}/accept.png
  30. 0  admin/images/{btn_icons → btn-icon}/accept_disabled.png
  31. 0  admin/images/{btn_icons → btn-icon}/add.png
  32. 0  admin/images/{btn_icons → btn-icon}/add_disabled.png
  33. BIN  admin/images/btn-icon/addpage.png
  34. 0  admin/images/{btn_icons → btn-icon}/addpage_disabled.png
  35. 0  admin/images/{btn_icons → btn-icon}/arrow-circle-135-left.png
  36. BIN  admin/images/btn-icon/back.png
  37. BIN  admin/images/btn-icon/back_disabled.png
  38. BIN  admin/images/btn-icon/chain--arrow.png
  39. BIN  admin/images/btn-icon/chain--exclamation.png
  40. BIN  admin/images/btn-icon/chain--minus.png
  41. BIN  admin/images/btn-icon/chain--pencil.png
  42. BIN  admin/images/btn-icon/chain--plus.png
  43. BIN  admin/images/btn-icon/chain-small.png
  44. BIN  admin/images/btn-icon/chain-unchain.png
  45. BIN  admin/images/btn-icon/chain.png
  46. 0  {images/sprites_16x16 → admin/images/btn-icon}/cross-circle.png
  47. 0  {images/sprites_16x16 → admin/images/btn-icon}/cross-circle_disabled.png
  48. 0  admin/images/{btn_icons → btn-icon}/decline.png
  49. 0  admin/images/{btn_icons → btn-icon}/decline_disabled.png
  50. BIN  admin/images/btn-icon/document--pencil.png
  51. BIN  admin/images/btn-icon/download-csv.png
  52. 0  {images/sprites_16x16 → admin/images/btn-icon}/drive-upload.png
  53. 0  {images/sprites_16x16 → admin/images/btn-icon}/drive-upload_disabled.png
  54. BIN  admin/images/btn-icon/grid_print.png
  55. 0  admin/images/{btn_icons → btn-icon}/magnifier.png
  56. 0  {images/sprites_16x16 → admin/images/btn-icon}/minus-circle.png
  57. 0  {images/sprites_16x16 → admin/images/btn-icon}/minus-circle_disabled.png
  58. 0  {images/sprites_16x16 → admin/images/btn-icon}/navigation.png
  59. 0  {images/sprites_16x16 → admin/images/btn-icon}/navigation_disabled.png
  60. 0  {images/sprites_16x16 → admin/images/btn-icon}/network-cloud.png
  61. 0  {images/sprites_16x16 → admin/images/btn-icon}/network-cloud_disabled.png
  62. 0  {images/sprites_16x16 → admin/images/btn-icon}/pencil.png
  63. 0  {images/sprites_16x16 → admin/images/btn-icon}/pencil_disabled.png
  64. 0  {images/sprites_16x16 → admin/images/btn-icon}/plug-disconnect-prohibition.png
  65. 0  {images/sprites_16x16 → admin/images/btn-icon}/plug-disconnect-prohibition_disabled.png
  66. 0  admin/images/{btn_icons → btn-icon}/preview.png
  67. 0  admin/images/{btn_icons → btn-icon}/preview_disabled.png
  68. 0  admin/images/{btn_icons → btn-icon}/settings.png
  69. 0  admin/images/{btn_icons → btn-icon}/settings_disabled.png
  70. 0  admin/images/{btn_icons → btn-icon}/unpublish.png
  71. 0  admin/images/{btn_icons → btn-icon}/unpublish_disabled.png
  72. BIN  admin/images/btn_icons-saaa1989272.png
  73. BIN  admin/images/btn_icons-sb7da7f8cce.png
  74. BIN  admin/images/btn_icons/addpage.png
  75. BIN  admin/images/content-header-tabs-sprite.png
  76. BIN  admin/images/filter-icons.png
  77. 0  admin/images/{menu_icons/16x16-s2ac647f5ef.png → menu-icons/16x16-s170d9d69bb.png}
  78. 0  admin/images/{menu_icons → menu-icons}/16x16/blog.png
  79. 0  admin/images/{menu_icons → menu-icons}/16x16/community.png
  80. 0  admin/images/{menu_icons → menu-icons}/16x16/document.png
  81. 0  admin/images/{menu_icons → menu-icons}/16x16/gears.png
  82. 0  admin/images/{menu_icons → menu-icons}/16x16/home.png
  83. 0  admin/images/{menu_icons → menu-icons}/16x16/information.png
  84. 0  admin/images/{menu_icons → menu-icons}/16x16/network.png
  85. 0  admin/images/{menu_icons → menu-icons}/16x16/pencil.png
  86. 0  admin/images/{menu_icons → menu-icons}/16x16/picture.png
  87. 0  admin/images/{menu_icons → menu-icons}/16x16/pie-chart.png
  88. 0  admin/images/{menu_icons/24x24-s0cb1fe1c77.png → menu-icons/24x24-s546fcae8fd.png}
  89. 0  admin/images/{menu_icons → menu-icons}/24x24/blog.png
  90. 0  admin/images/{menu_icons → menu-icons}/24x24/community.png
  91. 0  admin/images/{menu_icons → menu-icons}/24x24/document.png
  92. 0  admin/images/{menu_icons → menu-icons}/24x24/gears.png
  93. 0  admin/images/{menu_icons → menu-icons}/24x24/home.png
  94. 0  admin/images/{menu_icons → menu-icons}/24x24/information.png
  95. 0  admin/images/{menu_icons → menu-icons}/24x24/network.png
  96. 0  admin/images/{menu_icons → menu-icons}/24x24/pencil.png
  97. 0  admin/images/{menu_icons → menu-icons}/24x24/picture.png
  98. 0  admin/images/{menu_icons → menu-icons}/24x24/pie-chart.png
  99. 0  admin/images/{menu_icons → menu-icons}/README
  100. BIN  admin/images/question.png
  101. BIN  admin/images/spinner.gif
  102. BIN  admin/images/spinner.psd
  103. BIN  admin/images/sprites-32x32-sa4e142f7f0.png
  104. BIN  admin/images/sprites-32x32/blue-document-horizontal.png
  105. BIN  admin/images/sprites-32x32/blue-document-text-image.png
  106. BIN  admin/images/sprites-32x32/blue-document-text.png
  107. BIN  admin/images/sprites-32x32/blue-document.png
  108. BIN  admin/images/sprites-32x32/blue-folder-horizontal.png
  109. BIN  admin/images/sprites-32x32/blue-folder.png
  110. 0  admin/images/{sprites_32x32 → sprites-32x32}/dialog-close-over.png
  111. 0  admin/images/{sprites_32x32 → sprites-32x32}/dialog-close.png
  112. BIN  admin/images/sprites-32x32/document-horizontal.png
  113. BIN  admin/images/sprites-32x32/document-text-image.png
  114. BIN  admin/images/sprites-32x32/document-text.png
  115. BIN  admin/images/sprites-32x32/document.png
  116. BIN  admin/images/sprites-32x32/folder-horizontal.png
  117. BIN  admin/images/sprites-32x32/folder.png
  118. BIN  admin/images/sprites-32x32/image-sunset.png
  119. BIN  admin/images/sprites-32x32/image.png
  120. 0  admin/images/{sprites_32x32 → sprites-32x32}/logout.png
  121. 0  admin/images/{sprites_32x32 → sprites-32x32}/menu-arrow-deselected-down.png
  122. 0  admin/images/{sprites_32x32 → sprites-32x32}/menu-arrow-deselected-up.png
  123. 0  admin/images/{sprites_32x32 → sprites-32x32}/menu-arrow-down.png
  124. 0  admin/images/{sprites_32x32 → sprites-32x32}/menu-arrow-up.png
  125. 0  admin/images/{sprites_32x32 → sprites-32x32}/numeric-label.png
  126. BIN  admin/images/sprites-32x32/script-text.png
  127. BIN  admin/images/sprites-32x32/script.png
  128. BIN  admin/images/sprites-32x32/table.png
  129. BIN  admin/images/textures/cms_content_header.png
  130. BIN  admin/javascript/.DS_Store
  131. +0 −161 admin/javascript/AssetTableField.js
  132. +9 −6 admin/javascript/LeftAndMain.AddForm.js
  133. +34 −39 admin/javascript/LeftAndMain.BatchActions.js
  134. +81 −108 admin/javascript/LeftAndMain.Content.js
  135. +25 −104 admin/javascript/LeftAndMain.EditForm.js
  136. +67 −30 admin/javascript/LeftAndMain.Menu.js
  137. +21 −69 admin/javascript/LeftAndMain.Panel.js
  138. +1 −0  admin/javascript/LeftAndMain.Preview.js
  139. +188 −170 admin/javascript/LeftAndMain.Tree.js
  140. +353 −85 admin/javascript/LeftAndMain.js
  141. +0 −347 admin/javascript/MemberTableField.js
  142. +0 −21 admin/javascript/MemberTableField_popup.js
  143. +0 −180 admin/javascript/ModelAdmin.History.js
  144. +3 −192 admin/javascript/ModelAdmin.js
  145. +35 −30 admin/javascript/SecurityAdmin.js
  146. +235 −0 admin/javascript/lib.js
  147. +21 −1 admin/javascript/ssui.core.js
  148. +14 −75 admin/scss/_ModelAdmin.scss
  149. +12 −6 admin/scss/_SecurityAdmin.scss
  150. +125 −174 admin/scss/_forms.scss
  151. +59 −18 admin/scss/_menu.scss
  152. +11 −0 admin/scss/_mixins.scss
  153. +9 −6 admin/scss/_sprites.scss
  154. +907 −179 admin/scss/_style.scss
  155. +110 −21 admin/scss/_tree.scss
  156. +14 −6 admin/scss/_typography.scss
  157. +4 −6 admin/scss/_uitheme.scss
  158. +246 −1 admin/scss/ie7.scss
  159. +118 −1 admin/scss/ie8.scss
  160. +8 −0 admin/scss/screen.scss
  161. +46 −45 admin/scss/themes/_default.scss
  162. +9 −0 admin/templates/CMSBreadcrumbs.ss
  163. +0 −4 admin/templates/CMSGridFieldPopupForms.ss
  164. +7 −0 admin/templates/Includes/BackLink_Button.ss
  165. +3 −3 admin/templates/Includes/CMSLoadingScreen.ss
  166. +7 −1 admin/templates/Includes/LeftAndMain_Content.ss
  167. +39 −37 admin/templates/Includes/LeftAndMain_EditForm.ss
  168. +7 −42 admin/templates/Includes/LeftAndMain_Menu.ss
  169. +1 −1  admin/templates/Includes/LeftAndMain_SilverStripeNavigator.ss
  170. +0 −62 admin/templates/Includes/MemberTableField.ss
  171. +17 −33 admin/templates/Includes/ModelAdmin_Content.ss
  172. +0 −5 admin/templates/Includes/ModelAdmin_Results.ss
  173. +14 −0 admin/templates/Includes/ModelAdmin_Tools.ss
  174. +0 −19 admin/templates/Includes/SecurityAdmin_Content.ss
  175. +6 −13 admin/templates/LeftAndMain.ss
  176. +0 −4 admin/templates/ModelSidebar.ss
  177. +1 −1  admin/tests/CMSMenuTest.php
  178. +1 −1  admin/tests/LeftAndMainTest.php
  179. +0 −139 admin/tests/MemberTableFieldTest.php
  180. +0 −31 admin/tests/MemberTableFieldTest.yml
  181. +47 −4 admin/tests/ModelAdminTest.php
  182. +31 −30 admin/tests/SecurityAdminTest.php
  183. +1 −1  admin/thirdparty/chosen/.piston.yml
  184. +19 −5 admin/thirdparty/chosen/Cakefile
  185. +12 −8 admin/thirdparty/chosen/README.md
  186. +1 −1  admin/thirdparty/chosen/VERSION
  187. BIN  admin/thirdparty/chosen/chosen/chosen-sprite.png
  188. +112 −91 admin/thirdparty/chosen/chosen/chosen.css
  189. +209 −93 admin/thirdparty/chosen/chosen/chosen.jquery.js
  190. +4 −2 admin/thirdparty/chosen/chosen/chosen.jquery.min.js
  191. +824 −0 admin/thirdparty/chosen/chosen/chosen.js
  192. +199 −87 admin/thirdparty/chosen/chosen/chosen.proto.js
  193. +4 −2 admin/thirdparty/chosen/chosen/chosen.proto.min.js
  194. +26 −9 admin/thirdparty/chosen/coffee/chosen.jquery.coffee
  195. +9 −4 admin/thirdparty/chosen/coffee/chosen.proto.coffee
  196. +2 −0  admin/thirdparty/chosen/coffee/lib/abstract-chosen.coffee
  197. +267 −213 admin/thirdparty/chosen/example.proto.html
  198. +18 −0 admin/thirdparty/chosen/package.json
  199. +4 −1 admin/thirdparty/history-js/scripts/uncompressed/history.html4.js
  200. +1 −1  admin/thirdparty/history-js/tests.src/each.php
  201. +3 −1 admin/thirdparty/jlayout/lib/jquery.jlayout.js
  202. +3 −4 api/DataFormatter.php
  203. +1 −2  api/FormEncodedDataFormatter.php
  204. +1 −2  api/JSONDataFormatter.php
  205. +2 −3 api/RSSFeed.php
  206. +5 −5 api/RestfulServer.php
  207. +5 −4 api/RestfulService.php
  208. +1 −2  api/SOAPModelAccess.php
  209. +2 −2 api/SapphireSoapServer.php
  210. +4 −4 api/VersionedRestfulServer.php
  211. +2 −2 api/XMLDataFormatter.php
  212. +2 −2 cache/Cache.php
  213. +4 −4 cli-script.php
  214. +2 −2 cli/CliController.php
  215. +10 −4 conf/ConfigureFromEnv.php
  216. +5 −5 control/ContentNegotiator.php
  217. +31 −18 control/Controller.php
  218. +7 −12 control/Cookie.php
  219. +37 −28 control/Director.php
  220. +0 −273 control/FormResponse.php
  221. +5 −3 control/HTTP.php
  222. +15 −1 control/HTTPRequest.php
  223. +2 −2 control/HTTPResponse.php
  224. +2 −2 control/NullHTTPRequest.php
  225. +69 −0 control/PjaxResponseNegotiator.php
  226. +28 −22 control/RequestHandler.php
  227. +5 −31 control/Session.php
  228. +1 −1  core/ArrayLib.php
  229. +6 −6 core/ClassInfo.php
  230. +502 −0 core/Config.php
  231. +38 −80 core/Convert.php
  232. +84 −65 core/Core.php
  233. +74 −0 core/DAG.php
  234. +11 −11 core/Diff.php
  235. +17 −3 core/Extension.php
  236. +2 −2 core/HTMLCleaner.php
  237. +140 −240 core/Object.php
  238. +3 −3 core/PaginatedList.php
  239. +29 −9 core/manifest/ClassLoader.php
  240. +23 −26 core/manifest/ClassManifest.php
  241. +497 −0 core/manifest/ConfigManifest.php
  242. +5 −3 core/manifest/ManifestFileFinder.php
  243. +2 −2 core/manifest/TemplateLoader.php
  244. +3 −3 core/manifest/TemplateManifest.php
  245. +4 −4 core/manifest/TokenisedRegularExpression.php
  246. +18 −15 css/AssetUploadField.css
  247. +0 −3  css/CodeViewer.css
  248. +2 −2 css/FileIFrameField.css
  249. +98 −40 css/GridField.css
  250. +7 −0 css/GridField_print.css
  251. +6 −6 css/HasManyFileField.css
  252. +0 −3  css/TestViewer.css
  253. +2 −2 css/TreeDropdownField.css
  254. +6 −28 css/UploadField.css
  255. +6 −4 dev/Backtrace.php
  256. +2 −3 dev/BuildTask.php
  257. +3 −4 dev/BulkLoader.php
  258. +2 −2 dev/CSSContentParser.php
  259. +1 −2  dev/CSVParser.php
  260. +1 −2  dev/Cli.php
  261. +1 −2  dev/CliDebugView.php
  262. +24 −16 dev/CliTestReporter.php
  263. +0 −351 dev/CodeViewer.php
  264. +1 −4 dev/CsvBulkLoader.php
  265. +5 −2 dev/Debug.php
  266. +17 −6 dev/DebugView.php
  267. +3 −3 dev/Deprecation.php
  268. +13 −22 dev/DevelopmentAdmin.php
  269. +2 −2 dev/FunctionalTest.php
  270. +1 −2  dev/InstallerTest.php
  271. +2 −2 dev/JSTestRunner.php
  272. +2 −2 dev/Log.php
  273. +2 −2 dev/LogEmailWriter.php
  274. +2 −2 dev/LogErrorEmailFormatter.php
  275. +2 −2 dev/LogErrorFileFormatter.php
  276. +2 −2 dev/LogFileWriter.php
  277. +1 −2  dev/MigrationTask.php
  278. +0 −214 dev/ModelViewer.php
  279. +1 −2  dev/Profiler.php
  280. +4 −14 dev/SapphireInfo.php
  281. +3 −4 dev/SapphireREPL.php
  282. +37 −8 dev/SapphireTest.php
  283. +13 −6 dev/SapphireTestReporter.php
  284. +1 −2  dev/SapphireTestSuite.php
  285. +2 −2 dev/SysLogWriter.php
  286. +4 −4 dev/TaskRunner.php
  287. +2 −2 dev/TestListener.php
  288. +2 −2 dev/TestMailer.php
  289. +1 −2  dev/TestOnly.php
  290. +22 −26 dev/TestRunner.php
  291. +3 −3 dev/TestSession.php
  292. +0 −257 dev/TestViewer.php
  293. +1 −1  dev/YamlFixture.php
  294. +2 −2 dev/ZendLog.php
  295. +1 −1  dev/install/DatabaseAdapterRegistry.php
  296. +2 −2 dev/install/DatabaseConfigurationHelper.php
  297. +14 −14 dev/install/MySQLDatabaseConfigurationHelper.php
  298. +56 −56 dev/install/config-form.html
  299. +15 −0 dev/install/config.rb
  300. +101 −0 dev/install/css/install.css
Sorry, we could not display the entire diff because too many files (2,377) changed.
View
3  .gitignore
@@ -3,3 +3,6 @@
/.buildpath
/.project
/.settings
+css/GridField_print.css
+admin/thirdparty/chosen/node_modules
+
View
8 README.md
@@ -5,13 +5,13 @@ Requires a [`silverstripe-installer`](http://github.com/silverstripe/silverstrip
## Installation ##
-See [installation on different platforms](http://doc.silverstripe.org/sapphire/en/installation/),
-and [installation from source](http://doc.silverstripe.org/sapphire/en/installation/from-source).
+See [installation on different platforms](http://doc.silverstripe.org/framework/en/installation/),
+and [installation from source](http://doc.silverstripe.org/framework/en/installation/from-source).
## Links ##
- * [Requirements](http://doc.silverstripe.org/sapphire/en/installation/server-requirements)
- * [Changelogs](http://doc.silverstripe.org/sapphire/en/changelogs/)
+ * [Requirements](http://doc.silverstripe.org/framework/en/installation/server-requirements)
+ * [Changelogs](http://doc.silverstripe.org/framework/en/changelogs/)
* [Bugtracker](http://open.silverstripe.org)
* [Forums](http://silverstripe.org/forums)
* [Developer Mailinglist](https://groups.google.com/forum/#!forum/silverstripe-dev)
View
20 _config.php
@@ -1,9 +1,9 @@
<?php
/**
- * Sapphire configuration file
+ * Framework configuration file
*
- * Here you can make different settings for the Sapphire module (the core
+ * Here you can make different settings for the Framework module (the core
* module).
*
* For example you can register the authentication methods you wish to use
@@ -13,7 +13,7 @@
* Authenticator::register_authenticator('OpenIDAuthenticator');
* </code>
*
- * @package sapphire
+ * @package framework
* @subpackage core
*/
@@ -42,12 +42,12 @@
Object::useCustomClass('SSDatetime', 'SS_Datetime', true);
Object::useCustomClass('Datetime', 'SS_Datetime', true);
-
-
/**
* The root directory of TinyMCE
*/
-define('MCE_ROOT', 'sapphire/thirdparty/tinymce/');
+define('MCE_ROOT', FRAMEWORK_DIR . '/thirdparty/tinymce/');
+
+ShortcodeParser::get('default')->register('file_link', array('File', 'link_shortcode_handler'));
/**
* The secret key that needs to be sent along with pings to /Email_BounceHandler
@@ -61,12 +61,6 @@
define('EMAIL_BOUNCEHANDLER_KEY', '1aaaf8fb60ea253dbf6efa71baaacbb3');
}
-PasswordEncryptor::register('none', 'PasswordEncryptor_None');
-PasswordEncryptor::register('md5', 'PasswordEncryptor_LegacyPHPHash("md5")');
-PasswordEncryptor::register('sha1','PasswordEncryptor_LegacyPHPHash("sha1")');
-PasswordEncryptor::register('md5_v2.4', 'PasswordEncryptor_PHPHash("md5")');
-PasswordEncryptor::register('sha1_v2.4','PasswordEncryptor_PHPHash("sha1")');
-
// Zend_Cache temp directory setting
$_ENV['TMPDIR'] = TEMP_FOLDER; // for *nix
$_ENV['TMP'] = TEMP_FOLDER; // for Windows
@@ -81,4 +75,4 @@
Deprecation::notification_version('3.0.0');
// TODO Remove once new ManifestBuilder with submodule support is in place
-require_once('admin/_config.php');
+require_once('admin/_config.php');
View
16 _config/PasswordEncryptor.yml
@@ -0,0 +1,16 @@
+name: PasswordEncryptor
+---
+PasswordEncryptor:
+ encryptors:
+ none:
+ PasswordEncryptor_None:
+ md5:
+ PasswordEncryptor_LegacyPHPHash: md5
+ sha1:
+ PasswordEncryptor_LegacyPHPHash: sha1
+ md5_v2.4:
+ PasswordEncryptor_PHPHash: md5
+ sha1_v2.4:
+ PasswordEncryptor_PHPHash: sha1
+ blowfish:
+ PasswordEncryptor_Blowfish:
View
6 _register_database.php
@@ -1,12 +1,14 @@
<?php
// Register the SilverStripe provided databases
+$frameworkPath = defined('FRAMEWORK_PATH') ? FRAMEWORK_PATH : FRAMEWORK_NAME;
+
DatabaseAdapterRegistry::register(
array(
'class' => 'MySQLDatabase',
'title' => 'MySQL 5.0+',
- 'helperPath' => 'sapphire/dev/install/MySQLDatabaseConfigurationHelper.php',
- 'supported' => function_exists('mysql_connect'),
+ 'helperPath' => $frameworkPath . '/dev/install/MySQLDatabaseConfigurationHelper.php',
+ 'supported' => class_exists('MySQLi'),
)
);
View
8 admin/_config.php
@@ -18,17 +18,16 @@
'body_class' => 'typography',
'document_base_url' => Director::absoluteBaseURL(),
- 'urlconverter_callback' => "nullConverter",
- 'setupcontent_callback' => "sapphiremce_setupcontent",
'cleanup_callback' => "sapphiremce_cleanup",
'use_native_selects' => true, // fancy selects are bug as of SS 2.3.0
'valid_elements' => "@[id|class|style|title],#a[id|rel|rev|dir|tabindex|accesskey|type|name|href|target|title|class],-strong/-b[class],-em/-i[class],-strike[class],-u[class],#p[id|dir|class|align|style],-ol[class],-ul[class],-li[class],br,img[id|dir|longdesc|usemap|class|src|border|alt=|title|width|height|align],-sub[class],-sup[class],-blockquote[dir|class],-table[border=0|cellspacing|cellpadding|width|height|class|align|summary|dir|id|style],-tr[id|dir|class|rowspan|width|height|align|valign|bgcolor|background|bordercolor|style],tbody[id|class|style],thead[id|class|style],tfoot[id|class|style],#td[id|dir|class|colspan|rowspan|width|height|align|valign|scope|style],-th[id|dir|class|colspan|rowspan|width|height|align|valign|scope|style],caption[id|dir|class],-div[id|dir|class|align|style],-span[class|align|style],-pre[class|align],address[class|align],-h1[id|dir|class|align|style],-h2[id|dir|class|align|style],-h3[id|dir|class|align|style],-h4[id|dir|class|align|style],-h5[id|dir|class|align|style],-h6[id|dir|class|align|style],hr[class],dd[id|class|title|dir],dl[id|class|title|dir],dt[id|class|title|dir],@[id,style,class]",
- 'extended_valid_elements' => "img[class|src|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name|usemap],iframe[src|name|width|height|align|frameborder|marginwidth|marginheight|scrolling],object[width|height|data|type],param[name|value],map[class|name|id],area[shape|coords|href|target|alt]"
+ 'extended_valid_elements' => "img[class|src|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name|usemap],iframe[src|name|width|height|align|frameborder|marginwidth|marginheight|scrolling],object[width|height|data|type],param[name|value],map[class|name|id],area[shape|coords|href|target|alt]",
+ 'spellchecker_rpc_url' => THIRDPARTY_DIR . '/tinymce-spellchecker/rpc.php'
));
HtmlEditorConfig::get('cms')->enablePlugins('media', 'fullscreen');
-HtmlEditorConfig::get('cms')->enablePlugins(array('ssbuttons' => '../../../cms/javascript/tinymce_ssbuttons/editor_plugin_src.js'));
+HtmlEditorConfig::get('cms')->enablePlugins(array('ssbuttons' => sprintf('../../../%s/tinymce_ssbuttons/editor_plugin_src.js', THIRDPARTY_DIR)));
HtmlEditorConfig::get('cms')->insertButtonsBefore('formatselect', 'styleselect');
HtmlEditorConfig::get('cms')->addButtonsToLine(2, 'ssimage', 'ssflash', 'sslink', 'unlink', 'anchor', 'separator','code', 'fullscreen', 'separator');
@@ -36,3 +35,4 @@
HtmlEditorConfig::get('cms')->removeButtons('tablecontrols');
HtmlEditorConfig::get('cms')->addButtonsToLine(3, 'tablecontrols');
+CMSMenu::remove_menu_item('CMSProfileController');
View
2  admin/code/CMSBatchAction.php
@@ -146,4 +146,4 @@ function getParameterFields() {
function canView() {
return true;
}
-}
+}
View
26 admin/code/CMSBatchActionHandler.php
@@ -68,7 +68,7 @@ function Link() {
function handleAction($request) {
// This method can't be called without ajax.
- if(!$this->parentController->isAjax()) {
+ if(!$request->isAjax()) {
$this->parentController->redirectBack();
return;
}
@@ -81,7 +81,7 @@ function handleAction($request) {
$actionHandler = new $actionClass();
// Sanitise ID list and query the database for apges
- $ids = split(' *, *', trim($request->requestVar('csvIDs')));
+ $ids = preg_split('/ *, */', trim($request->requestVar('csvIDs')));
foreach($ids as $k => $v) if(!is_numeric($v)) unset($ids[$k]);
if($ids) {
@@ -111,8 +111,14 @@ function handleAction($request) {
implode(", ", $idsFromLive)
);
$livePages = Versioned::get_by_stage($this->recordClass, 'Live', $sql);
- if($pages) $pages->merge($livePages);
- else $pages = $livePages;
+ if($pages) {
+ // Can't merge into a DataList, need to condense into an actual list first
+ // (which will retrieve all records as objects, so its an expensive operation)
+ $pages = new ArrayList($pages->toArray());
+ $pages->merge($livePages);
+ } else {
+ $pages = $livePages;
+ }
}
}
} else {
@@ -124,12 +130,12 @@ function handleAction($request) {
function handleApplicablePages($request) {
// Find the action handler
- $actions = Object::get_static($this->class, 'batch_actions');
+ $actions = Config::inst()->get($this->class, 'batch_actions', Config::FIRST_SET);
$actionClass = $actions[$request->param('BatchAction')];
$actionHandler = new $actionClass['class']();
// Sanitise ID list and query the database for apges
- $ids = split(' *, *', trim($request->requestVar('csvIDs')));
+ $ids = preg_split('/ *, */', trim($request->requestVar('csvIDs')));
foreach($ids as $k => $id) $ids[$k] = (int)$id;
$ids = array_filter($ids);
@@ -146,12 +152,12 @@ function handleApplicablePages($request) {
function handleConfirmation($request) {
// Find the action handler
- $actions = Object::get_static($this->class, 'batch_actions');
+ $actions = Config::inst()->get($this->class, 'batch_actions', Config::FIRST_SET);
$actionClass = $actions[$request->param('BatchAction')];
$actionHandler = new $actionClass();
// Sanitise ID list and query the database for apges
- $ids = split(' *, *', trim($request->requestVar('csvIDs')));
+ $ids = preg_split('/ *, */', trim($request->requestVar('csvIDs')));
foreach($ids as $k => $id) $ids[$k] = (int)$id;
$ids = array_filter($ids);
@@ -197,7 +203,7 @@ function batchActionList() {
* @return array See {@link register()} for the returned format.
*/
function batchActions() {
- $actions = Object::get_static($this->class, 'batch_actions');
+ $actions = Config::inst()->get($this->class, 'batch_actions', Config::FIRST_SET);
if($actions) foreach($actions as $action) {
if($action['recordClass'] != $this->recordClass) unset($action);
}
@@ -205,4 +211,4 @@ function batchActions() {
return $actions;
}
-}
+}
View
23 admin/code/CMSMenu.php
@@ -59,9 +59,9 @@ public static function add_controller($controllerClass) {
* Return a CMSMenuItem to add the given controller to the CMSMenu
*/
protected static function menuitem_for_controller($controllerClass) {
- $urlBase = Object::get_static($controllerClass, 'url_base');
- $urlSegment = Object::get_static($controllerClass, 'url_segment');
- $menuPriority = Object::get_static($controllerClass, 'menu_priority');
+ $urlBase = Config::inst()->get($controllerClass, 'url_base', Config::FIRST_SET);
+ $urlSegment = Config::inst()->get($controllerClass, 'url_segment', Config::FIRST_SET);
+ $menuPriority = Config::inst()->get($controllerClass, 'menu_priority', Config::FIRST_SET);
// Don't add menu items defined the old way
if($urlSegment === null && $controllerClass != "CMSMain") return;
@@ -81,12 +81,12 @@ protected static function menuitem_for_controller($controllerClass) {
* Add the appropriate Director rules for the given controller.
*/
protected static function add_director_rule_for_controller($controllerClass) {
- $urlBase = Object::get_static($controllerClass, 'url_base');
- $urlSegment = Object::get_static($controllerClass, 'url_segment');
- $urlRule = Object::get_static($controllerClass, 'url_rule');
- $urlPriority = Object::get_static($controllerClass, 'url_priority');
-
- if($urlSegment || $controllerClass == "CMSMain") {
+ $urlBase = Config::inst()->get($controllerClass, 'url_base', Config::FIRST_SET);
+ $urlSegment = Config::inst()->get($controllerClass, 'url_segment', Config::FIRST_SET);
+ $urlRule = Config::inst()->get($controllerClass, 'url_rule', Config::FIRST_SET);
+ $urlPriority = Config::inst()->get($controllerClass, 'url_priority', Config::FIRST_SET);
+
+ if($urlSegment || $controllerClass == 'CMSMain') {
$link = Controller::join_links($urlBase, $urlSegment) . '/';
// Make director rule
@@ -101,7 +101,7 @@ protected static function add_director_rule_for_controller($controllerClass) {
/**
* Add an arbitrary URL to the CMS menu.
*
- * @param string $code A unique identifier (used to create a CSS ID and as it's key in {@link $menu_items}
+ * @param string $code A unique identifier (used to create a CSS ID and its key in {@link $menu_items})
* @param string $menuTitle The link's title in the CMS menu
* @param string $url The url of the link
* @param integer $priority The menu priority (sorting order) of the menu item. Higher priorities will be further left.
@@ -318,9 +318,8 @@ function provideI18nEntities() {
foreach($cmsClasses as $cmsClass) {
$defaultTitle = LeftAndMain::menu_title_for_class($cmsClass);
$ownerModule = i18n::get_owner_module($cmsClass);
- $entities["{$cmsClass}.MENUTITLE"] = array($defaultTitle, PR_HIGH, 'Menu title', $ownerModule);
+ $entities["{$cmsClass}.MENUTITLE"] = array($defaultTitle, 'Menu title', $ownerModule);
}
return $entities;
}
}
-?>
View
1  admin/code/CMSMenuItem.php
@@ -47,4 +47,3 @@ public function __construct($title, $url, $controller = null, $priority = -1) {
}
}
-?>
View
2  admin/code/CMSPreviewable.php
@@ -22,4 +22,4 @@ function Link();
*/
function CMSEditLink();
-}
+}
View
35 admin/code/CMSProfileController.php
@@ -0,0 +1,35 @@
+<?php
+class CMSProfileController extends LeftAndMain {
+
+ static $url_segment = 'myprofile';
+ static $required_permission_codes = false;
+
+ public function index($request) {
+ $form = $this->Member_ProfileForm();
+ return $this->customise(array(
+ 'Content' => ' ',
+ 'Form' => $form
+ ))->renderWith('CMSDialog');
+ }
+
+ public function Member_ProfileForm() {
+ return new Member_ProfileForm($this, 'Member_ProfileForm', Member::currentUser());
+ }
+
+ function canView($member = null) {
+ if(!$member && $member !== FALSE) $member = Member::currentUser();
+
+ // cms menus only for logged-in members
+ if(!$member) return false;
+
+ // Only check for generic CMS permissions
+ if(
+ !Permission::checkMember($member, "CMS_ACCESS_LeftAndMain")
+ && !Permission::checkMember($member, "CMS_ACCESS_CMSMain")
+ ) {
+ return false;
+ }
+
+ return true;
+ }
+}
View
30 admin/code/GroupImportForm.php
@@ -49,13 +49,16 @@ function __construct($controller, $name, $fields = null, $actions = null, $valid
}
if(!$actions) $actions = new FieldList(
- new FormAction('doImport', _t('SecurityAdmin_MemberImportForm.BtnImport', 'Import'))
+ $importAction = new FormAction('doImport', _t('SecurityAdmin_MemberImportForm.BtnImport', 'Import from CSV'))
);
-
+
+ $importAction->addExtraClass('ss-ui-button');
+
if(!$validator) $validator = new RequiredFields('CsvFile');
parent::__construct($controller, $name, $fields, $actions, $validator);
-
+
+ $this->addExtraClass('cms');
$this->addExtraClass('import-form');
}
@@ -67,24 +70,23 @@ function doImport($data, $form) {
// result message
$msgArr = array();
- if($result->CreatedCount()) $msgArr[] = sprintf(
- _t('GroupImportForm.ResultCreated', 'Created %d groups'),
- $result->CreatedCount()
+ if($result->CreatedCount()) $msgArr[] = _t(
+ 'GroupImportForm.ResultCreated', 'Created {count} groups',
+ array('count' => $result->CreatedCount())
);
- if($result->UpdatedCount()) $msgArr[] = sprintf(
- _t('GroupImportForm.ResultUpdated', 'Updated %d groups'),
- $result->UpdatedCount()
+ if($result->UpdatedCount()) $msgArr[] = _t(
+ 'GroupImportForm.ResultUpdated', 'Updated %d groups',
+ array('count' => $result->UpdatedCount())
);
- if($result->DeletedCount()) $msgArr[] = sprintf(
- _t('GroupImportForm.ResultDeleted', 'Deleted %d groups'),
- $result->DeletedCount()
+ if($result->DeletedCount()) $msgArr[] = _t(
+ 'GroupImportForm.ResultDeleted', 'Deleted %d groups',
+ array('count' => $result->DeletedCount())
);
$msg = ($msgArr) ? implode(',', $msgArr) : _t('MemberImportForm.ResultNone', 'No changes');
$this->sessionMessage($msg, 'good');
- $this->redirectBack();
+ $this->controller->redirectBack();
}
}
-?>
View
508 admin/code/LeftAndMain.php
@@ -9,7 +9,7 @@
* @package cms
* @subpackage core
*/
-class LeftAndMain extends Controller {
+class LeftAndMain extends Controller implements PermissionProvider {
/**
* The 'base' url for CMS administration areas.
@@ -73,18 +73,24 @@ class LeftAndMain extends Controller {
'savetreenode',
'getitem',
'getsubtree',
- 'myprofile',
'printable',
'show',
- 'Member_ProfileForm',
'EditorToolbar',
'EditForm',
- 'RootForm',
'AddForm',
'batchactions',
'BatchActionsForm',
'Member_ProfileForm',
);
+
+ /**
+ * @var Array Codes which are required from the current user to view this controller.
+ * If multiple codes are provided, all of them are required.
+ * All CMS controllers require "CMS_ACCESS_LeftAndMain" as a baseline check,
+ * and fall back to "CMS_ACCESS_<class>" if no permissions are defined here.
+ * See {@link canView()} for more details on permission checks.
+ */
+ static $required_permission_codes;
/**
* Register additional requirements through the {@link Requirements} class.
@@ -98,16 +104,18 @@ class LeftAndMain extends Controller {
'css' => array(),
'themedcss' => array(),
);
+
+ /**
+ * @var PJAXResponseNegotiator
+ */
+ protected $responseNegotiator;
/**
* @param Member $member
- *
* @return boolean
*/
function canView($member = null) {
- if(!$member && $member !== FALSE) {
- $member = Member::currentUser();
- }
+ if(!$member && $member !== FALSE) $member = Member::currentUser();
// cms menus only for logged-in members
if(!$member) return false;
@@ -117,12 +125,18 @@ function canView($member = null) {
$alternateAllowed = $this->alternateAccessCheck();
if($alternateAllowed === FALSE) return false;
}
-
- // Default security check for LeftAndMain sub-class permissions
- if(!Permission::checkMember($member, "CMS_ACCESS_$this->class") &&
- !Permission::checkMember($member, "CMS_ACCESS_LeftAndMain")) {
- return false;
+
+ // Check for "CMS admin" permission
+ if(Permission::checkMember($member, "CMS_ACCESS_LeftAndMain")) return true;
+
+ // Check for LeftAndMain sub-class permissions
+ $codes = array();
+ $extraCodes = $this->stat('required_permission_codes');
+ if($extraCodes !== false) { // allow explicit FALSE to disable subclass check
+ if($extraCodes) $codes = array_merge($codes, (array)$extraCodes);
+ else $codes[] = "CMS_ACCESS_$this->class";
}
+ foreach($codes as $code) if(!Permission::checkMember($member, $code)) return false;
return true;
}
@@ -146,7 +160,7 @@ function init() {
// can't be done in cms/_config.php as locale is not set yet
CMSMenu::add_link(
'Help',
- _t('LeftAndMain.HELP', 'Help', PR_HIGH, 'Menu title'),
+ _t('LeftAndMain.HELP', 'Help', 'Menu title'),
self::$help_link
);
@@ -184,13 +198,8 @@ function init() {
if(Director::redirected_to()) return;
// Audit logging hook
- if(empty($_REQUEST['executeForm']) && !$this->isAjax()) $this->extend('accessedCMS');
+ if(empty($_REQUEST['executeForm']) && !$this->request->isAjax()) $this->extend('accessedCMS');
- // Requirements
-
- // Suppress behaviour/prototype validation instructions in CMS, not compatible with ajax loading of forms.
- Validator::set_javascript_validation_handler('none');
-
// Set the members html editor config
HtmlEditorConfig::set_active(Member::currentUser()->getHtmlEditorConfigForCMS());
@@ -200,7 +209,7 @@ function init() {
$htmlEditorConfig->setOption('language', i18n::get_tinymce_lang());
if(!$htmlEditorConfig->getOption('content_css')) {
$cssFiles = array();
- $cssFiles[] = 'sapphire/admin/css/editor.css';
+ $cssFiles[] = FRAMEWORK_ADMIN_DIR . '/css/editor.css';
// Use theme from the site config
if(class_exists('SiteConfig') && ($config = SiteConfig::current_site_config()) && $config->Theme) {
@@ -230,40 +239,33 @@ function init() {
Requirements::combine_files(
'lib.js',
array(
- THIRDPARTY_DIR . '/prototype/prototype.js',
- THIRDPARTY_DIR . '/behaviour/behaviour.js',
- SAPPHIRE_DIR . '/javascript/prototype_improvements.js',
THIRDPARTY_DIR . '/jquery/jquery.js',
- SAPPHIRE_DIR . '/javascript/jquery_improvements.js',
- THIRDPARTY_DIR . '/jquery-livequery/jquery.livequery.js',
- SAPPHIRE_DIR . '/javascript/jquery-ondemand/jquery.ondemand.js',
+ FRAMEWORK_DIR . '/javascript/jquery-ondemand/jquery.ondemand.js',
+ FRAMEWORK_ADMIN_DIR . '/javascript/lib.js',
THIRDPARTY_DIR . '/jquery-ui/jquery-ui.js',
THIRDPARTY_DIR . '/json-js/json2.js',
THIRDPARTY_DIR . '/jquery-entwine/dist/jquery.entwine-dist.js',
THIRDPARTY_DIR . '/jquery-cookie/jquery.cookie.js',
THIRDPARTY_DIR . '/jquery-query/jquery.query.js',
- SAPPHIRE_ADMIN_DIR . '/thirdparty/jquery-notice/jquery.notice.js',
- THIRDPARTY_DIR . '/jquery-metadata/jquery.metadata.js',
- SAPPHIRE_ADMIN_DIR . '/thirdparty/jsizes/lib/jquery.sizes.js',
- SAPPHIRE_ADMIN_DIR . '/thirdparty/jlayout/lib/jlayout.border.js',
- SAPPHIRE_ADMIN_DIR . '/thirdparty/jlayout/lib/jquery.jlayout.js',
- SAPPHIRE_ADMIN_DIR . '/thirdparty/history-js/scripts/uncompressed/history.js',
- SAPPHIRE_ADMIN_DIR . '/thirdparty/history-js/scripts/uncompressed/history.adapter.jquery.js',
- // SAPPHIRE_ADMIN_DIR . '/thirdparty/history-js/scripts/uncompressed/history.html4.js',
+ THIRDPARTY_DIR . '/jquery-form/jquery.form.js',
+ FRAMEWORK_ADMIN_DIR . '/thirdparty/jquery-notice/jquery.notice.js',
+ FRAMEWORK_ADMIN_DIR . '/thirdparty/jsizes/lib/jquery.sizes.js',
+ FRAMEWORK_ADMIN_DIR . '/thirdparty/jlayout/lib/jlayout.border.js',
+ FRAMEWORK_ADMIN_DIR . '/thirdparty/jlayout/lib/jquery.jlayout.js',
+ FRAMEWORK_ADMIN_DIR . '/thirdparty/history-js/scripts/uncompressed/history.js',
+ FRAMEWORK_ADMIN_DIR . '/thirdparty/history-js/scripts/uncompressed/history.adapter.jquery.js',
+ FRAMEWORK_ADMIN_DIR . '/thirdparty/history-js/scripts/uncompressed/history.html4.js',
THIRDPARTY_DIR . '/jstree/jquery.jstree.js',
- SAPPHIRE_ADMIN_DIR . '/thirdparty/chosen/chosen/chosen.jquery.js',
- SAPPHIRE_ADMIN_DIR . '/thirdparty/jquery-hoverIntent/jquery.hoverIntent.js',
- SAPPHIRE_ADMIN_DIR . '/javascript/jquery-changetracker/lib/jquery.changetracker.js',
- SAPPHIRE_DIR . '/javascript/TreeDropdownField.js',
- SAPPHIRE_DIR ."/thirdparty/jquery-form/jquery.form.js",
- SAPPHIRE_DIR . '/javascript/DateField.js',
- SAPPHIRE_DIR . '/javascript/HtmlEditorField.js',
- SAPPHIRE_DIR . '/javascript/TabSet.js',
- SAPPHIRE_DIR . '/javascript/Validator.js',
- SAPPHIRE_DIR . '/javascript/i18n.js',
- SAPPHIRE_ADMIN_DIR . '/javascript/ssui.core.js',
- SAPPHIRE_DIR . '/javascript/tiny_mce_improvements.js',
- CMS_DIR . '/javascript/ThumbnailStripField.js',
+ FRAMEWORK_ADMIN_DIR . '/thirdparty/chosen/chosen/chosen.jquery.js',
+ FRAMEWORK_ADMIN_DIR . '/thirdparty/jquery-hoverIntent/jquery.hoverIntent.js',
+ FRAMEWORK_ADMIN_DIR . '/javascript/jquery-changetracker/lib/jquery.changetracker.js',
+ FRAMEWORK_DIR . '/javascript/TreeDropdownField.js',
+ FRAMEWORK_DIR . '/javascript/DateField.js',
+ FRAMEWORK_DIR . '/javascript/HtmlEditorField.js',
+ FRAMEWORK_DIR . '/javascript/TabSet.js',
+ FRAMEWORK_DIR . '/javascript/i18n.js',
+ FRAMEWORK_ADMIN_DIR . '/javascript/ssui.core.js',
+ FRAMEWORK_DIR . '/javascript/GridField.js',
)
);
@@ -273,34 +275,36 @@ function init() {
'leftandmain.js',
array_unique(array_merge(
array(
- SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.js',
- SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.Panel.js',
- SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.Tree.js',
- SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.Ping.js',
- SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.Content.js',
- SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.EditForm.js',
- SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.Menu.js',
- SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.AddForm.js',
- SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.Preview.js',
- SAPPHIRE_ADMIN_DIR . '/javascript/LeftAndMain.BatchActions.js',
+ FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.js',
+ FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.Panel.js',
+ FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.Tree.js',
+ FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.Ping.js',
+ FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.Content.js',
+ FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.EditForm.js',
+ FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.Menu.js',
+ FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.AddForm.js',
+ FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.Preview.js',
+ FRAMEWORK_ADMIN_DIR . '/javascript/LeftAndMain.BatchActions.js',
),
- Requirements::add_i18n_javascript(SAPPHIRE_DIR . '/javascript/lang', true, true),
- Requirements::add_i18n_javascript(SAPPHIRE_ADMIN_DIR . '/javascript/lang', true, true)
+ Requirements::add_i18n_javascript(FRAMEWORK_DIR . '/javascript/lang', true, true),
+ Requirements::add_i18n_javascript(FRAMEWORK_ADMIN_DIR . '/javascript/lang', true, true)
))
);
+ Requirements::css(FRAMEWORK_ADMIN_DIR . '/thirdparty/jquery-notice/jquery.notice.css');
Requirements::css(THIRDPARTY_DIR . '/jquery-ui-themes/smoothness/jquery-ui.css');
- Requirements::css(SAPPHIRE_ADMIN_DIR .'/thirdparty/chosen/chosen/chosen.css');
+ Requirements::css(FRAMEWORK_ADMIN_DIR .'/thirdparty/chosen/chosen/chosen.css');
Requirements::css(THIRDPARTY_DIR . '/jstree/themes/apple/style.css');
- Requirements::css(SAPPHIRE_DIR . '/css/TreeDropdownField.css');
- Requirements::css(SAPPHIRE_ADMIN_DIR . '/css/screen.css');
+ Requirements::css(FRAMEWORK_DIR . '/css/TreeDropdownField.css');
+ Requirements::css(FRAMEWORK_ADMIN_DIR . '/css/screen.css');
+ Requirements::css(FRAMEWORK_DIR . '/css/GridField.css');
// Browser-specific requirements
$ie = isset($_SERVER['HTTP_USER_AGENT']) ? strpos($_SERVER['HTTP_USER_AGENT'], 'MSIE') : false;
if($ie) {
$version = substr($_SERVER['HTTP_USER_AGENT'], $ie + 5, 3);
- if($version == 7) Requirements::css('sapphire/admin/css/ie7.css');
- else if($version == 8) Requirements::css('sapphire/admin/css/ie8.css');
+ if($version == 7) Requirements::css(FRAMEWORK_ADMIN_DIR . '/css/ie7.css');
+ else if($version == 8) Requirements::css(FRAMEWORK_ADMIN_DIR . '/css/ie8.css');
}
// Custom requirements
@@ -322,7 +326,7 @@ function init() {
SSViewer::set_theme(null);
}
- function handleRequest($request, DataModel $model) {
+ function handleRequest(SS_HTTPRequest $request, DataModel $model = null) {
$title = $this->Title();
$response = parent::handleRequest($request, $model);
@@ -332,8 +336,25 @@ function handleRequest($request, DataModel $model) {
return $response;
}
+ /**
+ * Overloaded redirection logic to trigger a fake redirect on ajax requests.
+ * While this violates HTTP principles, its the only way to work around the
+ * fact that browsers handle HTTP redirects opaquely, no intervention via JS is possible.
+ * In isolation, that's not a problem - but combined with history.pushState()
+ * it means we would request the same redirection URL twice if we want to update the URL as well.
+ * See LeftAndMain.js for the required jQuery ajaxComplete handlers.
+ */
+ function redirect($url, $code=302) {
+ if($this->request->isAjax()) {
+ $this->response->addHeader('X-ControllerURL', $url);
+ return ''; // Actual response will be re-requested by client
+ } else {
+ parent::redirect($url, $code);
+ }
+ }
+
function index($request) {
- return ($this->isAjax()) ? $this->show($request) : $this->getViewer('index')->process($this);
+ return $this->getResponseNegotiator()->respond($request);
}
@@ -368,14 +389,14 @@ public function Link($action = null) {
"$action"
);
}
-
+
/**
* Returns the menu title for the given LeftAndMain subclass.
* Implemented static so that we can get this value without instantiating an object.
* Menu title is *not* internationalised.
*/
static function menu_title_for_class($class) {
- $title = eval("return $class::\$menu_title;");
+ $title = Config::inst()->get($class, 'menu_title', Config::FIRST_SET);
if(!$title) $title = preg_replace('/Admin$/', '', $class);
return $title;
}
@@ -383,20 +404,30 @@ static function menu_title_for_class($class) {
public function show($request) {
// TODO Necessary for TableListField URLs to work properly
if($request->param('ID')) $this->setCurrentPageID($request->param('ID'));
-
- if($this->isAjax()) {
- if($request->getVar('cms-view-form')) {
- $form = $this->getEditForm();
- $content = $form->forTemplate();
- } else {
- // Rendering is handled by template, which will call EditForm() eventually
- $content = $this->renderWith($this->getTemplatesWithSuffix('_Content'));
- }
- } else {
- $content = $this->renderWith($this->getViewer('show'));
+ return $this->getResponseNegotiator()->respond($request);
+ }
+
+ /**
+ * Caution: Volatile API.
+ *
+ * @return PJAXResponseNegotiator
+ */
+ protected function getResponseNegotiator() {
+ if(!$this->responseNegotiator) {
+ $controller = $this;
+ $this->responseNegotiator = new PJAXResponseNegotiator(array(
+ 'CurrentForm' => function() use(&$controller) {
+ return $controller->getEditForm()->forTemplate();
+ },
+ 'Content' => function() use(&$controller) {
+ return $controller->renderWith($controller->getTemplatesWithSuffix('_Content'));
+ },
+ 'default' => function() use(&$controller) {
+ return $controller->renderWith($controller->getViewer('show'));
+ }
+ ));
}
-
- return $content;
+ return $this->responseNegotiator;
}
//------------------------------------------------------------------------------------------//
@@ -459,7 +490,7 @@ public function MainMenu() {
$menu->push(new ArrayData(array(
"MenuItem" => $menuItem,
"Title" => Convert::raw2xml($title),
- "Code" => DBField::create('Text', $code),
+ "Code" => DBField::create_field('Text', $code),
"Link" => $menuItem->url,
"LinkingMode" => $linkingmode
)));
@@ -478,10 +509,12 @@ public function Menu() {
/**
* Return a list of appropriate templates for this class, with the given suffix
*/
- protected function getTemplatesWithSuffix($suffix) {
+ public function getTemplatesWithSuffix($suffix) {
+ $templates = array();
$classes = array_reverse(ClassInfo::ancestry($this->class));
foreach($classes as $class) {
- $templates[] = $class . $suffix;
+ $template = $class . $suffix;
+ if(SSViewer::hasTemplate($template)) $templates[] = $template;
if($class == 'LeftAndMain') break;
}
return $templates;
@@ -503,6 +536,40 @@ public function getRecord($id) {
return false;
}
}
+
+ /**
+ * @return ArrayList
+ */
+ public function Breadcrumbs($unlinked = false) {
+ $title = self::menu_title_for_class($this->class);
+ $items = new ArrayList(array(
+ new ArrayData(array(
+ 'Title' => $title,
+ 'Link' => ($unlinked) ? false : $this->Link()
+ ))
+ ));
+ $record = $this->currentPage();
+ if($record && $record->exists()) {
+ if($record->hasExtension('Hierarchy')) {
+ $ancestors = $record->getAncestors();
+ $ancestors = new ArrayList(array_reverse($ancestors->toArray()));
+ $ancestors->push($record);
+ foreach($ancestors as $ancestor) {
+ $items->push(new ArrayData(array(
+ 'Title' => $ancestor->Title,
+ 'Link' => ($unlinked) ? false : Controller::join_links($this->Link('show'), $ancestor->ID)
+ )));
+ }
+ } else {
+ $items->push(new ArrayData(array(
+ 'Title' => $record->Title,
+ 'Link' => ($unlinked) ? false : Controller::join_links($this->Link('show'), $record->ID)
+ )));
+ }
+ }
+
+ return $items;
+ }
/**
* @return String HTML
@@ -522,10 +589,22 @@ public function SiteTreeAsUL() {
* @return String Nested unordered list with links to each page
*/
function getSiteTreeFor($className, $rootID = null, $childrenMethod = null, $numChildrenMethod = null, $filterFunction = null, $minNodeCount = 30) {
+ // Filter criteria
+ $params = $this->request->getVar('q');
+ if(isset($params['FilterClass']) && $filterClass = $params['FilterClass']){
+ if(!is_subclass_of($filterClass, 'CMSSiteTreeFilter')) {
+ throw new Exception(sprintf('Invalid filter class passed: %s', $filterClass));
+ }
+ $filter = new $filterClass($params);
+ } else {
+ $filter = null;
+ }
+
// Default childrenMethod and numChildrenMethod
- if (!$childrenMethod) $childrenMethod = 'AllChildrenIncludingDeleted';
- if (!$numChildrenMethod) $numChildrenMethod = 'numChildren';
-
+ if(!$childrenMethod) $childrenMethod = ($filter && $filter->getChildrenMethod()) ? $filter->getChildrenMethod() : 'AllChildrenIncludingDeleted';
+ if(!$numChildrenMethod) $numChildrenMethod = 'numChildren';
+ if(!$filterFunction) $filterFunction = ($filter) ? array($filter, 'isPageIncluded') : null;
+
// Get the tree root
$record = ($rootID) ? $this->getRecord($rootID) : null;
$obj = $record ? $record : singleton($className);
@@ -544,19 +623,22 @@ function getSiteTreeFor($className, $rootID = null, $childrenMethod = null, $num
}
// getChildrenAsUL is a flexible and complex way of traversing the tree
- $titleEval = '
- "<li id=\"record-$child->ID\" data-id=\"$child->ID\" class=\"" . $child->CMSTreeClasses($extraArg) . "\">" .
- "<ins class=\"jstree-icon\">&nbsp;</ins>" .
- "<a href=\"" . Controller::join_links($extraArg->Link("show"), $child->ID) . "\" title=\"'
- . _t('LeftAndMain.PAGETYPE','Page type: ')
- . '".$child->class."\" ><ins class=\"jstree-icon\">&nbsp;</ins><span class=\"text\">" . ($child->TreeTitle) .
- "</span></a>"
- ';
-
+ $controller = $this;
+ $recordController = ($this->stat('tree_class') == 'SiteTree') ? singleton('CMSPageEditController') : $this;
+ $titleFn = function(&$child) use(&$controller, &$recordController) {
+ $classes = $child->CMSTreeClasses();
+ if($controller->isCurrentPage($child)) $classes .= " current";
+ return "<li id=\"record-$child->ID\" data-id=\"$child->ID\" data-ssclass=\"$child->ClassName\" class=\"" . $classes . "\">" .
+ "<ins class=\"jstree-icon\">&nbsp;</ins>" .
+ "<a href=\"" . Controller::join_links($recordController->Link("show"), $child->ID) . "\" title=\"" .
+ _t('LeftAndMain.PAGETYPE','Page type: ') .
+ "$child->class\" ><ins class=\"jstree-icon\">&nbsp;</ins><span class=\"text\">" . ($child->TreeTitle).
+ "</span></a>";
+ };
$html = $obj->getChildrenAsUL(
- "",
- $titleEval,
- $this,
+ "",
+ $titleFn,
+ singleton('CMSPagesController'),
true,
$childrenMethod,
$numChildrenMethod,
@@ -577,7 +659,7 @@ function getSiteTreeFor($className, $rootID = null, $childrenMethod = null, $num
$treeTitle = '...';
}
- $html = "<ul><li id=\"record-0\" data-id=\"0\" class=\"Root nodelete\"><a href=\"$rootLink\"><strong>$treeTitle</strong></a>"
+ $html = "<ul><li id=\"record-0\" data-id=\"0\" class=\"Root nodelete\"><strong>$treeTitle</strong>"
. $html . "</li></ul>";
}
@@ -589,22 +671,12 @@ function getSiteTreeFor($className, $rootID = null, $childrenMethod = null, $num
* If ID = 0, then get the whole tree.
*/
public function getsubtree($request) {
- if($filterClass = $request->requestVar('FilterClass')) {
- if(!is_subclass_of($filterClass, 'CMSSiteTreeFilter')) {
- throw new Exception(sprintf('Invalid filter class passed: %s', $filterClass));
- }
-
- $filter = new $filterClass($request->requestVars());
- } else {
- $filter = null;
- }
-
$html = $this->getSiteTreeFor(
$this->stat('tree_class'),
$request->getVar('ID'),
- ($filter) ? $filter->getChildrenMethod() : null,
+ null,
null,
- ($filter) ? array($filter, 'isPageIncluded') : null,
+ null,
$request->getVar('minNodeCount')
);
@@ -636,13 +708,10 @@ public function save($data, $form) {
$form->saveInto($record, true);
$record->write();
$this->extend('onAfterSave', $record);
-
- $this->response->addHeader('X-Status', _t('LeftAndMain.SAVEDUP'));
-
- // write process might've changed the record, so we reload before returning
- $form = $this->getEditForm($record->ID);
+ $this->setCurrentPageID($record->ID);
- return $form->forTemplate();
+ $this->response->addHeader('X-Status', _t('LeftAndMain.SAVEDUP'));
+ return $this->getResponseNegotiator()->respond($this->request);
}
public function delete($data, $form) {
@@ -653,12 +722,12 @@ public function delete($data, $form) {
if(!$record || !$record->ID) throw new HTTPResponse_Exception("Bad record ID #" . (int)$data['ID'], 404);
$record->delete();
-
- if($this->isAjax()) {
- return $this->EmptyForm()->forTemplate();
- } else {
- $this->redirectBack();
- }
+
+ $this->response->addHeader('X-Status', _t('LeftAndMain.SAVEDUP'));
+ return $this->getResponseNegotiator()->respond(
+ $this->request,
+ array('currentform' => array($this, 'EmptyForm'))
+ );
}
/**
@@ -830,16 +899,24 @@ public function getEditForm($id = null, $fields = null) {
$actions = $record->getCMSActions();
// add default actions if none are defined
if(!$actions || !$actions->Count()) {
- if($record->hasMethod('canDelete') && $record->canDelete()) {
- $actions->push($deleteAction = new FormAction('delete',_t('ModelAdmin.DELETE','Delete')));
- $deleteAction->addExtraClass('ss-ui-action-destructive');
- }
if($record->hasMethod('canEdit') && $record->canEdit()) {
- $actions->push($saveAction = new FormAction('save',_t('CMSMain.SAVE','Save')));
- $saveAction->addExtraClass('ss-ui-action-constructive');
+ $actions->push(
+ FormAction::create('save',_t('CMSMain.SAVE','Save'))
+ ->addExtraClass('ss-ui-action-constructive')->setAttribute('data-icon', 'accept')
+ );
+ }
+ if($record->hasMethod('canDelete') && $record->canDelete()) {
+ $actions->push(
+ FormAction::create('delete',_t('ModelAdmin.DELETE','Delete'))
+ ->addExtraClass('ss-ui-action-destructive')
+ );
}
}
}
+
+ // Use <button> to allow full jQuery UI styling
+ $actionsFlattened = $actions->dataFields();
+ if($actionsFlattened) foreach($actionsFlattened as $action) $action->setUseButtonTag(true);
$form = new Form($this, "EditForm", $fields, $actions);
$form->addExtraClass('cms-edit-form');
@@ -863,7 +940,6 @@ public function getEditForm($id = null, $fields = null) {
// The clientside (mainly LeftAndMain*.js) rely on ajax responses
// which can be evaluated as javascript, hence we need
// to override any global changes to the validation handler.
- $validator->setJavascriptValidationHandler('prototype');
$form->setValidator($validator);
} else {
$form->unsetValidator();
@@ -874,16 +950,12 @@ public function getEditForm($id = null, $fields = null) {
$form->setFields($readonlyFields);
}
} else {
- $form = $this->RootForm();
+ $form = $this->EmptyForm();
}
return $form;
}
- function RootForm() {
- return $this->EmptyForm();
- }
-
/**
* Returns a placeholder form, used by {@link getEditForm()} if no record is selected.
* Our javascript logic always requires a form to be present in the CMS interface.
@@ -919,70 +991,50 @@ function EmptyForm() {
}
/**
- * @return Form
+ * Return the CMS's HTML-editor toolbar
*/
- function AddForm() {
- $class = $this->stat('tree_class');
-
- $typeMap = array($class => singleton($class)->i18n_singular_name());
- $form = new Form(
- $this,
- 'AddForm',
- new FieldList(
- new HiddenField('ParentID')
- ),
- new FieldList(
- $addAction = new FormAction('doAdd', _t('AssetAdmin_left.ss.GO','Go'))
- )
- );
- $addAction->addExtraClass('ss-ui-action-constructive');
- $form->addExtraClass('add-form');
-
- return $form;
+ public function EditorToolbar() {
+ return HtmlEditorField_Toolbar::create($this, "EditorToolbar");
}
-
+
/**
- * Add a new group and return its details suitable for ajax.
+ * Renders a panel containing tools which apply to all displayed
+ * "content" (mostly through {@link EditForm()}), for example a tree navigation or a filter panel.
+ * Auto-detects applicable templates by naming convention: "<controller classname>_Tools.ss",
+ * and takes the most specific template (see {@link getTemplatesWithSuffix()}).
+ * To explicitly disable the panel in the subclass, simply create a more specific, empty template.
+ *
+ * @return String HTML
*/
- public function doAdd($data, $form) {
- $class = $this->stat('tree_class');
-
- // check create permissions
- if(!singleton($class)->canCreate()) return Security::permissionFailure($this);
-
- // check addchildren permissions
- if(
- singleton($class)->hasDatabaseField('Hierarchy')
- && isset($data['ParentID'])
- && is_numeric($data['ParentID'])
- ) {
- $parentRecord = DataObject::get_by_id($class, $data['ParentID']);
- if(
- $parentRecord->hasMethod('canAddChildren')
- && !$parentRecord->canAddChildren()
- ) return Security::permissionFailure($this);
- }
-
- $record = Object::create($class);
- $form->saveInto($record);
- $record->write();
-
- // Used in TinyMCE inline folder creation
- if(isset($data['returnID'])) {
- return $record->ID;
- } else if($this->isAjax()) {
- $form = $this->getEditForm($record->ID);
- return $form->forTemplate();
+ public function Tools() {
+ $templates = $this->getTemplatesWithSuffix('_Tools');
+ if($templates) {
+ $viewer = new SSViewer($templates);
+ return $viewer->process($this);
} else {
- return $this->redirect(Controller::join_links($this->Link('show'), $record->ID));
+ return false;
}
}
/**
- * Return the CMS's HTML-editor toolbar
+ * Renders a panel containing tools which apply to the currently displayed edit form.
+ * The main difference to {@link Tools()} is that the panel is displayed within
+ * the element structure of the form panel (rendered through {@link EditForm}).
+ * This means the panel will be loaded alongside new forms, and refreshed upon save,
+ * which can mean a performance hit, depending on how complex your panel logic gets.
+ * Any form fields contained in the returned markup will also be submitted with the main form,
+ * which might be desired depending on the implementation details.
+ *
+ * @return String HTML
*/
- public function EditorToolbar() {
- return Object::create('HtmlEditorField_Toolbar', $this, "EditorToolbar");
+ public function EditFormTools() {
+ $templates = $this->getTemplatesWithSuffix('_EditFormTools');
+ if($templates) {
+ $viewer = new SSViewer($templates);
+ return $viewer->process($this);
+ } else {
+ return false;
+ }
}
/**
@@ -1005,11 +1057,11 @@ function BatchActionsForm() {
'BatchActionsForm',
new FieldList(
new HiddenField('csvIDs'),
- new DropdownField(
+ DropdownField::create(
'Action',
false,
$actionsMap
- )
+ )->setAttribute('autocomplete', 'off')
),
new FieldList(
// TODO i18n
@@ -1022,18 +1074,6 @@ function BatchActionsForm() {
return $form;
}
- public function myprofile() {
- $form = $this->Member_ProfileForm();
- return $this->customise(array(
- 'Content' => ' ',
- 'Form' => $form
- ))->renderWith('CMSDialog');
- }
-
- public function Member_ProfileForm() {
- return new Member_ProfileForm($this, 'Member_ProfileForm', Member::currentUser());
- }
-
public function printable() {
$form = $this->getEditForm($this->currentPageID());
if(!$form) return false;
@@ -1042,7 +1082,7 @@ public function printable() {
$form->setActions(null);
Requirements::clear();
- Requirements::css(SAPPHIRE_ADMIN_DIR . '/css/LeftAndMain_printable.css');
+ Requirements::css(FRAMEWORK_ADMIN_DIR . '/css/LeftAndMain_printable.css');
return array(
"PrintForm" => $form
);
@@ -1076,8 +1116,8 @@ function getSilverStripeNavigator() {
public function currentPageID() {
if($this->request->requestVar('ID')) {
return $this->request->requestVar('ID');
- } elseif ($this->request->param('ID') && is_numeric($this->request->param('ID'))) {
- return $this->request->param('ID');
+ } elseif (isset($this->urlParams['ID']) && is_numeric($this->urlParams['ID'])) {
+ return $this->urlParams['ID'];
} elseif(Session::get("{$this->class}.currentPage")) {
return Session::get("{$this->class}.currentPage");
} else {
@@ -1124,7 +1164,7 @@ public function isCurrentPage(DataObject $record) {
*
* @return String|boolean
*/
- public function PreviewLink() {
+ public function LinkPreview() {
return false;
}
@@ -1136,11 +1176,12 @@ public function PreviewLink() {
* @return string
*/
public function CMSVersion() {
- $sapphireVersion = file_get_contents(BASE_PATH . '/cms/silverstripe_version');
- if(!$sapphireVersion) $sapphireVersion = _t('LeftAndMain.VersionUnknown', 'unknown');
+ $frameworkVersion = file_get_contents(FRAMEWORK_PATH . '/silverstripe_version');
+ if(!$frameworkVersion) $frameworkVersion = _t('LeftAndMain.VersionUnknown', 'Unknown');
+
return sprintf(
- "sapphire: %s",
- $sapphireVersion
+ "Framework: %s",
+ $frameworkVersion
);
}
@@ -1167,7 +1208,7 @@ function SiteConfig() {
*
* @var String
*/
- static $application_name = 'SilverStripe CMS';
+ static $application_name = 'SilverStripe';
/**
* @param String $name
@@ -1226,7 +1267,7 @@ function MceRoot() {
* @return String
*/
function BaseCSSClasses() {
- return $this->CSSClasses();
+ return $this->CSSClasses('Controller');
}
function IsPreviewExpanded() {
@@ -1237,12 +1278,43 @@ function IsPreviewExpanded() {
* @return String
*/
function Locale() {
- return DBField::create('DBLocale', $this->i18nLocale());
+ return DBField::create_field('DBLocale', i18n::get_locale());
+ }
+
+ function providePermissions() {
+ $perms = array(
+ "CMS_ACCESS_LeftAndMain" => array(
+ 'name' => _t('CMSMain.ACCESSALLINTERFACES', 'Access to all CMS sections'),
+ 'category' => _t('Permission.CMS_ACCESS_CATEGORY', 'CMS Access'),
+ 'help' => _t('CMSMain.ACCESSALLINTERFACESHELP', 'Overrules more specific access settings.'),
+ 'sort' => -100
+ )
+ );
+
+ // Add any custom ModelAdmin subclasses. Can't put this on ModelAdmin itself
+ // since its marked abstract, and needs to be singleton instanciated.
+ foreach(ClassInfo::subclassesFor('ModelAdmin') as $i => $class) {
+ if($class == 'ModelAdmin') continue;
+ if(ClassInfo::classImplements($class, 'TestOnly')) continue;
+
+ $title = _t("{$class}.MENUTITLE", LeftAndMain::menu_title_for_class($class));
+ $perms["CMS_ACCESS_" . $class] = array(
+ 'name' => _t(
+ 'CMSMain.ACCESS',
+ "Access to '{title}' section",
+ "Item in permission selection identifying the admin section. Example: Access to 'Files & Images'",
+ array('title' => $title)
+ ),
+ 'category' => _t('Permission.CMS_ACCESS_CATEGORY', 'CMS Access')
+ );
+ }
+
+ return $perms;
}
/**
* Register the given javascript file as required in the CMS.
- * Filenames should be relative to the base, eg, SAPPHIRE_DIR . '/javascript/loader.js'
+ * Filenames should be relative to the base, eg, FRAMEWORK_DIR . '/javascript/loader.js'
*/
public static function require_javascript($file) {
self::$extra_requirements['javascript'][] = array($file);
@@ -1345,4 +1417,4 @@ function mark($node) {
return array_key_exists((int) $id, $this->ids) ? $this->ids[$id] : false;
}
}
-?>
+
View
4 admin/code/LeftAndMainDecorator.php
@@ -1,6 +1,6 @@
<?php
/**
- * @package sapphire
+ * @package framework
* @subpackage admin
* @deprecated 3.0 Use {@link LeftAndMainExtension}
*/
@@ -11,4 +11,4 @@ public function __construct() {
parent::__construct();
}
-}
+}
View
2  admin/code/LeftAndMainExtension.php
@@ -16,4 +16,4 @@ function accessedCMS() {
function augmentNewSiteTreeItem(&$item) {
}
-}
+}
View
36 admin/code/MemberImportForm.php
@@ -17,7 +17,7 @@ function __construct($controller, $name, $fields = null, $actions = null, $valid
if(!$fields) {
$helpHtml = _t(
'MemberImportForm.Help1',
- '<p>Import members in <em>CSV format</em> (comma-separated values). <small><a href="#" class="toggle-advanced">Show advanced usage</a></small></p>'
+ '<p>Import users in <em>CSV format</em> (comma-separated values). <small><a href="#" class="toggle-advanced">Show advanced usage</a></small></p>'
);
$helpHtml .= _t(
'MemberImportForm.Help2',
@@ -25,7 +25,7 @@ function __construct($controller, $name, $fields = null, $actions = null, $valid
<h4>Advanced usage</h4>
<ul>
<li>Allowed columns: <em>%s</em></li>
- <li>Existing members are matched by their unique <em>Code</em> property, and updated with any new values from the imported file.</li>
+ <li>Existing users are matched by their unique <em>Code</em> property, and updated with any new values from the imported file.</li>
<li>Groups can be assigned by the <em>Groups</em> column. Groups are identified by their <em>Code</em> property, multiple groups can be separated by comma. Existing group memberships are not cleared.</li>
</ul>
</div>');
@@ -48,16 +48,19 @@ function __construct($controller, $name, $fields = null, $actions = null, $valid
}
if(!$actions) $actions = new FieldList(
- new FormAction('doImport', _t('SecurityAdmin_MemberImportForm.BtnImport', 'Import'))
+ $importAction = new FormAction('doImport', _t('SecurityAdmin_MemberImportForm.BtnImport', 'Import from CSV'))
);
-
+
+ $importAction->addExtraClass('ss-ui-button');
+
if(!$validator) $validator = new RequiredFields('CsvFile');
-
parent::__construct($controller, $name, $fields, $actions, $validator);
- Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/jquery-entwine/dist/jquery.entwine-dist.js');
- Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/javascript/MemberImportForm.js');
+ Requirements::javascript(FRAMEWORK_DIR . '/thirdparty/jquery-entwine/dist/jquery.entwine-dist.js');
+ Requirements::javascript(FRAMEWORK_ADMIN_DIR . '/javascript/MemberImportForm.js');
+
+ $this->addExtraClass('cms');
$this->addExtraClass('import-form');
}
@@ -72,17 +75,17 @@ function doImport($data, $form) {
// result message
$msgArr = array();
- if($result->CreatedCount()) $msgArr[] = sprintf(
- _t('MemberImportForm.ResultCreated', 'Created %d members'),
- $result->CreatedCount()
+ if($result->CreatedCount()) $msgArr[] = _t(
+ 'MemberImportForm.ResultCreated', 'Created {count} members',
+ array('count' => $result->CreatedCount())
);
- if($result->UpdatedCount()) $msgArr[] = sprintf(
- _t('MemberImportForm.ResultUpdated', 'Updated %d members'),
- $result->UpdatedCount()
+ if($result->UpdatedCount()) $msgArr[] = _t(
+ 'MemberImportForm.ResultUpdated', 'Updated {count} members',
+ array('count' => $result->UpdatedCount())
);
- if($result->DeletedCount()) $msgArr[] = sprintf(
- _t('MemberImportForm.ResultDeleted', 'Deleted %d members'),
- $result->DeletedCount()
+ if($result->DeletedCount()) $msgArr[] = _t(
+ 'MemberImportForm.ResultDeleted', 'Deleted %d members',
+ array('count' => $result->DeletedCount())
);
$msg = ($msgArr) ? implode(',', $msgArr) : _t('MemberImportForm.ResultNone', 'No changes');
@@ -105,4 +108,3 @@ function getGroup($group) {
return $this->group;
}
}
-?>
View
371 admin/code/MemberTableField.php
@@ -1,371 +0,0 @@
-<?php
-/**
- * Enhances {ComplexTableField} with the ability to list groups and given members.
- * It is based around groups, so it deletes Members from a Group rather than from the entire system.
- *
- * In contrast to the original implementation, the URL-parameters "ParentClass" and "ParentID" are used
- * to specify "Group" (hardcoded) and the GroupID-relation.
- *
- * @todo write a better description about what this field does.
- *
- * Returns either:
- * - provided members
- * - members of a provided group
- * - all members
- * - members based on a search-query
- *
- * @package cms
- * @subpackage security
- */
-class MemberTableField extends ComplexTableField {
-
- protected $members;
-
- protected $hidePassword;
-
- protected $detailFormValidator;
-
- protected $group;
-
- protected $template = 'MemberTableField';
-
- public $popupClass = 'MemberTableField_Popup';
-
- public $itemClass = 'MemberTableField_Item';
-
- /**
- * Set the page size for this table.
- * @var int
- */
- public static $page_size = 20;
-
- protected $permissions = array(
- "add",
- "edit",
- "show",
- "delete",
- 'inlineadd'
- //"export",
- );
-
- /**
- * Constructor method for MemberTableField.
- *
- * @param Controller $controller Controller class which created this field
- * @param string $name Name of the field (e.g. "Members")
- * @param mixed $group Can be the ID of a Group instance, or a Group instance itself
- * @param SS_List $members Optional set of Members to set as the source items for this field
- * @param boolean $hidePassword Hide the password field or not in the summary?
- */
- function __construct($controller, $name, $group = null, $members = null, $hidePassword = true) {
-
- if(!$members) {
- if($group) {
- if(is_numeric($group)) $group = DataObject::get_by_id('Group', $group);
- $this->group = $group;
- $members = $group->Members();
-
- } elseif(isset($_REQUEST['ctf'][$this->getName()]["ID"]) && is_numeric($_REQUEST['ctf'][$this->getName()]["ID"])) {
- throw new Exception("Is this still being used? It's a hack and we should remove it.");
- $group = DataObject::get_by_id('Group', $_REQUEST['ctf'][$this->getName()]["ID"]);
- $this->group = $group;
- $members = $group->Members();
- } else {
- $members = DataObject::get("Member");
- }
- }
-
- $SNG_member = singleton('Member');
- $fieldList = $SNG_member->summaryFields();
- $memberDbFields = $SNG_member->db();
- $csvFieldList = array();
-
- foreach($memberDbFields as $field => $dbFieldType) {
- $csvFieldList[$field] = $field;
- }
-
- if(!$hidePassword) {
- $fieldList["SetPassword"] = "Password";
- }
-
- $this->hidePassword = $hidePassword;
-
- // Add a search filter
- $SQL_search = isset($_REQUEST['MemberSearch']) ? Convert::raw2sql($_REQUEST['MemberSearch']) : null;
- if(!empty($_REQUEST['MemberSearch'])) {
- $searchFilters = array();
- foreach($SNG_member->searchableFields() as $fieldName => $fieldSpec) {
- if(strpos($fieldName, '.') === false) $searchFilters[] = "\"$fieldName\" LIKE '%{$SQL_search}%'";
- }
- $members = $members->where('(' . implode(' OR ', $searchFilters) . ')');
- }
-
- parent::__construct($controller, $name, $members, $fieldList);
-
- $this->setFieldListCsv($csvFieldList);
- $this->setPageSize($this->stat('page_size'));
- }
-
- function FieldHolder() {
- $ret = parent::FieldHolder();
-
- Requirements::javascript(SAPPHIRE_DIR . "/thirdparty/scriptaculous/controls.js");
- Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/javascript/MemberTableField.js');
- Requirements::javascript(SAPPHIRE_ADMIN_DIR . "/javascript/MemberTableField_popup.js");
-
- return $ret;
- }
-
- function SearchForm() {
- $groupID = (isset($this->group)) ? $this->group->ID : 0;
- $query = isset($_GET['MemberSearch']) ? $_GET['MemberSearch'] : null;
-
- $searchFields = new FieldGroup(
- new TextField('MemberSearch', _t('MemberTableField.SEARCH', 'Search'), $query),
- new HiddenField("ctf[ID]", '', $groupID),
- new HiddenField('MemberFieldName', '', $this->name),
- new HiddenField('MemberDontShowPassword', '', $this->hidePassword)
- );
-
- $actionFields = new LiteralField('MemberFilterButton','<input type="submit" class="action" name="MemberFilterButton" value="'._t('MemberTableField.FILTER', 'Filter').'" id="MemberFilterButton"/>');
-
- $fieldContainer = new FieldGroup(
- $searchFields,