diff --git a/admin/code/CMSForm.php b/admin/code/CMSForm.php index 52dcda0d1..f364ad4ff 100644 --- a/admin/code/CMSForm.php +++ b/admin/code/CMSForm.php @@ -28,9 +28,16 @@ class CMSForm extends Form { protected function getValidationErrorResponse() { $request = $this->getRequest(); $negotiator = $this->getResponseNegotiator(); + if($request->isAjax() && $negotiator) { - $negotiator->setResponse(new SS_HTTPResponse($this)); - return $negotiator->respond($request); + $this->setupFormErrors(); + $result = $this->forTemplate(); + + return $negotiator->respond($request, array( + 'CurrentForm' => function() use($result) { + return $result; + } + )); } else { return parent::getValidationErrorResponse(); } diff --git a/admin/code/LeftAndMain.php b/admin/code/LeftAndMain.php index ca92f69b0..bc5919855 100644 --- a/admin/code/LeftAndMain.php +++ b/admin/code/LeftAndMain.php @@ -325,11 +325,11 @@ class LeftAndMain extends Controller implements PermissionProvider { 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/i18n.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', ) diff --git a/admin/javascript/LeftAndMain.EditForm.js b/admin/javascript/LeftAndMain.EditForm.js index 8754e7b2f..e2ff393c1 100644 --- a/admin/javascript/LeftAndMain.EditForm.js +++ b/admin/javascript/LeftAndMain.EditForm.js @@ -93,7 +93,7 @@ var firstTabWithErrors = this.find('.message.validation:first').closest('.tab'); $('.cms-container').clearCurrentTabState(); // clear state to avoid override later on this.redraw(); - firstTabWithErrors.closest('.cms-tabset').tabs('select', firstTabWithErrors.attr('id')); + firstTabWithErrors.closest('.ss-tabset').tabs('select', firstTabWithErrors.attr('id')); } this._super(); diff --git a/admin/tests/CMSMenuItemTest.php b/admin/tests/CMSMenuItemTest.php new file mode 100644 index 000000000..d6f61b173 --- /dev/null +++ b/admin/tests/CMSMenuItemTest.php @@ -0,0 +1,44 @@ + 'foo bar', 'disabled' => true, 'data-foo' => ''); + + $this->assertEquals( + 'title="foo bar" disabled="disabled" data-foo="<something>"', + $menuItem->getAttributesHTML($exampleAttributes), + 'Attributes appear correctly when passed as an argument' + ); + + $emptyAttributes = array('empty' => ''); + $this->assertEquals( + '', + $menuItem->getAttributesHTML($emptyAttributes), + 'No attributes are output when argument values are empty' + ); + $this->assertEquals( + '', + $menuItem->getAttributesHTML('some string'), + 'getAttributesHTML() ignores a string argument' + ); + + // Set attributes as class property + $menuItem->setAttributes($exampleAttributes); + $this->assertEquals( + 'title="foo bar" disabled="disabled" data-foo="<something>"', + $menuItem->getAttributesHTML(), + 'Attributes appear correctly when using setAttributes()' + ); + $this->assertEquals( + 'title="foo bar" disabled="disabled" data-foo="<something>"', + $menuItem->getAttributesHTML('foo bar'), + 'getAttributesHTML() ignores a string argument and falls back to class property' + ); + } + +} \ No newline at end of file diff --git a/dev/Debug.php b/dev/Debug.php index fc3512bb0..1d3f98f07 100644 --- a/dev/Debug.php +++ b/dev/Debug.php @@ -205,11 +205,16 @@ class Debug { * @param $message string to output */ public static function log($message) { - $file = dirname(__FILE__).'/../../debug.log'; + if (defined('BASE_PATH')) { + $path = BASE_PATH; + } + else { + $path = dirname(__FILE__) . '/../..'; + } + $file = $path . '/debug.log'; $now = date('r'); - $oldcontent = (file_exists($file)) ? file_get_contents($file) : ''; - $content = $oldcontent . "\n\n== $now ==\n$message\n"; - file_put_contents($file, $content); + $content = "\n\n== $now ==\n$message\n"; + file_put_contents($file, $content, FILE_APPEND); } /** diff --git a/docs/en/reference/shortcodes.md b/docs/en/reference/shortcodes.md index 362215484..76984bc66 100644 --- a/docs/en/reference/shortcodes.md +++ b/docs/en/reference/shortcodes.md @@ -64,7 +64,10 @@ These parameters are passed to the callback: will not have been parsed, and can optionally be fed back into the parser. - The ShortcodeParser instance used to parse the content. - The shortcode tag name that was matched within the parsed content. - + - An associative array of extra information about the shortcode being parsed. For example, if the shortcode is + is inside an attribute, the `element` key contains a reference to the parent `DOMElement`, and the `node` + key the attribute's `DOMNode`. + ## Example: Google Maps Iframe by Address To demonstrate how easy it is to build custom shortcodes, we'll build one to display diff --git a/javascript/GridField.js b/javascript/GridField.js index 9574a094b..746f6fbf6 100644 --- a/javascript/GridField.js +++ b/javascript/GridField.js @@ -136,7 +136,7 @@ }); // Covers both tabular delete button, and the button on the detail form - $('.ss-gridfield .Actions .action.gridfield-button-delete, .cms-edit-form .Actions button.action.action-delete').entwine({ + $('.ss-gridfield .col-buttons .action.gridfield-button-delete, .cms-edit-form .Actions button.action.action-delete').entwine({ onclick: function(e){ if(!confirm(ss.i18n._t('TABLEFIELD.DELETECONFIRMMESSAGE'))) { e.preventDefault(); diff --git a/javascript/TreeDropdownField.js b/javascript/TreeDropdownField.js index 7c05f33e4..13042dac0 100644 --- a/javascript/TreeDropdownField.js +++ b/javascript/TreeDropdownField.js @@ -23,9 +23,9 @@ }); var strings = { - 'openlink': 'Open', - 'fieldTitle': '(Choose)', - 'searchFieldTitle': '(Choose or Search)' + 'openlink': ss.i18n._t('TreeDropdownField.OpenLink'), + 'fieldTitle': '(' + ss.i18n._t('TreeDropdownField.FieldTitle') + ')', + 'searchFieldTitle': '(' + ss.i18n._t('TreeDropdownField.SearchFieldTitle') + ')' }; var _clickTestFn = function(e) { @@ -298,11 +298,7 @@ $('.TreeDropdownField.searchable').entwine({ onadd: function() { this._super(); - var title = ss.i18n._t( - 'DropdownField.ENTERTOSEARCH', - 'Press enter to search' - ); - + var title = ss.i18n._t('TreeDropdownField.ENTERTOSEARCH'); this.find('.treedropdownfield-panel').prepend( $('') ); diff --git a/javascript/lang/en_US.js b/javascript/lang/en_US.js index 076f18db6..2d3ec171c 100644 --- a/javascript/lang/en_US.js +++ b/javascript/lang/en_US.js @@ -36,6 +36,10 @@ if(typeof(ss) == 'undefined' || typeof(ss.i18n) == 'undefined') { 'UploadField.LOADING': 'Loading ...', 'UploadField.Editing': 'Editing ...', 'UploadField.Uploaded': 'Uploaded', - 'UploadField.OVERWRITEWARNING': 'File with the same name already exists' + 'UploadField.OVERWRITEWARNING': 'File with the same name already exists', + 'TreeDropdownField.ENTERTOSEARCH': 'Press enter to search', + 'TreeDropdownField.OpenLink': 'Open', + 'TreeDropdownField.FieldTitle': 'Choose', + 'TreeDropdownField.SearchFieldTitle': 'Choose or Search' }); } diff --git a/javascript/lang/mi_NZ.js b/javascript/lang/mi_NZ.js index 8df395b98..402610e46 100644 --- a/javascript/lang/mi_NZ.js +++ b/javascript/lang/mi_NZ.js @@ -13,14 +13,14 @@ if(typeof(ss) == 'undefined' || typeof(ss.i18n) == 'undefined') { 'UPDATEURL.CONFIRM': 'Kei te hiahia koe kia huri au i te PRO ki:\n\n%s/\n\nPāwhiri Āe kia hurihia te PRO, pāwhiri Whakakore kia waiho:\n\n%s', 'UPDATEURL.CONFIRMURLCHANGED':'Kua hurihia te PRO ki \n"%s"', 'FILEIFRAMEFIELD.DELETEFILE': 'Muku Kōnae', - 'FILEIFRAMEFIELD.UNATTACHFILE': 'Wehe Kōnae', + 'FILEIFRAMEFIELD.UNATTACHFILE': 'Wehetāpiri Kōnae', 'FILEIFRAMEFIELD.DELETEIMAGE': 'Muku Atahanga', 'FILEIFRAMEFIELD.CONFIRMDELETE': 'Kei te tino hiahia muku i tēnei kōnae?', 'LeftAndMain.IncompatBrowserWarning': 'Kāore tō pūtirotiro i te hototahi ki te atanga CMS. Whakamahia Internet Explorer 7+, Google Chrome 10+, Mozilla Firefox 3.5+ rānei.', 'GRIDFIELD.ERRORINTRANSACTION': 'Kua puta mai he hapa i te tiki raraunga mai i te tūmau\n Ngāna anō ā muri atu.', 'UploadField.ConfirmDelete': 'He tika tonu kia tangohia tēnei kōnae i te pūnahakōnae tūmau?', 'UploadField.PHP_MAXFILESIZE': 'Kua hipa te mōrahi_rahikōnae_tukuatu i te kōnae (whakaritenga php.ini)', - 'UploadField.HTML_MAXFILESIZE': 'Kua hipa te MŌRAHI_RAHI_KŌNAE i te kōnae (whakaritenga puka HTML)', + 'UploadField.HTML_MAXFILESIZE': 'Kua hipa te mōrahi_rahi_kōnae i te kōnae (whakaritenga puka HTML)', 'UploadField.ONLYPARTIALUPLOADED': 'Kua tukuna atu he wāhanga anake o te kōnae', 'UploadField.NOFILEUPLOADED': 'Kāore he Kōnae i tukuna atu', 'UploadField.NOTMPFOLDER': 'Kua ngaro tētahi kōpaki rangitahi', @@ -34,6 +34,11 @@ if(typeof(ss) == 'undefined' || typeof(ss.i18n) == 'undefined') { 'UploadField.EMPTYRESULT': 'Otinga tukuatu kōnae piako', 'UploadField.LOADING': 'Uta ana...', 'UploadField.Editing': 'Whakatika ana ...', - 'UploadField.Uploaded': 'Kua tukuna atu' + 'UploadField.Uploaded': 'Kua tukuna atu', + 'UploadField.OVERWRITEWARNING': 'Kei te tīari kē tētahi kōnae me te ingoa ōrite', + 'TreeDropdownField.ENTERTOSEARCH': 'Pēhi tāuru hei rapu', + 'TreeDropdownField.OpenLink': 'Whakatuwhera', + 'TreeDropdownField.FieldTitle': 'Kōwhiri', + 'TreeDropdownField.SearchFieldTitle': 'Kōwhiri ka Rapu rānei' }); } diff --git a/lang/mi.yml b/lang/mi.yml index 8daaafe0d..b8d13ffa1 100644 --- a/lang/mi.yml +++ b/lang/mi.yml @@ -2,6 +2,7 @@ mi: AssetAdmin: ALLOWEDEXTS: 'Ngā toronga ka whakaaetia' NEWFOLDER: KōpakiHōu + SHOWALLOWEDEXTS: 'Whakaaturia mai ngā toronga e whakaaetia ana' AssetTableField: CREATED: 'Tukuatu tuatahi' DIM: Ngā Rahinga @@ -68,6 +69,8 @@ mi: ACCESSALLINTERFACES: 'Uru ki ngā wāhanga CMS katoa' ACCESSALLINTERFACESHELP: 'Ka takahi i ngā tautuhinga uru tauwhāiti ake' SAVE: Tiaki + CMSProfileController: + MENUTITLE: 'Taku Kōtaha' ChangePasswordEmail_ss: CHANGEPASSWORDTEXT1: 'Kua hurihia tō kupuhipa mō' CHANGEPASSWORDTEXT2: 'Ka taea te whakamahi i ēnei taipitopito tuakiri ināianei hei takiuru:' @@ -96,13 +99,30 @@ mi: FOURTH: tuawhā SECOND: tuarua THIRD: tuatoru + CurrencyField: + CURRENCYSYMBOL: $ DataObject: PLURALNAME: 'Ngā Ahanoa Raraunga' SINGULARNAME: 'Ahanoa Raraunga' Date: + DAY: rā + DAYS: ngā rā + HOUR: haora + HOURS: ngā haora + MIN: meneti + MINS: ngā meneti + MONTH: marama + MONTHS: ngā marama + SEC: hēkona + SECS: ngā hēkona TIMEDIFFAGO: '{difference} i mua' TIMEDIFFIN: 'i roto i te {difference}' + YEAR: tau + YEARS: ngā tau + LessThanMinuteAgo: 'iti iho i te meneti kotahi' DateField: + NOTSET: 'kāore i tautuhia' + TODAY: tēnei rā VALIDDATEFORMAT2: 'Tāurua he hōputu rā tika ({format})' VALIDDATEMAXDATE: 'Me tawhito ake tō rā, kia ōrite rānei ki te rā mōrahi ({date}) kua whakaaetia' VALIDDATEMINDATE: 'Me hōu ake tō rā, kia ōrite rānei ki te rā moroiti ({date}) kua whakaaetia' @@ -120,18 +140,37 @@ mi: Enum: ANY: Ko tētahi File: + AviType: 'kōnae ataata AVI' Content: Ngā Ihirangi + CssType: 'kōnae CSS' + DmgType: 'atahanga kōpae Apple' + DocType: 'tuhinga Word' Filename: Ingoa Kōnae + GifType: 'atahanga GIF - he pai mō ngā hoahoa' + GzType: 'kōnae kōpeke GZIP' + HtlType: 'kōnae HTML' + HtmlType: 'kōnae HTML' INVALIDEXTENSION: 'Kāore e whakaaetia te toronga (valid: {extensions})' INVALIDEXTENSIONSHORT: 'Kāore e whakaaetia te toronga' + IcoType: 'atahanga Ata' + JpgType: 'atahanga JPEG - he pai mō ngā whakaahua' + JsType: 'kōnae Javascript' + Mp3Type: 'kōnae ororongo MP3' + MpgType: 'kōnae ataata MPEG' NOFILESIZE: 'He kore ngā paita kei te kōnae' NOVALIDUPLOAD: 'Ehara te kōnae i te tukuatu pono' Name: Ingoa PLURALNAME: Ngā Kōnae + PdfType: 'kōnae Adobe Acrobat PDF' + PngType: 'atahanga PNG - he hōputu pai hei whakamahi whānui noa' SINGULARNAME: Kōnae TOOLARGE: 'He rahi rawa te rahi kōnae, he {size} te rahi mōrahi ka taea' TOOLARGESHORT: 'Ka hipa te {size} i te rahi kōnae' + TiffType: 'Hōputu atatahanga tūtohu ' Title: Taitara + WavType: 'kōnae ororongo WAV' + XlsType: 'ripakaute Excel' + ZipType: 'kōnae kōpeke ZIP' FileIFrameField: ATTACH: 'Āpiti {type}' ATTACHONCESAVED: 'Ka taea te āpiti i ngā {type} ina oti te tiaki tuatahi o te pūkete.' @@ -147,12 +186,17 @@ mi: TITLE: 'Iframe Tukuatu Atahanga' Filesystem: SYNCRESULTS: 'Kua oti te tukutahi: e {createdcount} ngā tūemi i hangaia, e {deletedcount} ngā tūemi i mukua' + Folder: + PLURALNAME: Ngā Kōpaki + SINGULARNAME: Kōpaki ForgotPasswordEmail_ss: HELLO: Kia ora TEXT1: 'Anei tō' TEXT2: 'hono tautuhi kupuhipa anō' TEXT3: mā Form: + FIELDISREQUIRED: 'Ka hiahiatia te {name}' + SubmitBtnLabel: Haere VALIDATIONCREDITNUMBER: 'Tirohia kua tika tō tāuru i te tau kāri nama {number}' VALIDATIONNOTUNIQUE: 'Ehara te uara i tāurua i te ahurei' VALIDATIONPASSWORDSDONTMATCH: 'Kāore ngā kupuhipa i te ōrite' @@ -160,8 +204,10 @@ mi: VALIDATIONSTRONGPASSWORD: 'Kia kotahi tonu te mati, kia tahi hoki te pūāhua retawhika i te iti rawa o ngā kupuhipa' VALIDATOR: Pūwhakamana VALIDCURRENCY: 'Tāurua he moni tika' + CSRF_FAILED_MESSAGE: 'Te āhua nei kua puta he raru hangarau. Pāwhiria te pātene hoki, ka tāmata anō i tō pūtirotiro, ka ngana anō.' FormField: NONE: Kore + Example: 'hei tauira %s' GridAction: DELETE_DESCRIPTION: Muku Delete: Muku @@ -183,6 +229,7 @@ mi: ResetFilter: Tautuhi anō GridFieldAction_Delete: DeletePermissionsFailure: 'Kāore he muku whakaaetanga' + EditPermissionsFailure: 'Kāore ō whakaaetanga kia wetehono pūkete' GridFieldDetailForm: CancelBtn: Whakakore Create: Hanga @@ -190,16 +237,25 @@ mi: DeletePermissionsFailure: 'Kāore he whakaaetanga muku' Deleted: 'Kua mukua %s %s' Save: Tiaki + Saved: 'I tiakina te {name} {link}' GridFieldItemEditView_ss: Go_back: 'Hoki' Group: AddRole: 'Tāpiritia he tūnga mō tēnei rōpū' + Code: 'Waehere Rōpū' + DefaultGroupTitleAdministrators: Ngā Kaiwhakahaere DefaultGroupTitleContentAuthors: 'Ngā Kaituhi Ihirangi' + Description: Whakaahuatanga GroupReminder: 'Mēnā ka kōwhiri koe i tētahi rōpū matua, ka whiwhi tēnei rōpū i ōna tūnga katoa' + Locked: 'Kua maukati?' + NoRoles: 'Kāore i kitea he tūnga' PLURALNAME: Ngā Rōpū + Parent: 'Rōpū Matua' RolesAddEditLink: 'Whakahaere tūnga' SINGULARNAME: Rōpū + Sort: 'Raupapa Kōmaka' has_many_Permissions: Ngā Whakaaetanga + many_many_Members: Ngā Mema GroupImportForm: Help1: '

Kawea mai ngā kaiwhakamahi i te hōputu CSV (ngā uara ka wehea ki te piko). Whakaatu whakamahinga ara atu anō

' Help2: "
\n

Advanced usage

\n \n
" @@ -231,6 +287,8 @@ mi: FROMWEB: 'Mai i te tukutuku' FindInFolder: 'Rapu i te Kōpaki' IMAGEALT: 'Tuhinga kē (alt)' + IMAGEALTTEXT: 'Kuputuhi kē (alt) - ka whakaaturia ki te kore e taea te atahanga te whakaatu' + IMAGEALTTEXTDESC: 'Ka whakaaturia ki ngā pūpānui mata ki te kore e taea te atahanga te whakaatu' IMAGEDIMENSIONS: Ngā Rahinga IMAGEHEIGHTPX: Teitei IMAGETITLE: 'Tuhinga taitara (ākiutauta) - mō ngā mōhiohio tāpiri mō te atahanga' @@ -251,6 +309,7 @@ mi: URL: PRO URLNOTANOEMBEDRESOURCE: 'Kāore e taea te huri i te PRO ''{url}'' hei rawa pāpāho.' UpdateMEDIA: 'Whakahōu Pāpāho' + BUTTONADDURL: 'Tāpiri PRO' Image: PLURALNAME: Ngā Kōnae SINGULARNAME: Kōnae @@ -275,6 +334,9 @@ mi: REORGANISATIONSUCCESSFUL: 'Kua momoho te whakaraupapa anō i te rākau pae' SAVEDUP: Kua Tiakina VersionUnknown: tē mōhiotia + ShowAsList: 'whakaaturia hei rārangi' + TooManyPages: 'He nui rawa ngā whārangi' + ValidationError: 'Hapa manatoko' LeftAndMain_Menu_ss: Hello: Kia ora LOGOUT: 'Takiputa' @@ -290,6 +352,7 @@ mi: BUTTONLOGIN: 'Takiuru' BUTTONLOGINOTHER: 'Takiuru hei tangata kē' BUTTONLOSTPASSWORD: 'Kua ngaro i a au taku kupuhipa' + CANTEDIT: 'Kāore ō whakaaetanga kia pēnā' CONFIRMNEWPASSWORD: 'Whakaū Kupuhipa Hōu' CONFIRMPASSWORD: 'Whakaū Kupuhipa' DATEFORMAT: 'Hōputu Rā' @@ -299,6 +362,7 @@ mi: EMPTYNEWPASSWORD: 'Kāore e whakaaetia kia piako te kupuhipa hōu, ngana anō' ENTEREMAIL: 'Tāurua he wāhitau īmēra kia whiwhi i te hono tautuhi kupuhipa anō.' ERRORLOCKEDOUT: 'Kua mono rangitahitia tō pūkete nā te nui rawa o ngā whakamātau hē ki te takiuru. Ngana anō ā te 20 meneti.' + ERRORLOCKEDOUT2: 'Kua monokia rangitahitia tō pūkete nā te nui rawa o ngā ngana takiuru kua rahua. Ngana anō ā muri i te {count} meneti.' ERRORNEWPASSWORD: 'Kua rerekē tō tāuru kupuhipa, whakamātau anō' ERRORPASSWORDNOTMATCH: 'Kāore i te ōrite tō kupuhipa o nāianei, ngana anō' ERRORWRONGCRED: 'Te āhua nei ehara i te wāhitau īmerā tika, i te kuphipa tika rānei. Ngana anō' @@ -326,6 +390,7 @@ mi: db_NumVisit: 'Maha o ngā Toronga' db_Password: Kupuhipa db_PasswordExpiry: 'Rā Mōnehu Kupuhipa' + NoPassword: 'Kāore he kupuhipa i tēnei mema.' MemberAuthenticator: TITLE: 'Īmērā & Kupuhipa' MemberDatetimeOptionsetField: @@ -348,6 +413,7 @@ mi: TWODIGITMONTH: 'Marama matirua (01=Kohitātea)' TWODIGITSECOND: 'Ngā mati hēkona e rua (00 ki te 59)' TWODIGITYEAR: 'Tau matirua' + Toggle: 'Whakaaturia te āwhina whakahōputu' MemberImportForm: Help1: '

Kawea mai ngā kaiwhakamahi i te hōputu CSV (ngā uara ka wehea ki te piko). Whakaatu whakamahinga ara atu anō

' Help2: "
\n

Advanced usage

\n \n
" @@ -355,11 +421,15 @@ mi: ResultDeleted: 'Kua mukua e %d ngā mema' ResultNone: 'Kāore he huringa' ResultUpdated: 'I whakahōutia e {count} mhā mema' + MemberPassword: + PLURALNAME: 'Ngā Kupuhipa Mema' + SINGULARNAME: 'Kupuhipa Mema' MemberTableField: APPLY_FILTER: 'Hoatu Tātari' ModelAdmin: DELETE: Muku DELETEDRECORDS: 'I mukua e {count} ngā pūkete.' + EMPTYBEFOREIMPORT: 'Whakakapi raraunga' IMPORT: 'Kawemai i CSV' IMPORTEDRECORDS: 'I kawea mai e {count} ngā pūkete.' NOCSVFILE: 'Pūtirotiro kia kitea he kōnae CSV hei kawemai' @@ -387,22 +457,30 @@ mi: VALIDATION: 'Ehara te ''{value}'' i te tau, ka taea ngā tau anake ki tēnei āpure' Pagination: Page: Whārangi + View: Tiro Permission: AdminGroup: Kaiwhakahaere CMS_ACCESS_CATEGORY: 'Uru CMS' FULLADMINRIGHTS: 'Ngā motika kaiwhakahaere katoa' FULLADMINRIGHTS_HELP: 'Ka whakapae me te takahi i ērā atu whakaaetanga katoa kua tautapatia.' + PLURALNAME: Ngā Whakaaetanga + SINGULARNAME: Whakaaetanga PermissionCheckboxSetField: AssignedTo: 'kua tautapatia ki "{title}"' FromGroup: 'I tukuna iho i te rōpū "{title}"' FromRole: 'I tukuna iho i te tūnga "{title}"' FromRoleOnGroup: 'i tukuna iho i "%s" i te rōpū "%s"' PermissionRole: + OnlyAdminCanApply: 'Ka taea anake te tono e ngā kaiwhakahaere' PLURALNAME: Ngā Tūnga SINGULARNAME: Tūranga Title: Taitara + PermissionRoleCode: + PLURALNAME: 'Ngā Waehere Tūnga Whakaaetanga' + SINGULARNAME: 'Waehere Tūnga Whakaaetanga' Permissions: PERMISSIONS_CATEGORY: 'Ngā tūnga me ngā whakaaetanga uru' + UserPermissionsIntro: 'Mā te tautapa rōpū ki tēnei kaiwhakamahi e whakarite āna whakaaetanga. Tirohia te wāhanga rōpū mō ngā taipitopito o ngā whakaaetanga o ngā rōpū takitahi.' PhoneNumberField: VALIDATION: 'Tāurua he tau waea tika' RelationComplexTableField_ss: @@ -411,6 +489,7 @@ mi: NOTFOUND: 'Kāore i kitea he tūemi' Security: ALREADYLOGGEDIN: 'Kāore i te whakaaetia kia uru koe ki tēnei whārangi. Mēnā he pūkete anō tōu e taea ai te uru ki tēnā whārangi, ka taea te takiuru anō i raro.' + LOSTPASSWORDHEADER: 'Kupuhipa Ngaro' BUTTONSEND: 'Tukuna mai te hono tautuhi kupuhipa anō' CHANGEPASSWORDBELOW: 'Ka taea te huri i tō kupuhipa i raro' CHANGEPASSWORDHEADER: 'Hurihia tō kupuhipa' @@ -446,6 +525,19 @@ mi: FileFieldLabel: 'Kōnae CSV (Ngā toronga ka whakaaetia: *.csv)' SilverStripeNavigator: Edit: Whakatika + Auto: Aunoa + ChangeViewMode: 'Hurihia te aratau tiro' + Desktop: Papamahi + DualWindowView: 'Matapihi Takirua' + EditView: 'Aratau whakatika' + Mobile: Pūkoro + PreviewState: 'Tūnga Arokite' + PreviewView: 'Aratau arokite' + Responsive: Urupare + SplitView: 'Aratau weherua' + Tablet: Paparorohiko + ViewDeviceWidth: 'Tīpakohia he whānui arokite' + Width: whānui SimpleImageField: NOUPLOAD: 'Kāore He Atahanga Tukuatu' SiteTree: @@ -493,17 +585,31 @@ mi: FROMCOMPUTER: 'Mai i tō rorohiko' FROMCOMPUTERINFO: 'Tīpako mai i ngā kōnae' FROMFILES: 'I ngā kōnae' + HOTLINKINFO: 'Mōhiohio: Ka honoweratia tēnei atahanga. Me whakarite kia whai whakaaetanga koe i te kaihanga pae taketake kia pēnā.' MAXNUMBEROFFILES: 'Kua hipa te mōrahi o ngā kōnae {count}.' MAXNUMBEROFFILESSHORT: 'Ka taea te tukuatu i ngā kōnae {count} anake ' + MAXNUMBEROFFILESONE: 'Ka taea tētahi kōnae kotahi anake te tukuatu' REMOVE: Tango REMOVEERROR: 'Kua rarua te tango kōnae' REMOVEINFO: 'Tangohia tēnei kōane i konei, engari kaua e muku i te pātaka kōnae' STARTALL: 'Tīmata katoa' STARTALLINFO: 'Tīmataria ngā tukuatu katoa' Saved: Kua Tiakina + CHOOSEANOTHERFILE: 'Kōwhiria tētahi kōnae anō' + CHOOSEANOTHERINFO: 'Whakakapia tēnei kōnae ki tētahi atu mai i te pātaka kōnae' + OVERWRITEWARNING: 'Kei te tīari kē tētahi kōnae me te ingoa ōrite' + UPLOADSINTO: 'ka tiaki ki /{path}' Versioned: has_many_Versions: Ngā Putanga + CMSPageHistoryController_versions_ss: + PREVIEW: 'Arokite Paetukutuku' GridFieldEditButton_ss: EDIT: Whakatika + ContentController: + NOTLOGGEDIN: 'kāore i te takiuru' GridFieldItemEditView: Go_back: 'Hoki' + PasswordValidator: + LOWCHARSTRENGTH: 'Whakakahatia tō kupuhipa mā te tāpiri i ētahi o ēnei pūāhua: %s' + PREVPASSWORD: 'Kua whakamahi kētia tēnā kupuhipa i mua, kōwhiria he kupuhipa hou' + TOOSHORT: 'He poto rawa te kupuhipa, me %s pūāhua neke atu te roa' diff --git a/lang/zh.yml b/lang/zh.yml index 9064823b2..dc8905da9 100644 --- a/lang/zh.yml +++ b/lang/zh.yml @@ -413,8 +413,8 @@ zh: TWODIGITYEAR: '两位数表示的年份' Toggle: '显示格式帮助' MemberImportForm: - Help1: '<p>采用 <em>CSV 格式</em> 导入用户(逗号分隔值)<small><a href="#" class="toggle-advanced">显示高级用法</a></small></p>' - Help2: "<div class=\"advanced\">\n <h4>高级用法</h4>\n <ul>\n <li>允许的栏目:<em>%s</em></li>\n <li>通过独有的 <em>代码</em> 属性对现有用户进行配对并使用导入文件中任何新的值更新他们。</li>\n <li>群组可通过 <em>组别</em> 栏目进行分类。群组通过他们的<em>代码</em> 属性进行识别,\n多个群组可用逗号隔开。现有的群组分配情况不会被清除。</li>\n </ul>\n</div>" + Help1: '

采用 CSV 格式 导入用户(逗号分隔值)显示高级用法

' + Help2: "
\n

高级用法

\n \n
" ResultCreated: '已创建 {count} 位成员' ResultDeleted: '已删除 %d 位成员' ResultNone: '无更改' @@ -520,7 +520,7 @@ zh: Users: 用户 SecurityAdmin_MemberImportForm: BtnImport: '从 CSV 导入' - FileFieldLabel: 'CSV 文件 <small>(允许的扩展名:*.csv)</small>' + FileFieldLabel: 'CSV 文件 (允许的扩展名:*.csv)' SilverStripeNavigator: Edit: 编辑 Auto: 自动 diff --git a/parsers/ShortcodeParser.php b/parsers/ShortcodeParser.php index 8388873e7..ed7e659d9 100644 --- a/parsers/ShortcodeParser.php +++ b/parsers/ShortcodeParser.php @@ -68,6 +68,7 @@ class ShortcodeParser { * this will not have been parsed, and can optionally be fed back into the parser. * - The {@link ShortcodeParser} instance used to parse the content. * - The shortcode tag name that was matched within the parsed content. + * - An associative array of extra information about the shortcode being parsed. * * @param string $shortcode The shortcode tag to map to the callback - normally in lowercase_underscore format. * @param callback $callback The callback to replace the shortcode with. @@ -102,9 +103,9 @@ class ShortcodeParser { $this->shortcodes = array(); } - public function callShortcode($tag, $attributes, $content) { + public function callShortcode($tag, $attributes, $content, $extra = array()) { if (!isset($this->shortcodes[$tag])) return false; - return call_user_func($this->shortcodes[$tag], $attributes, $content, $this, $tag); + return call_user_func($this->shortcodes[$tag], $attributes, $content, $this, $tag, $extra); } // -------------------------------------------------------------------------------------------------------------- @@ -332,11 +333,12 @@ class ShortcodeParser { for($i = 0; $i < $attributes->length; $i++) { $node = $attributes->item($i); $tags = $this->extractTags($node->nodeValue); + $extra = array('node' => $node, 'element' => $node->ownerElement); if($tags) { $node->nodeValue = $this->replaceTagsWithText($node->nodeValue, $tags, - function($idx, $tag) use ($parser){ - $content = $parser->callShortcode($tag['open'], $tag['attrs'], $tag['content']); + function($idx, $tag) use ($parser, $extra){ + $content = $parser->callShortcode($tag['open'], $tag['attrs'], $tag['content'], $extra); if ($content === false) { if(ShortcodeParser::$error_behavior == ShortcodeParser::ERROR) { diff --git a/security/Member.php b/security/Member.php index 5c9ceb6df..de25557f4 100644 --- a/security/Member.php +++ b/security/Member.php @@ -1192,7 +1192,11 @@ class Member extends DataObject implements TemplateGlobalProvider { $fields->removeByName('Groups'); if(Permission::check('EDIT_PERMISSIONS')) { - $groupsMap = Group::get()->map('ID', 'Breadcrumbs')->toArray(); + $groupsMap = array(); + foreach(Group::get() as $group) { + // Listboxfield values are escaped, use ASCII char instead of » + $groupsMap[$group->ID] = $group->getBreadcrumbs(' > '); + } asort($groupsMap); $fields->addFieldToTab('Root.Main', ListboxField::create('DirectGroups', singleton('Group')->i18n_plural_name()) diff --git a/tests/parsers/ShortcodeParserTest.php b/tests/parsers/ShortcodeParserTest.php index a87caff85..1ab935a06 100644 --- a/tests/parsers/ShortcodeParserTest.php +++ b/tests/parsers/ShortcodeParserTest.php @@ -6,6 +6,7 @@ class ShortcodeParserTest extends SapphireTest { protected $arguments, $contents, $tagName, $parser; + protected $extra = array(); public function setUp() { ShortcodeParser::get('test')->register('test_shortcode', array($this, 'shortcodeSaver')); @@ -210,16 +211,25 @@ class ShortcodeParserTest extends SapphireTest { ); } + public function testExtraContext() { + $this->parser->parse('Test'); + + $this->assertInstanceOf('DOMNode', $this->extra['node']); + $this->assertInstanceOf('DOMElement', $this->extra['element']); + $this->assertEquals($this->extra['element']->tagName, 'a'); + } + // ----------------------------------------------------------------------------------------------------------------- /** * Stores the result of a shortcode parse in object properties for easy testing access. */ - public function shortcodeSaver($arguments, $content = null, $parser, $tagName = null) { + public function shortcodeSaver($arguments, $content, $parser, $tagName, $extra) { $this->arguments = $arguments; - $this->contents = $content; - $this->tagName = $tagName; - + $this->contents = $content; + $this->tagName = $tagName; + $this->extra = $extra; + return $content; }