From 449cce95a73015a73da3dbdc56d1e8eb6500b72a Mon Sep 17 00:00:00 2001 From: Sean Harvey Date: Tue, 4 Dec 2012 14:36:59 +1300 Subject: [PATCH 01/73] Fixing .htaccess to ignore rewriting PHP files directly --- dev/install/install.php5 | 1 + 1 file changed, 1 insertion(+) diff --git a/dev/install/install.php5 b/dev/install/install.php5 index 0b6d9b151..d3ec3783e 100644 --- a/dev/install/install.php5 +++ b/dev/install/install.php5 @@ -1281,6 +1281,7 @@ ErrorDocument 500 /assets/error-500.html $baseClause RewriteCond %{REQUEST_URI} ^(.*)$ RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_URI} !\.php$ RewriteRule .* $modulePath/main.php?url=%1&%{QUERY_STRING} [L] TEXT; From c23df511cd0dc0d316489bd443d7256ee28c4226 Mon Sep 17 00:00:00 2001 From: Sean Harvey Date: Fri, 14 Dec 2012 12:06:25 +1300 Subject: [PATCH 02/73] Improve class naming and docs for DataList::applyFilterContext() --- model/DataList.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/model/DataList.php b/model/DataList.php index da740e24a..86195c2c2 100644 --- a/model/DataList.php +++ b/model/DataList.php @@ -386,7 +386,7 @@ class DataList extends ViewableData implements SS_List, SS_Filterable, SS_Sortab $fieldArgs = explode(':',$field); $field = array_shift($fieldArgs); foreach($fieldArgs as $fieldArg){ - $comparisor = $this->applyFilterContext($field, $fieldArg, $value); + $this->applyFilterContext($field, $fieldArg, $value); } } else { if($field == 'ID') { @@ -455,23 +455,23 @@ class DataList extends ViewableData implements SS_List, SS_Filterable, SS_Sortab } /** - * Translates the comparisator to the sql query + * Translates a filter type to a SQL query. * * @param string $field - the fieldname in the db - * @param string $comparisators - example StartsWith, relates to a filtercontext + * @param string $filter - a {@link SearchFilter} class, e.g. PartialMatch or StartsWith * @param string $value - the value that the filtercontext will use for matching * @todo Deprecated SearchContexts and pull their functionality into the core of the ORM */ - private function applyFilterContext($field, $comparisators, $value) { + private function applyFilterContext($field, $filter, $value) { $t = singleton($this->dataClass())->dbObject($field); - $className = "{$comparisators}Filter"; - if(!class_exists($className)){ - throw new InvalidArgumentException('There are no '.$comparisators.' comparisator'); + $className = sprintf('%sFilter', $filter); + if(!class_exists($className)) { + throw new InvalidArgumentException(sprintf('Filter class "%s" does not exist', $className)); } - $t = new $className($field,$value); + $t = new $className($field, $value); $t->apply($this->dataQuery()); } - + /** * Return a copy of this list which does not contain any items with these charactaristics * From fbeaa4770aad0db9961177ee937699970d19be1a Mon Sep 17 00:00:00 2001 From: Howard Grigg Date: Fri, 14 Dec 2012 23:13:08 +1300 Subject: [PATCH 03/73] Corrected link in Form field types docs --- docs/en/reference/form-field-types.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/reference/form-field-types.md b/docs/en/reference/form-field-types.md index 0b59da7f9..a38c606d5 100644 --- a/docs/en/reference/form-field-types.md +++ b/docs/en/reference/form-field-types.md @@ -1,6 +1,6 @@ # Form Field Types -This is a highlevel overview of available `[api:apiFormField]` subclasses. An automatically generated list is available through our [API] +This is a highlevel overview of available `[api:FormField]` subclasses. An automatically generated list is available through our [API] ## Basic From b3657147bff395fa4305bbb0b3ba6cfd0d1fffe1 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Sat, 15 Dec 2012 20:02:17 +0100 Subject: [PATCH 04/73] BUG Remove "delete" button from "My Profile" (fixes #8121) --- admin/code/CMSProfileController.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/code/CMSProfileController.php b/admin/code/CMSProfileController.php index 7eb7ee9df..8e69338b8 100644 --- a/admin/code/CMSProfileController.php +++ b/admin/code/CMSProfileController.php @@ -30,7 +30,7 @@ class CMSProfileController extends LeftAndMain { ->setAttribute('data-icon', 'accept') ->setUseButtonTag(true) ); - $form->Actions()->removeByName('delete'); + $form->Actions()->removeByName('action_delete'); $form->setValidator(new Member_Validator()); $form->setTemplate('Form'); $form->setAttribute('data-pjax-fragment', null); From 8455686c367428e1f8b7ee7aed2fba7d0c301a0b Mon Sep 17 00:00:00 2001 From: Mateusz Uzdowski Date: Sun, 16 Dec 2012 14:33:05 +1300 Subject: [PATCH 05/73] BUG Fix the re-layouting not being triggered in IE8. Move onresize handler from entwine to regular event for IE8. The fromWindow::onresize does not trigger otherwise. Refer to http://open.silverstripe.org/ticket/8095 --- admin/javascript/LeftAndMain.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/admin/javascript/LeftAndMain.js b/admin/javascript/LeftAndMain.js index 9d9141b0f..671e8e3cd 100644 --- a/admin/javascript/LeftAndMain.js +++ b/admin/javascript/LeftAndMain.js @@ -5,6 +5,11 @@ jQuery.noConflict(); */ (function($) { + window.onresize = function(e) { + // Entwine's 'fromWindow::onresize' does not trigger on IE8. Use synthetic event. + $('.cms-container').trigger('windowresize'); + } + // setup jquery.entwine $.entwine.warningLevel = $.entwine.WARN_LEVEL_BESTPRACTISE; $.entwine('ss', function($) { @@ -145,7 +150,10 @@ jQuery.noConflict(); fromWindow: { onstatechange: function(){ this.handleStateChange(); }, - onresize: function(){ this.redraw(); } + }, + + 'onwindowresize': function() { + this.redraw(); }, 'from .cms-panel': { From bf5590d8734c8cc35f1b324a393b544caf467673 Mon Sep 17 00:00:00 2001 From: Mateusz Uzdowski Date: Sun, 16 Dec 2012 15:53:22 +1300 Subject: [PATCH 06/73] BUG Fix side-by-side initial icon display issue in IE8. The new 'liszt:ready' handler is called late enough to trigger the update, whereas the redraw is called to early for IE8 to pick up the class change. The class property is changed correcly though, it looks like an IE8 rendering issue. http://open.silverstripe.org/ticket/8095 --- admin/javascript/LeftAndMain.Preview.js | 33 ++++++++++++------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/admin/javascript/LeftAndMain.Preview.js b/admin/javascript/LeftAndMain.Preview.js index d4c01419d..c0ef8e464 100644 --- a/admin/javascript/LeftAndMain.Preview.js +++ b/admin/javascript/LeftAndMain.Preview.js @@ -424,6 +424,7 @@ * Reacts to the user changing the preview mode. */ onchange: function(e) { + this._super(e); e.preventDefault(); var targetStateName = $(this).val(); @@ -523,38 +524,36 @@ 'onliszt:showing_dropdown': function() { this.siblings().find('.chzn-drop').addClass('open')._alignRight(); }, + 'onliszt:hiding_dropdown': function() { this.siblings().find('.chzn-drop').removeClass('open')._removeRightAlign(); - }, + }, + + /** + * Trigger additional initial icon update when the control is fully loaded. + * Solves an IE8 timing issue. + */ + 'onliszt:ready': function() { + this._super(); + this._addIcon(); + }, + _addIcon: function(){ var selected = this.find(':selected'); var iconClass = selected.attr('data-icon'); var target = this.parent().find('.chzn-container a.chzn-single'); var oldIcon = target.attr('data-icon'); - if(oldIcon != undefined){ + if(typeof oldIcon !== 'undefined'){ target.removeClass(oldIcon); } target.addClass(iconClass); target.attr('data-icon', iconClass); + + return this; } }); - /* - * When chzn initiated run select addIcon - * Apply description text if applicable - */ - $('.preview-selector a.chzn-single').entwine({ - onmatch: function() { - this.closest('.preview-selector').find('select')._addIcon(); - this._super(); - }, - onunmatch: function() { - this._super(); - } - }); - - $('.preview-selector .chzn-drop').entwine({ _alignRight: function(){ var that = this; From 22eeaa4ac10622f616063af9fb76c240aa037d79 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Sat, 15 Dec 2012 20:23:50 +0100 Subject: [PATCH 07/73] BUG Members should not be allowed to delete themselves (fixes #8121) --- security/Member.php | 8 ++++++-- tests/security/MemberTest.php | 30 +++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/security/Member.php b/security/Member.php index 964b329c8..9a5bf8d96 100644 --- a/security/Member.php +++ b/security/Member.php @@ -1294,16 +1294,20 @@ class Member extends DataObject implements TemplateGlobalProvider { */ public function canDelete($member = null) { if(!$member || !(is_a($member, 'Member')) || is_numeric($member)) $member = Member::currentUser(); - + // extended access checks $results = $this->extend('canDelete', $member); if($results && is_array($results)) { if(!min($results)) return false; else return true; } - + // No member found if(!($member && $member->exists())) return false; + + // Members are not allowed to remove themselves, + // since it would create inconsistencies in the admin UIs. + if($this->ID && $member->ID == $this->ID) return false; return $this->canEdit($member); } diff --git a/tests/security/MemberTest.php b/tests/security/MemberTest.php index 099c8dcfb..c61f77cc7 100644 --- a/tests/security/MemberTest.php +++ b/tests/security/MemberTest.php @@ -432,7 +432,7 @@ class MemberTest extends FunctionalTest { /* Logged in users can edit their own record */ $this->session()->inst_set('loggedInAs', $member->ID); $this->assertTrue($member->canView()); - $this->assertTrue($member->canDelete()); + $this->assertFalse($member->canDelete()); $this->assertTrue($member->canEdit()); /* Other uses cannot view, delete or edit others records */ @@ -653,6 +653,34 @@ class MemberTest extends FunctionalTest { $this->assertFalse($m2->validateAutoLoginToken($m1Token), 'Fails token validity test against other member.'); } + public function testCanDelete() { + $admin1 = $this->objFromFixture('Member', 'admin'); + $admin2 = $this->objFromFixture('Member', 'other-admin'); + $member1 = $this->objFromFixture('Member', 'grouplessmember'); + $member2 = $this->objFromFixture('Member', 'noformatmember'); + + $this->assertTrue( + $admin1->canDelete($admin2), + 'Admins can delete other admins' + ); + $this->assertTrue( + $member1->canDelete($admin2), + 'Admins can delete non-admins' + ); + $this->assertFalse( + $admin1->canDelete($admin1), + 'Admins can not delete themselves' + ); + $this->assertFalse( + $member1->canDelete($member2), + 'Non-admins can not delete other non-admins' + ); + $this->assertFalse( + $member1->canDelete($member1), + 'Non-admins can not delete themselves' + ); + } + } class MemberTest_ViewingAllowedExtension extends DataExtension implements TestOnly { From 1848d7e90abad4b4b969fa87922a58c97a1026de Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Mon, 17 Dec 2012 00:46:51 +0100 Subject: [PATCH 08/73] API Check model permissions in GridField --- docs/en/changelogs/3.1.0.md | 33 +++++++++++++++ docs/en/reference/grid-field.md | 10 +++++ forms/gridfield/GridFieldAddNewButton.php | 6 ++- forms/gridfield/GridFieldDeleteAction.php | 22 ++++++---- forms/gridfield/GridFieldDetailForm.php | 41 +++++++++++++++---- .../gridfield/GridFieldDetailFormTest.php | 4 ++ 6 files changed, 101 insertions(+), 15 deletions(-) diff --git a/docs/en/changelogs/3.1.0.md b/docs/en/changelogs/3.1.0.md index a880275c9..22367db46 100644 --- a/docs/en/changelogs/3.1.0.md +++ b/docs/en/changelogs/3.1.0.md @@ -44,6 +44,39 @@ you'll need to adjust your code. } } +### GridField and ModelAdmin Permission Checks + +`GridFieldDetailForm` now checks for `canEdit()` and `canDelete()` permissions +on your model. `GridFieldAddNewButton` checks `canCreate()`. +The default implementation requires `ADMIN` permissions. +You'll need to loosen those permissions if you want other users with CMS +access to interact with your data. +Since `GridField` is used in `ModelAdmin`, this change will affect both classes. + + Example: Require "CMS: Pages section" access + + :::php + class MyModel extends DataObject { + public function canView($member = null) { + return Permission::check('CMS_ACCESS_CMSMain', 'any', $member); + } + public function canEdit($member = null) { + return Permission::check('CMS_ACCESS_CMSMain', 'any', $member); + } + public function canDelete($member = null) { + return Permission::check('CMS_ACCESS_CMSMain', 'any', $member); + } + public function canCreate($member = null) { + return Permission::check('CMS_ACCESS_CMSMain', 'any', $member); + } + +You can also implement [custom permission codes](/topics/permissions). +For 3.1.0 stable, we aim to further simplify the permission definitions, +in order to reduce the boilerplate code required to get a model editable in the CMS. + +Note: GridField is already relying on the permission checks performed +through the CMS controllers, providing a simple level of security. + ### Other * `TableListField`, `ComplexTableField`, `TableField`, `HasOneComplexTableField`, `HasManyComplexTableField` and `ManyManyComplexTableField` have been removed from the core and placed into a module called "legacytablefields" located at https://github.com/silverstripe-labs/legacytablefields diff --git a/docs/en/reference/grid-field.md b/docs/en/reference/grid-field.md index dfe52bf06..79d0083d4 100644 --- a/docs/en/reference/grid-field.md +++ b/docs/en/reference/grid-field.md @@ -310,6 +310,16 @@ transfered between page requests by being inserted as a hidden field in the form A GridFieldComponent sets and gets data from the GridState. +## Permissions + +Since GridField is mostly used in the CMS, the controller managing a GridField instance +will already do some permission checks for you, and can decline display or executing +any logic on your field. + +If you need more granular control, e.g. to consistently deny non-admins from deleting +records, use the `DataObject->can...()` methods +(see [DataObject permissions](/reference/dataobject#permissions)). + ## Related * [ModelAdmin: A UI driven by GridField](/reference/modeladmin) diff --git a/forms/gridfield/GridFieldAddNewButton.php b/forms/gridfield/GridFieldAddNewButton.php index 2c1e0bf87..ba3089490 100644 --- a/forms/gridfield/GridFieldAddNewButton.php +++ b/forms/gridfield/GridFieldAddNewButton.php @@ -1,6 +1,7 @@ canCreate()} for this record returns true. * * @package framework * @subpackage gridfield @@ -21,9 +22,12 @@ class GridFieldAddNewButton implements GridField_HTMLProvider { } public function getHTMLFragments($gridField) { + $singleton = singleton($gridField->getModelClass()); + if(!$singleton->canCreate()) return array(); + if(!$this->buttonName) { // provide a default button name, can be changed by calling {@link setButtonName()} on this component - $objectName = singleton($gridField->getModelClass())->i18n_singular_name(); + $objectName = $singleton->i18n_singular_name(); $this->buttonName = _t('GridField.Add', 'Add {name}', array('name' => $objectName)); } diff --git a/forms/gridfield/GridFieldDeleteAction.php b/forms/gridfield/GridFieldDeleteAction.php index 16c24a10b..9c2aeb83b 100644 --- a/forms/gridfield/GridFieldDeleteAction.php +++ b/forms/gridfield/GridFieldDeleteAction.php @@ -98,15 +98,16 @@ class GridFieldDeleteAction implements GridField_ColumnProvider, GridField_Actio */ public function getColumnContent($gridField, $record, $columnName) { if($this->removeRelation) { + if(!$record->canEdit()) return; + $field = GridField_FormAction::create($gridField, 'UnlinkRelation'.$record->ID, false, "unlinkrelation", array('RecordID' => $record->ID)) ->addExtraClass('gridfield-button-unlink') ->setAttribute('title', _t('GridAction.UnlinkRelation', "Unlink")) ->setAttribute('data-icon', 'chain--minus'); } else { - if(!$record->canDelete()) { - return; - } + if(!$record->canDelete()) return; + $field = GridField_FormAction::create($gridField, 'DeleteRecord'.$record->ID, false, "deleterecord", array('RecordID' => $record->ID)) ->addExtraClass('gridfield-button-delete') @@ -132,13 +133,20 @@ class GridFieldDeleteAction implements GridField_ColumnProvider, GridField_Actio if(!$item) { return; } - if($actionName == 'deleterecord' && !$item->canDelete()) { - throw new ValidationException( - _t('GridFieldAction_Delete.DeletePermissionsFailure',"No delete permissions"),0); - } + if($actionName == 'deleterecord') { + if(!$item->canDelete()) { + throw new ValidationException( + _t('GridFieldAction_Delete.DeletePermissionsFailure',"No delete permissions"),0); + } + $item->delete(); } else { + if(!$item->canEdit()) { + throw new ValidationException( + _t('GridFieldAction_Delete.EditPermissionsFailure',"No permission to unlink record"),0); + } + $gridField->getList()->remove($item); } } diff --git a/forms/gridfield/GridFieldDetailForm.php b/forms/gridfield/GridFieldDetailForm.php index 23818c217..44c1bd738 100644 --- a/forms/gridfield/GridFieldDetailForm.php +++ b/forms/gridfield/GridFieldDetailForm.php @@ -310,16 +310,31 @@ class GridFieldDetailForm_ItemRequest extends RequestHandler { return $controller->redirect($noActionURL, 302); } + $canView = $this->record->canView(); + $canEdit = $this->record->canEdit(); + $canDelete = $this->record->canDelete(); + $canCreate = $this->record->canCreate(); + + if(!$canView) { + $controller = Controller::curr(); + // TODO More friendly error + return $controller->httpError(403); + } + $actions = new FieldList(); if($this->record->ID !== 0) { - $actions->push(FormAction::create('doSave', _t('GridFieldDetailForm.Save', 'Save')) - ->setUseButtonTag(true) - ->addExtraClass('ss-ui-action-constructive') - ->setAttribute('data-icon', 'accept')); + if($canEdit) { + $actions->push(FormAction::create('doSave', _t('GridFieldDetailForm.Save', 'Save')) + ->setUseButtonTag(true) + ->addExtraClass('ss-ui-action-constructive') + ->setAttribute('data-icon', 'accept')); + } - $actions->push(FormAction::create('doDelete', _t('GridFieldDetailForm.Delete', 'Delete')) - ->setUseButtonTag(true) - ->addExtraClass('ss-ui-action-destructive')); + if($canDelete) { + $actions->push(FormAction::create('doDelete', _t('GridFieldDetailForm.Delete', 'Delete')) + ->setUseButtonTag(true) + ->addExtraClass('ss-ui-action-destructive')); + } }else{ // adding new record //Change the Save label to 'Create' @@ -353,6 +368,14 @@ class GridFieldDetailForm_ItemRequest extends RequestHandler { $form->loadDataFrom($this->record, $this->record->ID == 0 ? Form::MERGE_IGNORE_FALSEISH : Form::MERGE_DEFAULT); + if($this->record->ID && !$canEdit) { + // Restrict editing of existing records + $form->makeReadonly(); + } elseif(!$this->record->ID && !$canCreate) { + // Restrict creation of new records + $form->makeReadonly(); + } + // Load many_many extraData for record. // Fields with the correct 'ManyMany' namespace need to be added manually through getCMSFields(). if($list instanceof ManyManyList) { @@ -429,6 +452,10 @@ class GridFieldDetailForm_ItemRequest extends RequestHandler { $extraData = null; } + if(!$this->record->canEdit()) { + return $controller->httpError(403); + } + try { $form->saveInto($this->record); $this->record->write(); diff --git a/tests/forms/gridfield/GridFieldDetailFormTest.php b/tests/forms/gridfield/GridFieldDetailFormTest.php index c883aefd3..6c50b2e5c 100644 --- a/tests/forms/gridfield/GridFieldDetailFormTest.php +++ b/tests/forms/gridfield/GridFieldDetailFormTest.php @@ -192,6 +192,8 @@ class GridFieldDetailFormTest extends FunctionalTest { } public function testCustomItemRequestClass() { + $this->logInWithPermission('ADMIN'); + $component = new GridFieldDetailForm(); $this->assertEquals('GridFieldDetailForm_ItemRequest', $component->getItemRequestClass()); $component->setItemRequestClass('GridFieldDetailFormTest_ItemRequest'); @@ -199,6 +201,8 @@ class GridFieldDetailFormTest extends FunctionalTest { } public function testItemEditFormCallback() { + $this->logInWithPermission('ADMIN'); + $category = new GridFieldDetailFormTest_Category(); $component = new GridFieldDetailForm(); $component->setItemEditFormCallback(function($form, $component) { From bbc8e06d49fda5b87ccc780b57d8f9722e7c0393 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Mon, 17 Dec 2012 00:47:23 +0100 Subject: [PATCH 09/73] API Show GridFieldEditButton even without edit permissions (for readonly forms) --- forms/gridfield/GridFieldEditButton.php | 6 +++--- tests/forms/gridfield/GridFieldEditButtonTest.php | 9 +++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/forms/gridfield/GridFieldEditButton.php b/forms/gridfield/GridFieldEditButton.php index 1c6836ed6..d2801d535 100644 --- a/forms/gridfield/GridFieldEditButton.php +++ b/forms/gridfield/GridFieldEditButton.php @@ -72,9 +72,9 @@ class GridFieldEditButton implements GridField_ColumnProvider { * @return string - the HTML for the column */ public function getColumnContent($gridField, $record, $columnName) { - if(!$record->canEdit()){ - return; - } + // No permission checks, handled through GridFieldDetailForm, + // which can make the form readonly if no edit permissions are available. + $data = new ArrayData(array( 'Link' => Controller::join_links($gridField->Link('item'), $record->ID, 'edit') )); diff --git a/tests/forms/gridfield/GridFieldEditButtonTest.php b/tests/forms/gridfield/GridFieldEditButtonTest.php index ee04dc0ce..69235eee0 100644 --- a/tests/forms/gridfield/GridFieldEditButtonTest.php +++ b/tests/forms/gridfield/GridFieldEditButtonTest.php @@ -25,15 +25,16 @@ class GridFieldEditButtonTest extends SapphireTest { $this->form = new Form(new Controller(), 'mockform', new FieldList(array($this->gridField)), new FieldList()); } - public function testDontShowEditLinks() { + public function testShowEditLinks() { if(Member::currentUser()) { Member::currentUser()->logOut(); } $content = new CSSContentParser($this->gridField->FieldHolder()); // Check that there are content $this->assertEquals(3, count($content->getBySelector('.ss-gridfield-item'))); - // Make sure that there are no edit links - $this->assertEquals(0, count($content->getBySelector('.edit-link')), - 'Edit links should not show when not logged in.'); + // Make sure that there are edit links, even though the user doesn't have "edit" permissions + // (he can still view the records) + $this->assertEquals(2, count($content->getBySelector('.edit-link')), + 'Edit links should show when not logged in.'); } public function testShowEditLinksWithAdminPermission() { From 3da41efa70af845410554f305bb78fd67e9bb889 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Mon, 17 Dec 2012 00:47:30 +0100 Subject: [PATCH 10/73] Permission docs --- docs/en/reference/dataobject.md | 35 +++++++++++++++++++++++++++++++++ docs/en/reference/modeladmin.md | 28 ++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/docs/en/reference/dataobject.md b/docs/en/reference/dataobject.md index 5aea366f3..b9602d308 100644 --- a/docs/en/reference/dataobject.md +++ b/docs/en/reference/dataobject.md @@ -192,6 +192,41 @@ To include relations in your summaries, you can use a dot-notation. ); } +## Permissions + +Models can be modified in a variety of controllers and user interfaces, +all of which can implement their own security checks. But often it makes +sense to centralize those checks on the model, regardless of the used controller. + +The API provides four methods for this purpose: +`canEdit()`, `canCreate()`, `canView()` and `canDelete()`. +Since they're PHP methods, they can contain arbitrary logic +matching your own requirements. They can optionally receive a `$member` argument, +and default to the currently logged in member (through `Member::currentUser()`). + +Example: Check for CMS access permissions + + class MyDataObject extends DataObject { + // ... + public function canView($member = null) { + return Permission::check('CMS_ACCESS_CMSMain', 'any', $member); + } + public function canEdit($member = null) { + return Permission::check('CMS_ACCESS_CMSMain', 'any', $member); + } + public function canDelete($member = null) { + return Permission::check('CMS_ACCESS_CMSMain', 'any', $member); + } + public function canCreate($member = null) { + return Permission::check('CMS_ACCESS_CMSMain', 'any', $member); + } + } + +**Important**: These checks are not enforced on low-level ORM operations +such as `write()` or `delete()`, but rather rely on being checked in the invoking code. +The CMS default sections as well as custom interfaces like +`[ModelAdmin](/reference/modeladmin)` or `[GridField](/reference/gridfield)` +already enforce these permissions. ## API Documentation diff --git a/docs/en/reference/modeladmin.md b/docs/en/reference/modeladmin.md index 5531e0477..5e122b854 100644 --- a/docs/en/reference/modeladmin.md +++ b/docs/en/reference/modeladmin.md @@ -44,6 +44,34 @@ We'll name it `MyAdmin`, but the class name can be anything you want. This will automatically add a new menu entry to the CMS, and you're ready to go! Try opening http://localhost/admin/products/?flush=all. +## Permissions + +Each new `ModelAdmin` subclass creates its own [permission code](/reference/permission), +for the example above this would be `CMS_ACCESS_MyAdmin`. Users with access to the CMS +need to have this permission assigned through `admin/security/` in order to gain +access to the controller (unless they're admins). + +The `DataObject` API has more granular permission control, which is enforced in ModelAdmin by default. +Available checks are `canEdit()`, `canCreate()`, `canView()` and `canDelete()`. +Models check for administrator permissions by default. For most cases, +less restrictive checks make sense, e.g. checking for general CMS access rights. + + :::php + class Category extends DataObject { + // ... + public function canView($member = null) { + return Permission::check('CMS_ACCESS_CMSMain', 'any', $member); + } + public function canEdit($member = null) { + return Permission::check('CMS_ACCESS_CMSMain', 'any', $member); + } + public function canDelete($member = null) { + return Permission::check('CMS_ACCESS_CMSMain', 'any', $member); + } + public function canCreate($member = null) { + return Permission::check('CMS_ACCESS_CMSMain', 'any', $member); + } + ## Search Fields ModelAdmin uses the `[SearchContext](/reference/searchcontext)` class to provide From 75b0c3ec8fd091518b1a860c6c168fe755546a48 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Mon, 17 Dec 2012 00:36:23 +0100 Subject: [PATCH 11/73] Added 3.1.0-beta1 changelog --- docs/en/changelogs/3.1.0.md | 22 ++ docs/en/changelogs/beta/3.1.0-beta1.md | 333 +++++++++++++++++++++++++ 2 files changed, 355 insertions(+) create mode 100644 docs/en/changelogs/beta/3.1.0-beta1.md diff --git a/docs/en/changelogs/3.1.0.md b/docs/en/changelogs/3.1.0.md index 22367db46..09b76fd9b 100644 --- a/docs/en/changelogs/3.1.0.md +++ b/docs/en/changelogs/3.1.0.md @@ -2,6 +2,28 @@ ## Overview ## +### CMS + + * "Split view" editing with side-by-side preview of the edited website + * Resizing of preview to common screen widths ("desktop", "tablet" and "smartphone") + * Decluttered "Edit Page" buttons by moving minor actions into a "more options" panel + * Auto-detect CMS changes and highlight the save button for better informancy + * Display "last edited" and "last published" data for pages in CMS + * CMS form fields now support help text through `setDescription()`, both inline and as tooltips + * Removed SiteTree "MetaTitle" and "MetaKeywords" fields + * More legible and simplified tab and menu styling in the CMS + +### Framework + + * `DataList` and `ArrayList` are now immutable, they'll return cloned instances on modification + * Behaviour testing support through [Behat](http://behat.org), with CMS test coverage + (see the [SilverStripe Behat Extension]() for details) + * Removed legacy table APIs (e.g. `TableListField`), use GridField instead + * Editing of relation table data (`$many_many_extraFields`) in `GridField` + * Optional integration with ImageMagick as a new image manipulation backend + * Support for PHP 5.4's built-in webserver + * Support for [Composer](http://getcomposer.org) dependency manager (also works with 3.0) + ## Upgrading ### Grouped CMS Buttons diff --git a/docs/en/changelogs/beta/3.1.0-beta1.md b/docs/en/changelogs/beta/3.1.0-beta1.md new file mode 100644 index 000000000..29ca133b3 --- /dev/null +++ b/docs/en/changelogs/beta/3.1.0-beta1.md @@ -0,0 +1,333 @@ +# 3.1.0-beta1 (unreleased) # + +## Overview ## + +### CMS + + * "Split view" editing with side-by-side preview of the edited website + * Resizing of preview to common screen widths ("desktop", "tablet" and "smartphone") + * Decluttered "Edit Page" buttons by moving minor actions into a "more options" panel + * Auto-detect CMS changes and highlight the save button for better informancy + * Display "last edited" and "last published" data for pages in CMS + * CMS form fields now support help text through `setDescription()`, both inline and as tooltips + * More legible and simplified tab and menu styling in the CMS + +### Framework + + * `DataList` and `ArrayList` are now immutable, they'll return cloned instances on modification + * Behaviour testing support through [Behat](http://behat.org), with CMS test coverage + (see the [SilverStripe Behat Extension]() for details) + * Removed legacy table APIs (e.g. `TableListField`), use GridField instead + * Editing of relation table data (`$many_many_extraFields`) in `GridField` + * Optional integration with ImageMagick as a new image manipulation backend + * Support for PHP 5.4's built-in webserver + +## Upgrading + +See [3.1.0 release notes](/changelogs/3.1.0) + +## Changelog + +### API Changes + + * 2012-12-14 [644cc79](https://github.com/silverstripe/sapphire/commit/644cc79) Removed methods previously deprecated in 3.0 (Ingo Schommer) + * 2012-12-13 [6f9d01f](https://github.com/silverstripe/sapphire/commit/6f9d01f) FormField->setDescription() visible in default template (Ingo Schommer) + * 2012-12-13 [559abec](https://github.com/silverstripe/sapphire/commit/559abec) Copying instance props on FormField readonly/disabled transformations (Ingo Schommer) + * 2012-12-13 [2e164ea](https://github.com/silverstripe/silverstripe-cms/commit/2e164ea) Report::get_reports() returns native array (fixes #8096) (Ingo Schommer) + * 2012-12-12 [27113f8](https://github.com/silverstripe/sapphire/commit/27113f8) Make DataList and ArrayList immutable (Hamish Friedlander) + * 2012-12-10 [e6e47cb](https://github.com/silverstripe/sapphire/commit/e6e47cb) DB-specific comparisators in SearchFilter and DataList (Ingo Schommer) + * 2012-12-11 [4d6d823](https://github.com/silverstripe/sapphire/commit/4d6d823) Allow ignoring persistent tab state through entwine property. (Mateusz Uzdowski) + * 2012-12-10 [efa9ff9](https://github.com/silverstripe/sapphire/commit/efa9ff9) Queries added by DataList::addInnerJoin() and DataList::leftJoin() come after the base joins, not before. (stojg) + * 2012-12-06 [c6b1d4a](https://github.com/silverstripe/sapphire/commit/c6b1d4a) Storing alternative DB name in cookie rather than session (Ingo Schommer) + * 2012-12-04 [4fa2b0f](https://github.com/silverstripe/sapphire/commit/4fa2b0f) Support disabling/enabling of previews. (Mateusz Uzdowski) + * 2012-12-03 [5fed5b9](https://github.com/silverstripe/sapphire/commit/5fed5b9) Moved email bounce handling to new 'emailbouncehandler' module (Ingo Schommer) + * 2012-12-03 [fb076c0](https://github.com/silverstripe/sapphire/commit/fb076c0) Deprecated global email methods, moved to Mailer class (Ingo Schommer) + * 2012-11-30 [548ad50](https://github.com/silverstripe/sapphire/commit/548ad50) Removed keyed arrays for title/value setting in SelectionGroup (Ingo Schommer) + * 2012-11-29 [8f5acd7](https://github.com/silverstripe/sapphire/commit/8f5acd7) Move state to enwtine properties, provide API for preview. (Mateusz Uzdowski) + * 2012-11-29 [47f41d8](https://github.com/silverstripe/silverstripe-cms/commit/47f41d8) Machine-friendly name for CMS states navigator (stages). (Mateusz Uzdowski) + * 2012-11-26 [d4f13fe](https://github.com/silverstripe/sapphire/commit/d4f13fe) Refactor the CMS layouting to provide access to options. (Mateusz Uzdowski) + * 2012-11-22 [fe08236](https://github.com/silverstripe/sapphire/commit/fe08236) Add action tabsets as a interface idiom. (Mateusz Uzdowski) + * 2012-11-22 [26cc14a](https://github.com/silverstripe/silverstripe-cms/commit/26cc14a) Rework the CMS actions to use alternating buttons and drop-ups. (Mateusz Uzdowski) + * 2012-11-15 [8b0bb8d](https://github.com/silverstripe/sapphire/commit/8b0bb8d) Replace deprecated FormField::createTag() with static create_tag() (Sean Harvey) + * 2012-11-07 [b02b1e6](https://github.com/silverstripe/sapphire/commit/b02b1e6) Forward the editor events to underlying textarea. (Mateusz Uzdowski) + * 2012-11-02 [683db8d](https://github.com/silverstripe/sapphire/commit/683db8d) Explicitly load project template files after modules (Will Rossiter) + * 2012-10-30 [d54b1b4](https://github.com/silverstripe/sapphire/commit/d54b1b4) Removed permission checks from XML/JSON data formatters (Ingo Schommer) + * 2012-10-12 [a3295e2](https://github.com/silverstripe/sapphire/commit/a3295e2) File->canEdit() returns TRUE by default (not checking CMS perms) (Ingo Schommer) + * 2012-10-10 [b31188f](https://github.com/silverstripe/silverstripe-cms/commit/b31188f) Use late static binding for Object::has_extension() (Andrew O'Neil) + * 2012-10-10 [0c8de0a](https://github.com/silverstripe/sapphire/commit/0c8de0a) Use late static binding for Object::has_extension() (Andrew O'Neil) + * 2012-10-10 [48a9bcf](https://github.com/silverstripe/silverstripe-cms/commit/48a9bcf) Use late static binding for Object::remove_extension() (Andrew O'Neil) + * 2012-10-10 [6dd6a5c](https://github.com/silverstripe/sapphire/commit/6dd6a5c) Use late static binding for Object::remove_extension() (Andrew O'Neil) + * 2012-10-09 [1722f00](https://github.com/silverstripe/silverstripe-cms/commit/1722f00) add_extension() is now called directly on the class, instead of on Object (Andrew O'Neil) + * 2012-10-09 [fdea532](https://github.com/silverstripe/sapphire/commit/fdea532) add_extension() is now called directly on the class, instead of on Object (Andrew O'Neil) + * 2012-09-27 [39952f4](https://github.com/silverstripe/sapphire/commit/39952f4) Added 'onBeforeHTTPError' and 'onBeforeHTTPError<code>' extension points to RequestHandler::httpError(). (Sam Minnee) + * 2012-09-26 [aa6f345](https://github.com/silverstripe/sapphire/commit/aa6f345) FormField::name_to_label() for unlabelled fields (Howard Grigg) + * 2012-09-21 [cbd31e3](https://github.com/silverstripe/silverstripe-cms/commit/cbd31e3) Removed SiteTree.MetaTitle and MetaKeywords (Ingo Schommer) + * 2012-09-21 [a3007b6](https://github.com/silverstripe/silverstripe-cms/commit/a3007b6) moved StaticCache / StaticPublisher to module. (Will Rossiter) + * 2012-09-21 [e72114d](https://github.com/silverstripe/sapphire/commit/e72114d) Remove static main and dev/buildcache (Will Rossiter) + * 2012-09-20 [6d696d5](https://github.com/silverstripe/sapphire/commit/6d696d5) Allow subgroups in the WHERE clause of a Data/SQLQuery (Simon Welsh) + * 2012-09-20 [c49f756](https://github.com/silverstripe/sapphire/commit/c49f756) Allow use of :not, :nocase and :case modifiers to SearchFilters. (Simon Welsh) + * 2012-09-06 [79b3f8a](https://github.com/silverstripe/sapphire/commit/79b3f8a) Add exclude() method to SearchFilters that excludes items that match the filter. (Simon Welsh) + * 2012-09-06 [2faf7d1](https://github.com/silverstripe/sapphire/commit/2faf7d1) Allow using SearchFilters in DataList::exclude() (Simon Welsh) + * 2012-07-05 [0fe515e](https://github.com/silverstripe/sapphire/commit/0fe515e) Deprecated Profiler class, removed related debug GET params (Ingo Schommer) + * 2012-06-30 [78fdcc5](https://github.com/silverstripe/sapphire/commit/78fdcc5) DataList->leftJoin()/innerJoin() args no longer escaped (Simon Welsh) + +### Features and Enhancements + + * 2012-12-13 [7e46290](https://github.com/silverstripe/sapphire/commit/7e46290) Date->Ago() with "less than a minute" support (Ingo Schommer) + * 2012-12-13 [1ca3883](https://github.com/silverstripe/sapphire/commit/1ca3883) Tooltip and inline help text support for CMS form fields (Ingo Schommer) + * 2012-11-22 [f4b080e](https://github.com/silverstripe/sapphire/commit/f4b080e) Side by side editing functionality - first cut (os#7412) (Mateusz Uzdowski) + * 2012-11-15 [639f6e4](https://github.com/silverstripe/silverstripe-cms/commit/639f6e4) Side by side editing functionality - first cut (os#7412) (Naomi Guyer) + * 2012-11-08 [c8136f5](https://github.com/silverstripe/sapphire/commit/c8136f5) Many-many relation data editing in GridFieldDetailForm (Ingo Schommer) + * 2012-11-06 [a52514a](https://github.com/silverstripe/silverstripe-cms/commit/a52514a) Tab style consolidation and design consistency (Ingo Schommer) + * 2012-11-06 [2d07567](https://github.com/silverstripe/sapphire/commit/2d07567) Tab style consolidation and design consistency (Ingo Schommer) + * 2012-11-06 [dbbcd08](https://github.com/silverstripe/sapphire/commit/dbbcd08) Extend the ssui.button with alternate appearances. (Mateusz Uzdowski) + * 2012-11-05 [411673e](https://github.com/silverstripe/sapphire/commit/411673e) general css enhancements (Paul Clarke) + * 2012-11-03 [bbc4443](https://github.com/silverstripe/sapphire/commit/bbc4443) Allows setting of has_many and many_many relations before writing (Simon Welsh) + * 2012-11-02 [26e5afc](https://github.com/silverstripe/sapphire/commit/26e5afc) Add new method "each" to SS_List and core implementors thereof (Justin Martin) + * 2012-10-24 [d24b586](https://github.com/silverstripe/sapphire/commit/d24b586) Enable multiple image manipulation back-ends on the Image class (Justin Martin) + * 2012-10-12 [5be3a4c](https://github.com/silverstripe/sapphire/commit/5be3a4c) DataList->filterAny() (Ingo Schommer) + * 2012-10-08 [1711303](https://github.com/silverstripe/silverstripe-cms/commit/1711303) Enable SiteTree::$nested_urls by default (Ingo Schommer) + * 2012-10-08 [38e7df2](https://github.com/silverstripe/sapphire/commit/38e7df2) Enable SiteTree::$nested_urls by default (Ingo Schommer) + * 2012-10-05 [76e569a](https://github.com/silverstripe/silverstripe-cms/commit/76e569a) open/7886 added preview button to the settings page so that when a user changes the theme they can preview the change. (Jeremy Bridson) + * 2012-10-05 [ad7383a](https://github.com/silverstripe/sapphire/commit/ad7383a) open/7886 added preview button to the settings page so that when a user changes the theme they can preview the change. (Jeremy Bridson) + * 2012-10-04 [8108f7f](https://github.com/silverstripe/sapphire/commit/8108f7f) Relation search for GridFieldAddExistingAutocompleter (Ingo Schommer) + * 2012-09-20 [a670e4c](https://github.com/silverstripe/sapphire/commit/a670e4c) open/7875 - added help labels to metadata fields on page content edit screen. (Jeremy Bridson) + * 2012-09-20 [05d5bd7](https://github.com/silverstripe/silverstripe-cms/commit/05d5bd7) open/7875 - added help labels to metadata fields on page content edit screen. (Jeremy Bridson) + * 2012-09-11 [1005571](https://github.com/silverstripe/sapphire/commit/1005571) Added support for PHP 5.4's built-in webserver. (Sam Minnee) + * 2012-07-23 [f1db583](https://github.com/silverstripe/sapphire/commit/f1db583) Allow arguments to be passed to allowed_action checkers (Simon Welsh) + * 2012-07-15 [6e2d6c2](https://github.com/silverstripe/sapphire/commit/6e2d6c2) Hide the search bar in Chosen dropdown fields when list is reasonably short. (unclecheese) + * 2012-06-29 [ebb2458](https://github.com/silverstripe/sapphire/commit/ebb2458) Improving Cookie class to allow for extendability (Matt Lewis) + +### Bugfixes + + * 2012-12-16 [bf5590d](https://github.com/silverstripe/sapphire/commit/bf5590d) Fix side-by-side initial icon display issue in IE8. (Mateusz Uzdowski) + * 2012-12-16 [8455686](https://github.com/silverstripe/sapphire/commit/8455686) Fix the re-layouting not being triggered in IE8. (Mateusz Uzdowski) + * 2012-12-15 [b365714](https://github.com/silverstripe/sapphire/commit/b365714) Remove "delete" button from "My Profile" (fixes #8121) (Ingo Schommer) + * 2012-12-15 [c2d31e5](https://github.com/silverstripe/silverstripe-cms/commit/c2d31e5) Hiding group selections in "Settings" (Ingo Schommer) + * 2012-12-14 [d2c1d53](https://github.com/silverstripe/sapphire/commit/d2c1d53) ed UploadField->setDescription() handlgin (Ingo Schommer) + * 2012-12-14 [74d6379](https://github.com/silverstripe/silverstripe-cms/commit/74d6379) ed regression in SiteTree->getCMSActions() (Ingo Schommer) + * 2012-12-14 [f41f307](https://github.com/silverstripe/sapphire/commit/f41f307) ed spacing (Ingo Schommer) + * 2012-12-13 [a355e1d](https://github.com/silverstripe/sapphire/commit/a355e1d) Set visibility on login form methods to public. (Justin Martin) + * 2012-12-13 [d42c004](https://github.com/silverstripe/silverstripe-cms/commit/d42c004) Fixed pagination functionality on root assets folder (Niklas Forsdahl) + * 2012-12-13 [006790b](https://github.com/silverstripe/sapphire/commit/006790b) ed IE7 GridField "add row" alignment issue (Ingo Schommer) + * 2012-12-13 [0ba51c1](https://github.com/silverstripe/sapphire/commit/0ba51c1) to allow buttons to align inline (fixes #8099) (Paul Clarke) + * 2012-12-13 [bdc3e91](https://github.com/silverstripe/sapphire/commit/bdc3e91) ed wrong floating on GridField certain buttons (Ingo Schommer) + * 2012-12-13 [bd59f84](https://github.com/silverstripe/sapphire/commit/bd59f84) Make sure you can only remove items from a DataList that are actually in it (Hamish Friedlander) + * 2012-12-13 [9979b11](https://github.com/silverstripe/sapphire/commit/9979b11) Make sure ArrayList#limit uses clone so for subclasses it returns instances of same subclass (Hamish Friedlander) + * 2012-12-12 [639cc02](https://github.com/silverstripe/sapphire/commit/639cc02) Fix insert media form inserting images from other UploadFields (fixes #8051) (Loz Calver) + * 2012-12-12 [546762e](https://github.com/silverstripe/silverstripe-cms/commit/546762e) use of DataList#innerJoin expecting it to be mutable (Hamish Friedlander) + * 2012-12-12 [c0a1226](https://github.com/silverstripe/sapphire/commit/c0a1226) fix and code clean up (Paul Clarke) + * 2012-12-12 [5d93f8d](https://github.com/silverstripe/sapphire/commit/5d93f8d) fix preview note "Website preview" (Paul Clarke) + * 2012-12-11 [0f60ca7](https://github.com/silverstripe/sapphire/commit/0f60ca7) Confirmed Password Field now copies attributes to child fields. (Justin Martin) + * 2012-12-11 [9803459](https://github.com/silverstripe/sapphire/commit/9803459) ed SelectionGroupTest (Ingo Schommer) + * 2012-12-10 [084acc0](https://github.com/silverstripe/silverstripe-cms/commit/084acc0) ed Behat tests for preview feature (Ingo Schommer) + * 2012-12-10 [0fd6d14](https://github.com/silverstripe/sapphire/commit/0fd6d14) ed Behat steps for preview feature (Ingo Schommer) + * 2012-12-07 [4f63f91](https://github.com/silverstripe/sapphire/commit/4f63f91) Fixed issue with convertServiceProperty (Marcus Nyeholt) + * 2012-12-04 [4d106aa](https://github.com/silverstripe/sapphire/commit/4d106aa) Fixed unintentional ParentID reset in "add page" form (Ingo Schommer) + * 2012-12-04 [b8c656b](https://github.com/silverstripe/sapphire/commit/b8c656b) ed cms extension docs to remove zzz_admin workaround (Ingo Schommer) + * 2012-12-04 [65002f6](https://github.com/silverstripe/sapphire/commit/65002f6) GD::greyscale did not correctly preserve alpha component of images Added test cases to test greyscale operation across various image formats Replaced various magic numbers with IMAGETYPE_XXX definitions (Damian Mooyman) + * 2012-12-03 [f9a5601](https://github.com/silverstripe/silverstripe-cms/commit/f9a5601) Enforce "add page" restrictions, improve UI (fixes #7879) (Ingo Schommer) + * 2012-12-03 [a63a9f0](https://github.com/silverstripe/silverstripe-cms/commit/a63a9f0) removed class cms-panel-link as it was calling loadPanel to be called twice trac 8041 (Kirk Mayo) + * 2012-12-03 [da1a6e7](https://github.com/silverstripe/sapphire/commit/da1a6e7) Unable to return to site tree admin from Preview mode trac 8063 (Kirk Mayo) + * 2012-11-30 [0808a1c](https://github.com/silverstripe/sapphire/commit/0808a1c) ed JS syntax error (Ingo Schommer) + * 2012-11-30 [dbaf407](https://github.com/silverstripe/sapphire/commit/dbaf407) ed help text alignment for checkbox and grid fields (Ingo Schommer) + * 2012-11-30 [2614171](https://github.com/silverstripe/sapphire/commit/2614171) Deep cloning for DateTimeField (Ingo Schommer) + * 2012-11-30 [20a5bc1](https://github.com/silverstripe/sapphire/commit/20a5bc1) iOS safari navigation bug (fixes #8039) (Kirk Mayo) + * 2012-11-29 [7d0e10f](https://github.com/silverstripe/sapphire/commit/7d0e10f) Extends too generic (Naomi Guyer) + * 2012-11-27 [414c006](https://github.com/silverstripe/sapphire/commit/414c006) Restore GD class to avoid breaking GD::set_default_quality() calls (Ingo Schommer) + * 2012-11-26 [670c579](https://github.com/silverstripe/silverstripe-cms/commit/670c579) Namespaces for CmsFormsContext and CmsUiContext are wrong (Kirk Mayo) + * 2012-11-23 [76b99e4](https://github.com/silverstripe/silverstripe-cms/commit/76b99e4) ed tests without assertions (Ingo Schommer) + * 2012-11-16 [4651e9b](https://github.com/silverstripe/sapphire/commit/4651e9b) Fixing ToggleField to work correctly with jQuery (Sean Harvey) + * 2012-11-15 [94b37db](https://github.com/silverstripe/silverstripe-cms/commit/94b37db) ing AssetAdmin to use static FormField::create_tag() (Sean Harvey) + * 2012-11-15 [1edfeef](https://github.com/silverstripe/sapphire/commit/1edfeef) Remove extraneous layout calls. (Mateusz Uzdowski) + * 2012-11-12 [4fab9b8](https://github.com/silverstripe/silverstripe-cms/commit/4fab9b8) Incorrect html nesting of breadcrumbs (Naomi Guyer) + * 2012-11-12 [a933847](https://github.com/silverstripe/sapphire/commit/a933847) Incorrect html nesting of breadcrumbs (Naomi Guyer) + * 2012-11-12 [9d74c99](https://github.com/silverstripe/sapphire/commit/9d74c99) ArrayList now discards keys of the array passed in and keeps the numerically indexed array sequential. This fixes FirstLast and EvenOdd in templates, and makes ArrayList more consistent, as several methods already discarded the keys. (Andrew O'Neil) + * 2012-11-11 [af2ac1d](https://github.com/silverstripe/sapphire/commit/af2ac1d) include ImagickBackend only when Imagick installed (Will Rossiter) + * 2012-11-07 [91b69bf](https://github.com/silverstripe/sapphire/commit/91b69bf) ed tab alignment and padding (Ingo Schommer) + * 2012-11-05 [7ae73ea](https://github.com/silverstripe/sapphire/commit/7ae73ea) Border at top of tabs when no subtabs (Naomi Guyer) + * 2012-11-02 [f2a709d](https://github.com/silverstripe/sapphire/commit/f2a709d) DataObject::write overwrites Created on first write (Justin Martin) + * 2012-11-02 [95b5f65](https://github.com/silverstripe/sapphire/commit/95b5f65) GridField add existing auto complete has no max height (fixes #7965) (Naomi Guyer) + * 2012-11-01 [a651d73](https://github.com/silverstripe/sapphire/commit/a651d73) DataObject::__construct() now accepts stdClass for $record (Justin Martin) + * 2012-11-02 [2dabaeb](https://github.com/silverstripe/sapphire/commit/2dabaeb) File Uploading Notifications (fixes #7883) (Naomi Guyer) + * 2012-11-01 [eb23f50](https://github.com/silverstripe/sapphire/commit/eb23f50) Site Tree checkboxes and refactoring (Naomi Guyer) + * 2012-11-01 [2a67715](https://github.com/silverstripe/sapphire/commit/2a67715) One too many brackets in _style.scss (Naomi Guyer) + * 2012-10-30 [0883226](https://github.com/silverstripe/sapphire/commit/0883226) ed merge errors in CMSProfileController (Ingo Schommer) + * 2012-10-23 [0d642af](https://github.com/silverstripe/silverstripe-cms/commit/0d642af) Filter in asset grid appears in incorrect place (Naomi Guyer) + * 2012-10-17 [8a7f9ed](https://github.com/silverstripe/sapphire/commit/8a7f9ed) ed empty string always on scaffolded enum fields (icecaster) + * 2012-10-16 [d61f16d](https://github.com/silverstripe/silverstripe-cms/commit/d61f16d) File Uploading Notifications (fixes #7883) (Naomi Guyer) + * 2012-10-10 [fbfff8d](https://github.com/silverstripe/sapphire/commit/fbfff8d) 7934 When lazy loading fields respect version of the record (jean) + * 2012-09-27 [39792de](https://github.com/silverstripe/silverstripe-cms/commit/39792de) Use RequestHandler::httpError() for all HTTP errors. (Sam Minnee) + * 2012-09-27 [b92f759](https://github.com/silverstripe/silverstripe-cms/commit/b92f759) ing test to be less fragile (selects the input ID directly instead of holder) (Sean Harvey) + * 2012-09-27 [e9ce89e](https://github.com/silverstripe/sapphire/commit/e9ce89e) ing broken FulltextSearchableTest (Sean Harvey) + * 2012-09-24 [0470219](https://github.com/silverstripe/sapphire/commit/0470219) Output the title of the task instead of Array when listing in the CLI (Simon Welsh) + * 2012-09-17 [b6c1a64](https://github.com/silverstripe/sapphire/commit/b6c1a64) ed link to RC3 changelog (Sean Harvey) + * 2012-09-04 [6b6571c](https://github.com/silverstripe/silverstripe-cms/commit/6b6571c) Only rely on request var ParentID, instead of using both $this->currentPage() and the request var. This will hopefully fix issues around the parent ID getting lost. (Andrew O'Neil) + * 2012-08-23 [cd61b61](https://github.com/silverstripe/sapphire/commit/cd61b61) Use array_intersect() with expected values so that the order matches. (Simon Welsh) + * 2012-08-21 [cbdc3bf](https://github.com/silverstripe/sapphire/commit/cbdc3bf) ed bug in Travis matrix definition (Sam Minnee) + * 2012-08-21 [597bc08](https://github.com/silverstripe/sapphire/commit/597bc08) ed bug in Travis exclusion of 5.4/SQlite and 5.4/PostgreSQL (Sam Minnee) + * 2012-08-15 [c621a6d](https://github.com/silverstripe/sapphire/commit/c621a6d) fixed trac 7665 - CMS Menu header now changes height depending on the name of the admin and greeting message. position and height were being set inline so added !important to override this. (Jeremy Bridson) + * 2012-08-14 [0e08840](https://github.com/silverstripe/sapphire/commit/0e08840) ed Travis CI and make it use SQLite (Sam Minnee) + * 2012-08-14 [50b4d80](https://github.com/silverstripe/sapphire/commit/50b4d80) ed bugs in Travis CI set-up (Sam Minnee) + * 2012-07-23 [c058f97](https://github.com/silverstripe/sapphire/commit/c058f97) Allow using instances for search filters. (Andrew Short) + * 2012-07-17 [dbc862e](https://github.com/silverstripe/sapphire/commit/dbc862e) Attempt to create log path before writing file (Simon Elvery) + * 2012-07-10 [c91e855](https://github.com/silverstripe/sapphire/commit/c91e855) resolve errors with commits from (#572) (Will Rossiter) + * 2012-07-09 [0ef0c9c](https://github.com/silverstripe/sapphire/commit/0ef0c9c) removed text shadow off confirmation message links trac 7637 (Jeremy Bridson) + * 2012-07-06 [2a9a4be](https://github.com/silverstripe/sapphire/commit/2a9a4be) ed nested tab styling in other CMS interfaces. (Andrew Short) + * 2012-07-06 [7ff2a79](https://github.com/silverstripe/sapphire/commit/7ff2a79) links in profiling documentation. (Will Rossiter) + * 2012-07-01 [a67b964](https://github.com/silverstripe/sapphire/commit/a67b964) improve Director::makeRelative() to ignore SSL changes. (Tim Klein) + * 2012-07-01 [9f6eeb4](https://github.com/silverstripe/sapphire/commit/9f6eeb4) insert javascript requirements before the first inline script. (Simon Welsh) + * 2012-07-01 [9babb01](https://github.com/silverstripe/sapphire/commit/9babb01) ensure that permissions_for_member() accounts for denied permissions. (Will Rossiter) + * 2012-06-29 [e050540](https://github.com/silverstripe/sapphire/commit/e050540) Director::is_absolute_url() now ignores query and fragment strings (Simon Welsh) + * 2012-06-25 [606d86a](https://github.com/silverstripe/sapphire/commit/606d86a) DateField javascript fails when it is included in a GroupField (Jeremy Shipman) + +### Other + + * 2012-12-15 [5b2cc19](https://github.com/silverstripe/silverstripe-cms/commit/5b2cc19) Added placeholder text to group listboxes (Ingo Schommer) + * 2012-12-14 [e6bf199](https://github.com/silverstripe/sapphire/commit/e6bf199) Less far-future date assertions, seems to throw off some PHP installs (Ingo Schommer) + * 2012-12-14 [4f5b3fa](https://github.com/silverstripe/sapphire/commit/4f5b3fa) Readd SQlite to travis builds, having it fail harms TDD (Ingo Schommer) + * 2012-12-14 [90084bb](https://github.com/silverstripe/sapphire/commit/90084bb) Separate PHPCS run on travis, don't fail whole build for it (Ingo Schommer) + * 2012-12-14 [681a024](https://github.com/silverstripe/sapphire/commit/681a024) DOC Removed link to missing 'extending-the-cms.md' (Stig Lindqvist) + * 2012-12-14 [244bc97](https://github.com/silverstripe/sapphire/commit/244bc97) Don't register a PGSQL failure as a Travis build failure. (Sam Minnee) + * 2012-12-14 [b65180a](https://github.com/silverstripe/sapphire/commit/b65180a) Changelog update for grouped CMS buttons (Ingo Schommer) + * 2012-12-13 [1d470fe](https://github.com/silverstripe/silverstripe-cms/commit/1d470fe) Removed duplciate success status feedback on CMS save/publish (Ingo Schommer) + * 2012-12-13 [aed58a5](https://github.com/silverstripe/sapphire/commit/aed58a5) Loading indicator for "more options" buttons (Ingo Schommer) + * 2012-12-13 [7dd224d](https://github.com/silverstripe/sapphire/commit/7dd224d) Made GridField font size settings less cryptic (Ingo Schommer) + * 2012-12-13 [abf1ee9](https://github.com/silverstripe/sapphire/commit/abf1ee9) Suppress jQuery UI's borders around tabs in the CMS (Ingo Schommer) + * 2012-12-13 [2369cc4](https://github.com/silverstripe/sapphire/commit/2369cc4) Moved group member listing utility buttons after field (Ingo Schommer) + * 2012-12-13 [236e335](https://github.com/silverstripe/sapphire/commit/236e335) Permission list styling improvements (#8100) (Joel Edwards) + * 2012-12-13 [f4128a0](https://github.com/silverstripe/silverstripe-cms/commit/f4128a0) Revert "BUG removed class cms-panel-link as it was calling loadPanel to be called twice trac 8041" (Ingo Schommer) + * 2012-12-12 [611c3f1](https://github.com/silverstripe/silverstripe-cms/commit/611c3f1) Added travis environment info output (Ingo Schommer) + * 2012-12-12 [441bb5f](https://github.com/silverstripe/sapphire/commit/441bb5f) Added travis environment info output (Ingo Schommer) + * 2012-12-12 [6100eb9](https://github.com/silverstripe/sapphire/commit/6100eb9) Remove or comment magic numbers, whitespace (Naomi Guyer) + * 2012-12-11 [40b5366](https://github.com/silverstripe/silverstripe-installer/commit/40b5366) Updated composer.json (Ingo Schommer) + * 2012-12-11 [ed11970](https://github.com/silverstripe/sapphire/commit/ed11970) Updated composer.json (Ingo Schommer) + * 2012-12-11 [4cd166a](https://github.com/silverstripe/silverstripe-cms/commit/4cd166a) Updated composer.json (Ingo Schommer) + * 2012-12-11 [df41fcd](https://github.com/silverstripe/silverstripe-cms/commit/df41fcd) Skip SearchFormTest if DB driver doesn't support fulltext (Ingo Schommer) + * 2012-12-11 [d92258d](https://github.com/silverstripe/sapphire/commit/d92258d) Allow calling SSViewer_Scope on empty sets (Ingo Schommer) + * 2012-12-10 [d5dcecf](https://github.com/silverstripe/sapphire/commit/d5dcecf) Disable change tracking for preview state switch (Ingo Schommer) + * 2012-12-09 [fc5dd29](https://github.com/silverstripe/sapphire/commit/fc5dd29) Add codesniffer that ensures indentation is with tabs. (Simon Welsh) + * 2012-12-09 [b0121b5](https://github.com/silverstripe/sapphire/commit/b0121b5) Add codesniffer that ensures indentation is with tabs. (Simon Welsh) + * 2012-12-06 [a9004b9](https://github.com/silverstripe/silverstripe-cms/commit/a9004b9) Restore numbering to navigator items so we can use iterator. (Mateusz Uzdowski) + * 2012-12-06 [dbee4a1](https://github.com/silverstripe/sapphire/commit/dbee4a1) Clean up the side-by-side code. (Naomi Guyer) + * 2012-12-06 [747346b](https://github.com/silverstripe/sapphire/commit/747346b) Ability to rotate the mobile preview in side-by-side preview. (Paul Clarke) + * 2012-12-05 [5cef05e](https://github.com/silverstripe/sapphire/commit/5cef05e) Separate out ActionTabSet functionality into a new file & clean up. (Naomi Guyer) + * 2012-12-05 [35cbe28](https://github.com/silverstripe/silverstripe-cms/commit/35cbe28) Re-add preview button for IE<=7. Side-by-side disabled for these. (Naomi Guyer) + * 2012-12-04 [98e824b](https://github.com/silverstripe/silverstripe-cms/commit/98e824b) Avoid duplicating ReportAdmin search params (fixes #8046) (Ingo Schommer) + * 2012-12-04 [00f1ba4](https://github.com/silverstripe/sapphire/commit/00f1ba4) Side-by-side preview browser compatibility fixes. (Naomi Guyer) + * 2012-12-04 [230182f](https://github.com/silverstripe/silverstripe-cms/commit/230182f) Remove preview button from history section. (Mateusz Uzdowski) + * 2012-12-04 [fa3ef8c](https://github.com/silverstripe/sapphire/commit/fa3ef8c) Side-by-side preview initialisation and navigation fixes. (Mateusz Uzdowski) + * 2012-12-04 [aaae8c9](https://github.com/silverstripe/silverstripe-cms/commit/aaae8c9) Explicitly mark the section as previewable. (Mateusz Uzdowski) + * 2012-12-03 [8ce2728](https://github.com/silverstripe/sapphire/commit/8ce2728) Replace the state selector switch to support more than 2 states. (Naomi Guyer) + * 2012-11-30 [2cd46ff](https://github.com/silverstripe/silverstripe-cms/commit/2cd46ff) Use new SelectionGroup_Item API in "add page" UI (Ingo Schommer) + * 2012-11-30 [963f02e](https://github.com/silverstripe/sapphire/commit/963f02e) Using new description style in MemberDateTimeOptionSetField (Ingo Schommer) + * 2012-11-30 [255b4c4](https://github.com/silverstripe/sapphire/commit/255b4c4) UploadField->setDescription() support, removed extraneous "title" attrs (Ingo Schommer) + * 2012-11-30 [212c427](https://github.com/silverstripe/sapphire/commit/212c427) Pass setDescription() through to sub-fields in DatetimeField and PhoneNumberField (Ingo Schommer) + * 2012-11-30 [ee797e4](https://github.com/silverstripe/sapphire/commit/ee797e4) More CSS fixes for the ActionTabSets. (Naomi Guyer) + * 2012-11-30 [618e639](https://github.com/silverstripe/sapphire/commit/618e639) Refactor and comment TabSet.js (Naomi Guyer) + * 2012-11-29 [027a41a](https://github.com/silverstripe/silverstripe-cms/commit/027a41a) Consistent naming for root breadcrumb on page controllers (fixes #8057) (Ingo Schommer) + * 2012-11-29 [235e8c8](https://github.com/silverstripe/sapphire/commit/235e8c8) CSS fixes for the ActionTabSet. (Naomi Guyer) + * 2012-11-29 [a80aa3c](https://github.com/silverstripe/sapphire/commit/a80aa3c) Provide new save icon for the use in the framework. (Naomi Guyer) + * 2012-11-29 [772961c](https://github.com/silverstripe/silverstripe-cms/commit/772961c) Add a secondary side-by-side state selector to the edit form (Mateusz Uzdowski) + * 2012-11-28 [7bd200f](https://github.com/silverstripe/silverstripe-cms/commit/7bd200f) Re-adding usage of $TRAVIS_BRANCH, fixing wrong 3.0 dependency (Ingo Schommer) + * 2012-11-27 [09f382d](https://github.com/silverstripe/silverstripe-cms/commit/09f382d) Composer require framework at 'dev-master' (Ingo Schommer) + * 2012-11-27 [9312c70](https://github.com/silverstripe/sapphire/commit/9312c70) Side-by-side preview options fixes. (Naomi Guyer) + * 2012-11-27 [715b62f](https://github.com/silverstripe/sapphire/commit/715b62f) Updating chosen dependency (Naomi Guyer) + * 2012-11-27 [0711c32](https://github.com/silverstripe/silverstripe-cms/commit/0711c32) Add side-by-side translation context. (Naomi Guyer) + * 2012-11-22 [477cf6b](https://github.com/silverstripe/sapphire/commit/477cf6b) Removing redundant DatabaseAdmin::testinstall() (Sean Harvey) + * 2012-11-22 [544d2eb](https://github.com/silverstripe/sapphire/commit/544d2eb) Side-by-side preview options styling. (Paul Clarke) + * 2012-11-19 [3f2ddbb](https://github.com/silverstripe/sapphire/commit/3f2ddbb) Future-proof the submitForm for use with forms without validation. (Mateusz Uzdowski) + * 2012-11-16 [8168a7d](https://github.com/silverstripe/sapphire/commit/8168a7d) Remove deprecated DBField::create(), use create_field() instead (Sean Harvey) + * 2012-11-16 [b3d5b68](https://github.com/silverstripe/sapphire/commit/b3d5b68) Remove deprecated SQLQuery::setWhere() multiple arguments (Sean Harvey) + * 2012-11-16 [a2bd378](https://github.com/silverstripe/sapphire/commit/a2bd378) Remove deprecated ArrayList::getRange(), use limit() instead (Sean Harvey) + * 2012-11-16 [7042d87](https://github.com/silverstripe/sapphire/commit/7042d87) Remove deprecated Object::set_uninherited() (Sean Harvey) + * 2012-11-16 [d13b067](https://github.com/silverstripe/sapphire/commit/d13b067) Remove deprecated HTTP::getMimeType() use get_mime_type() instead (Sean Harvey) + * 2012-11-16 [a46838c](https://github.com/silverstripe/sapphire/commit/a46838c) Removed deprecated Folder::findOrMake(), use find_or_make() instead (Sean Harvey) + * 2012-11-16 [d1c5cd1](https://github.com/silverstripe/sapphire/commit/d1c5cd1) Removing unused entities from en.yml (Sean Harvey) + * 2012-11-16 [4c73f23](https://github.com/silverstripe/silverstripe-cms/commit/4c73f23) Removing deprecated FileList as it relies on TableListField (Sean Harvey) + * 2012-11-16 [4ea5bc5](https://github.com/silverstripe/sapphire/commit/4ea5bc5) adding notes about deprecated things in the core (Sean Harvey) + * 2012-11-16 [4330ecf](https://github.com/silverstripe/sapphire/commit/4330ecf) Removing redundant templates (moved to legacytablefields module) (Sean Harvey) + * 2012-11-16 [6a868e7](https://github.com/silverstripe/sapphire/commit/6a868e7) Removing deprecated prototype/behaviour libraries (Sean Harvey) + * 2012-11-16 [77337ae](https://github.com/silverstripe/sapphire/commit/77337ae) Removing deprecated TableListField and subclasses (Sean Harvey) + * 2012-11-16 [aeef4d6](https://github.com/silverstripe/sapphire/commit/aeef4d6) Removing deprecated JS from AjaxUniqueTextField (Sean Harvey) + * 2012-11-15 [26a3c1c](https://github.com/silverstripe/sapphire/commit/26a3c1c) Re-adding Debug::caller() which was inadvertently removed in 9eca2d6 (Sean Harvey) + * 2012-11-15 [cef087f](https://github.com/silverstripe/silverstripe-cms/commit/cef087f) Removed deprecated SiteTree::TreeTitle(), use getTreeTitle() instead (Sean Harvey) + * 2012-11-15 [d236bb5](https://github.com/silverstripe/silverstripe-cms/commit/d236bb5) Removed deprecated SiteTree::prepopuplate_permission_cache() (Sean Harvey) + * 2012-11-15 [33884ac](https://github.com/silverstripe/silverstripe-cms/commit/33884ac) Removed deprecated ContentController::LangAttributes() (Sean Harvey) + * 2012-11-15 [555ecd7](https://github.com/silverstripe/silverstripe-cms/commit/555ecd7) Removed deprecated SiteTreeDecorator, use SiteTreeExtension instead (Sean Harvey) + * 2012-11-15 [41efeed](https://github.com/silverstripe/sapphire/commit/41efeed) Update javascript/GridField.js (Vitaliy) + * 2012-11-15 [35bcf69](https://github.com/silverstripe/silverstripe-cms/commit/35bcf69) Removed deprecated Register::register() and unregister() (Sean Harvey) + * 2012-11-15 [8c3ecab](https://github.com/silverstripe/sapphire/commit/8c3ecab) Removed deprecated ToggleCompositeField::startClosed() (Sean Harvey) + * 2012-11-15 [4c803a2](https://github.com/silverstripe/sapphire/commit/4c803a2) Removed deprecated arguments of row, cols to TextareaField (Sean Harvey) + * 2012-11-15 [4d11080](https://github.com/silverstripe/sapphire/commit/4d11080) Remove deprecated rows and columns argument support from HtmlEditorField (Sean Harvey) + * 2012-11-15 [b3b071a](https://github.com/silverstripe/sapphire/commit/b3b071a) Removing deprecated FormField functions (Sean Harvey) + * 2012-11-15 [0d659a5](https://github.com/silverstripe/sapphire/commit/0d659a5) Removing deprecated FormField::Name(), use getName() instead (Sean Harvey) + * 2012-11-15 [c99ed7d](https://github.com/silverstripe/sapphire/commit/c99ed7d) Extending deprecation of legacy table fields to 3.1 (Sean Harvey) + * 2012-11-15 [e1c5f08](https://github.com/silverstripe/sapphire/commit/e1c5f08) Removing deprecated container class argument to DataObject::get() (Sean Harvey) + * 2012-11-15 [3a198c3](https://github.com/silverstripe/sapphire/commit/3a198c3) Removing deprecated DataObject::databaseFields() and customDatabaseFields() (Sean Harvey) + * 2012-11-15 [e4088fe](https://github.com/silverstripe/sapphire/commit/e4088fe) Removing deprecated instance_get_one() and instance_get() (Sean Harvey) + * 2012-11-15 [a8d779b](https://github.com/silverstripe/sapphire/commit/a8d779b) Removing deprecated DataObject::buildDataObjectSet() (Sean Harvey) + * 2012-11-15 [dde820d](https://github.com/silverstripe/sapphire/commit/dde820d) Extend deprecation of DataObject::Aggregate() and RelationshipAggregate() (Sean Harvey) + * 2012-11-15 [0db33f7](https://github.com/silverstripe/sapphire/commit/0db33f7) Removing DataObject::buildSQL() and extendedSQL(), use DataList instead (Sean Harvey) + * 2012-11-15 [651d4b3](https://github.com/silverstripe/sapphire/commit/651d4b3) Removing DataObject::getAllFields(), use toMap() instead (Sean Harvey) + * 2012-11-15 [5f852ae](https://github.com/silverstripe/sapphire/commit/5f852ae) Removing deprecated DataObject::setComponent() (Sean Harvey) + * 2012-11-15 [3108dea](https://github.com/silverstripe/sapphire/commit/3108dea) Removing deprecated DataList::limit() arguments (Sean Harvey) + * 2012-11-15 [68bb748](https://github.com/silverstripe/sapphire/commit/68bb748) Removing join() on DataList/DataQuery (Sean Harvey) + * 2012-11-15 [b43b023](https://github.com/silverstripe/sapphire/commit/b43b023) Remove deprecated security token methods on Form (Sean Harvey) + * 2012-11-15 [6382013](https://github.com/silverstripe/sapphire/commit/6382013) Remove deprecated Form::FormEncType(), use getEncType() instead (Sean Harvey) + * 2012-11-15 [4e355bd](https://github.com/silverstripe/sapphire/commit/4e355bd) Removing deprecated methods on Form (Sean Harvey) + * 2012-11-15 [2080867](https://github.com/silverstripe/sapphire/commit/2080867) Removing deprecated arguments to FileField for setting folder name (Sean Harvey) + * 2012-11-15 [a9d7c9e](https://github.com/silverstripe/sapphire/commit/a9d7c9e) Removing deprecated variables from FileField (Sean Harvey) + * 2012-11-15 [0a5d43f](https://github.com/silverstripe/sapphire/commit/0a5d43f) Removing deprecated CompositeField::FieldSet(), use FieldList() instead (Sean Harvey) + * 2012-11-15 [6448cd7](https://github.com/silverstripe/sapphire/commit/6448cd7) Removing deprecated Validator javascript methods (Sean Harvey) + * 2012-11-15 [5c983a2](https://github.com/silverstripe/sapphire/commit/5c983a2) emove deprecated StringField::Lower() and Upper() methods (Sean Harvey) + * 2012-11-15 [9e7bdb3](https://github.com/silverstripe/sapphire/commit/9e7bdb3) Removing deprecated Text::EscapeXML(), use DBField->XML() instead (Sean Harvey) + * 2012-11-15 [f41650c](https://github.com/silverstripe/sapphire/commit/f41650c) Remove deprecated i18n::include_locale_file() (Sean Harvey) + * 2012-11-15 [587d669](https://github.com/silverstripe/sapphire/commit/587d669) Removing deprecated PasswordEncryptor::compare() method (Sean Harvey) + * 2012-11-15 [f122b10](https://github.com/silverstripe/sapphire/commit/f122b10) Remove deprecated Group::addToGroupByName() (Sean Harvey) + * 2012-11-15 [d038cd7](https://github.com/silverstripe/sapphire/commit/d038cd7) Removing deprecated tests (Sean Harvey) + * 2012-11-15 [0d79897](https://github.com/silverstripe/sapphire/commit/0d79897) Removing deprecated ArrayData::getArray() (Sean Harvey) + * 2012-11-15 [de2509c](https://github.com/silverstripe/sapphire/commit/de2509c) Removing deprecated SimpleImageField (Sean Harvey) + * 2012-11-15 [6ce33d5](https://github.com/silverstripe/sapphire/commit/6ce33d5) Removing deprecated ImageFormAction (Sean Harvey) + * 2012-11-15 [8156f0f](https://github.com/silverstripe/sapphire/commit/8156f0f) Removing deprecated ImageField, use UploadField instead (Sean Harvey) + * 2012-11-15 [594faf7](https://github.com/silverstripe/sapphire/commit/594faf7) Removing deprecated FileIFrameField, use UploadField instead (Sean Harvey) + * 2012-11-15 [5a98cdd](https://github.com/silverstripe/sapphire/commit/5a98cdd) Removing deprecated File::TreeTitle(), use File::getTreeTitle() instead (Sean Harvey) + * 2012-11-15 [e52db56](https://github.com/silverstripe/sapphire/commit/e52db56) Removing deprecated validator functions on Upload (Sean Harvey) + * 2012-11-15 [9eca2d6](https://github.com/silverstripe/sapphire/commit/9eca2d6) Removing deprecated Debug functions, use SS_Log and SS_Backtrace instead (Sean Harvey) + * 2012-11-15 [b6870ad](https://github.com/silverstripe/sapphire/commit/b6870ad) Removing deprecated Core.php functions (Sean Harvey) + * 2012-11-15 [b5ee9f9](https://github.com/silverstripe/sapphire/commit/b5ee9f9) Removing ClassInfo::is_subclass_of(), use is_subclass_of() instead (Sean Harvey) + * 2012-11-15 [78311c9](https://github.com/silverstripe/sapphire/commit/78311c9) Remove deprecated PaginatedList::getPageLimits() and setPageLimits() (Sean Harvey) + * 2012-11-15 [63983ad](https://github.com/silverstripe/sapphire/commit/63983ad) Remove deprecated RequestHandler::isAjax(), use SS_HTTPRequest->isAjax() instead (Sean Harvey) + * 2012-11-15 [491057f](https://github.com/silverstripe/sapphire/commit/491057f) Remove deprecated Director dev/test server functions (Sean Harvey) + * 2012-11-15 [66d8ff9](https://github.com/silverstripe/sapphire/commit/66d8ff9) Remove deprecated Director static functions (Sean Harvey) + * 2012-11-15 [de0ade9](https://github.com/silverstripe/sapphire/commit/de0ade9) Remove deprecated Director::urlParam() and Director::urlParams() (Sean Harvey) + * 2012-11-15 [6718814](https://github.com/silverstripe/sapphire/commit/6718814) Remove deprecated PartialMatchFilter, use PartialMatchFilter instead (Sean Harvey) + * 2012-11-15 [4c3b804](https://github.com/silverstripe/sapphire/commit/4c3b804) Remove deprecated ComponentSet, use ManyManyList or HasManyList instead (Sean Harvey) + * 2012-11-15 [0a046af](https://github.com/silverstripe/sapphire/commit/0a046af) Remove deprecated DataObjectDecorator, use DataExtension instead (Sean Harvey) + * 2012-11-15 [a371db4](https://github.com/silverstripe/sapphire/commit/a371db4) Remove deprecated DataObjectSet, use DataList or ArrayList instead (Sean Harvey) + * 2012-11-15 [0673f27](https://github.com/silverstripe/sapphire/commit/0673f27) Remove deprecated FieldSet, use FieldList instead (Sean Harvey) + * 2012-11-15 [6a9617b](https://github.com/silverstripe/sapphire/commit/6a9617b) Remove deprecated LeftAndMainDecorator, use LeftAndMainExtension instead (Sean Harvey) + * 2012-11-10 [d006c08](https://github.com/silverstripe/silverstripe-cms/commit/d006c08) Reverts test code committed in a52514a3 (Simon Welsh) + * 2012-11-08 [0fe9379](https://github.com/silverstripe/silverstripe-cms/commit/0fe9379) Composer branch alias from dev-master to 3.1 (Ingo Schommer) + * 2012-11-08 [bde6344](https://github.com/silverstripe/sapphire/commit/bde6344) Composer branch alias from dev-master to 3.1 (Ingo Schommer) + * 2012-11-06 [ada4210](https://github.com/silverstripe/sapphire/commit/ada4210) Tabs docs for CMS (Ingo Schommer) + * 2012-11-07 [078a8e9](https://github.com/silverstripe/sapphire/commit/078a8e9) Adding note about Object::add_extension() and has_extension() changes (Sean Harvey) + * 2012-11-06 [f988ae3](https://github.com/silverstripe/sapphire/commit/f988ae3) ENHANCEMENT Message colours updated (Paul Clarke) + * 2012-11-05 [f30759e](https://github.com/silverstripe/silverstripe-installer/commit/f30759e) Updating favicon (Sean Harvey) + * 2012-11-01 [f9e32f5](https://github.com/silverstripe/silverstripe-cms/commit/f9e32f5) Added composer.json (Ingo Schommer) + * 2012-11-01 [43cd54b](https://github.com/silverstripe/sapphire/commit/43cd54b) Added composer.json (Ingo Schommer) + * 2012-10-23 [84851c9](https://github.com/silverstripe/sapphire/commit/84851c9) Remove sub navigation for "Files" (fixes 7956) (Naomi Guyer) + * 2012-10-23 [92e4b4f](https://github.com/silverstripe/sapphire/commit/92e4b4f) Remove sub navigation for "Files" (fixes 7956) (Naomi Guyer) + * 2012-10-16 [f365134](https://github.com/silverstripe/sapphire/commit/f365134) Added 2.4.8-rc1 changelog (Ingo Schommer) + * 2012-10-08 [e3a27ea](https://github.com/silverstripe/sapphire/commit/e3a27ea) CMS member profile now is no longer in a popup (#7880) (Saophalkun Ponlu) + * 2012-10-03 [fb5e488](https://github.com/silverstripe/sapphire/commit/fb5e488) Line length fixes (Ingo Schommer) + * 2012-09-21 [7f1b6cf](https://github.com/silverstripe/sapphire/commit/7f1b6cf) HTTPRequest and HTTPResponse now return $this on all setters MINOR: also added some docs (Zauberfisch) + * 2012-09-21 [5df519c](https://github.com/silverstripe/sapphire/commit/5df519c) Removed SiteTree.MetaTitle and MetaKeywords usage (Ingo Schommer) + * 2012-09-21 [4506e92](https://github.com/silverstripe/silverstripe-cms/commit/4506e92) Adds Travis testing to the CMS (Simon Welsh) + * 2012-08-21 [9f4fb13](https://github.com/silverstripe/sapphire/commit/9f4fb13) Added PHP 5.4 + MySQL to build grid (Sam Minnee) + * 2012-08-21 [866d9a9](https://github.com/silverstripe/sapphire/commit/866d9a9) Updated Travis-CI configuration to have a 3 database build grid. (Sam Minnee) + * 2012-08-14 [2dadc77](https://github.com/silverstripe/sapphire/commit/2dadc77) Revert "Make PHPUnit bootstrap add flush=1" (Sam Minnee) + * 2012-08-14 [4d1c2ed](https://github.com/silverstripe/sapphire/commit/4d1c2ed) Make PHPUnit bootstrap add flush=1 (Sam Minnee) + * 2012-08-14 [8d92046](https://github.com/silverstripe/sapphire/commit/8d92046) Added support for Travis CI (Sam Minnee) + * 2012-08-01 [f5b25d2](https://github.com/silverstripe/sapphire/commit/f5b25d2) Make the list used for autocomplete search results settable. (Andrew Short) + * 2012-07-17 [9a5baaf](https://github.com/silverstripe/sapphire/commit/9a5baaf) Don't capture form submits to new windows. (Andrew Short) \ No newline at end of file From 6aa16e1f01d884cbce408e5caa6df9d3c3b5ddce Mon Sep 17 00:00:00 2001 From: Damian Mooyman Date: Mon, 17 Dec 2012 17:15:26 +1300 Subject: [PATCH 12/73] BUG Test case for versioned now correctly checks IDs returned from Versioned::get_including_deleted BUG Issue with deleted records not being queried properly. API DataQuery::expressionForField no longer requires a second parameter. Rather the query object is inferred from the DataQuery itself. This should improve consistency of use of this function. --- model/DataQuery.php | 30 +++++++++++++++++------------- model/Versioned.php | 24 +++++++++++++++++++----- tests/model/VersionedTest.php | 16 ++++++++++++++-- 3 files changed, 50 insertions(+), 20 deletions(-) diff --git a/model/DataQuery.php b/model/DataQuery.php index 16d3a1276..bc0382423 100644 --- a/model/DataQuery.php +++ b/model/DataQuery.php @@ -647,12 +647,12 @@ class DataQuery { * @param string $field */ public function subtract(DataQuery $subtractQuery, $field='ID') { - $subSelect= $subtractQuery->getFinalisedQuery(); - $fieldExpression = $this->expressionForField($field, $subSelect); + $fieldExpression = $subtractQuery->expressionForField($field); + $subSelect = $subtractQuery->getFinalisedQuery(); $subSelect->setSelect(array()); $subSelect->selectField($fieldExpression, $field); $subSelect->setOrderBy(null); - $this->where($this->expressionForField($field, $this).' NOT IN ('.$subSelect->sql().')'); + $this->where($this->expressionForField($field).' NOT IN ('.$subSelect->sql().')'); return $this; } @@ -679,9 +679,9 @@ class DataQuery { * @param String $field See {@link expressionForField()}. */ public function column($field = 'ID') { + $fieldExpression = $this->expressionForField($field); $query = $this->getFinalisedQuery(array($field)); $originalSelect = $query->getSelect(); - $fieldExpression = $this->expressionForField($field, $query); $query->setSelect(array()); $query->selectField($fieldExpression, $field); $this->ensureSelectContainsOrderbyColumns($query, $originalSelect); @@ -692,17 +692,21 @@ class DataQuery { /** * @param String $field Select statement identifier, either the unquoted column name, * the full composite SQL statement, or the alias set through {@link SQLQuery->selectField()}. - * @param SQLQuery $query - * @return String + * @return String The expression used to query this field via this DataQuery */ - protected function expressionForField($field, $query) { - // Special case for ID - if($field == 'ID') { + protected function expressionForField($field) { + + // Prepare query object for selecting this field + $query = $this->getFinalisedQuery(array($field)); + + // Allow query to define the expression for this field + $expression = $query->expressionForField($field); + if(!empty($expression)) return $expression; + + // Special case for ID, if not provided + if($field === 'ID') { $baseClass = ClassInfo::baseDataClass($this->dataClass); - return "\"$baseClass\".\"ID\""; - - } else { - return $query->expressionForField($field); + return "\"$baseClass\".\"ID\""; } } diff --git a/model/Versioned.php b/model/Versioned.php index 560358475..7fab016e5 100644 --- a/model/Versioned.php +++ b/model/Versioned.php @@ -136,8 +136,8 @@ class Versioned extends DataExtension { * @todo Should this all go into VersionedDataQuery? */ public function augmentSQL(SQLQuery &$query, DataQuery &$dataQuery = null) { - $baseTable = ClassInfo::baseDataClass($dataQuery->dataClass()); - + $baseTable = ClassInfo::baseDataClass($dataQuery->dataClass()); + switch($dataQuery->getQueryParam('Versioned.mode')) { // Noop case '': @@ -232,8 +232,19 @@ class Versioned extends DataExtension { foreach(self::$db_for_versions_table as $name => $type) { $query->selectField(sprintf('"%s_versions"."%s"', $baseTable, $name), $name); } + + // Alias the record ID as the row ID $query->selectField(sprintf('"%s_versions"."%s"', $baseTable, 'RecordID'), "ID"); - $query->addOrderBy(sprintf('"%s_versions"."%s"', $baseTable, 'Version')); + + // Ensure that any sort order referring to this ID is correctly aliased + $orders = $query->getOrderBy(); + foreach($orders as $order => $dir) { + if($order === "\"$baseTable\".\"ID\"") { + unset($orders[$order]); + $orders["\"{$baseTable}_versions\".\"RecordID\""] = $dir; + } + } + $query->setOrderBy($orders); // latest_version has one more step // Return latest version instances, regardless of whether they are on a particular stage @@ -250,6 +261,9 @@ class Versioned extends DataExtension { ) AS \"{$alias}_versions_latest\" WHERE \"{$alias}_versions_latest\".\"RecordID\" = \"{$alias}_versions\".\"RecordID\" )"); + } else { + // If all versions are requested, ensure that records are sorted by this field + $query->addOrderBy(sprintf('"%s_versions"."%s"', $baseTable, 'Version')); } break; default: @@ -266,8 +280,8 @@ class Versioned extends DataExtension { */ function augmentLoadLazyFields(SQLQuery &$query, DataQuery &$dataQuery = null, $record) { $dataClass = $dataQuery->dataClass(); - if (isset($record['Version'])){ - $dataQuery->where("\"$dataClass\".\"RecordID\" = " . $record['ID']); + if (isset($record['Version'])){ + $dataQuery->where("\"$dataClass\".\"RecordID\" = " . $record['ID']); $dataQuery->where("\"$dataClass\".\"Version\" = " . $record['Version']); $dataQuery->setQueryParam('Versioned.mode', 'all_versions'); } diff --git a/tests/model/VersionedTest.php b/tests/model/VersionedTest.php index 6c1aec3b9..a671adc77 100644 --- a/tests/model/VersionedTest.php +++ b/tests/model/VersionedTest.php @@ -74,8 +74,15 @@ class VersionedTest extends SapphireTest { * Test Versioned::get_including_deleted() */ public function testGetIncludingDeleted() { - // Delete a page - $this->objFromFixture('VersionedTest_DataObject', 'page3')->delete(); + // Get all ids of pages + $allPageIDs = DataObject::get('VersionedTest_DataObject', "\"ParentID\" = 0", "\"VersionedTest_DataObject\".\"ID\" ASC")->column('ID'); + + // Modify a page, ensuring that the Version ID and Record ID will differ, + // and then subsequently delete it + $targetPage = $this->objFromFixture('VersionedTest_DataObject', 'page3'); + $targetPage->Content = 'To be deleted'; + $targetPage->write(); + $targetPage->delete(); // Get all items, ignoring deleted $remainingPages = DataObject::get("VersionedTest_DataObject", "\"ParentID\" = 0", @@ -90,12 +97,17 @@ class VersionedTest extends SapphireTest { // Check that page 3 is still there $this->assertEquals(array("Page 1", "Page 2", "Page 3"), $allPages->column('Title')); + // Check that the returned pages have the correct IDs + $this->assertEquals($allPageIDs, $allPages->column('ID')); + // Check that this still works if we switch to reading the other stage Versioned::reading_stage("Live"); $allPages = Versioned::get_including_deleted("VersionedTest_DataObject", "\"ParentID\" = 0", "\"VersionedTest_DataObject\".\"ID\" ASC"); $this->assertEquals(array("Page 1", "Page 2", "Page 3"), $allPages->column('Title')); + // Check that the returned pages still have the correct IDs + $this->assertEquals($allPageIDs, $allPages->column('ID')); } public function testVersionedFieldsAdded() { From 17908b670a35fcaafaa6d3bbddc2fecc982fd437 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Mon, 17 Dec 2012 10:55:27 +0100 Subject: [PATCH 13/73] Revert CMS button style (regression from fe08236) Was originally added for CMS grouped actions, but can't see any effect. Probably related to the unreleased changes around the new "batch actions" and "add page" panel styling. It breaks button height in the top toolbar, by shifting from jQuery UI's (well tested) mode of applying padding to the container, to applying padding to the contained text instead. This conflicts with the line-height set on many buttons. --- admin/css/ie7.css | 5 --- admin/css/screen.css | 74 ++++++++++++++++++++---------------------- admin/scss/_forms.scss | 18 ---------- admin/scss/ie7.scss | 14 -------- 4 files changed, 36 insertions(+), 75 deletions(-) diff --git a/admin/css/ie7.css b/admin/css/ie7.css index 375915673..bc068612e 100644 --- a/admin/css/ie7.css +++ b/admin/css/ie7.css @@ -217,8 +217,3 @@ table.ss-gridfield-table tr.ss-gridfield-item.even { background: #F0F4F7; } .cms .cms-content-actions .Actions .action-menus.ss-ui-action-tabset ul.ui-tabs-nav .ui-state-active a.ui-tabs-anchor { background: transparent url(../images/sprites-32x32/arrow_up_lighter.png) no-repeat right top; } .cms .cms-content-actions .Actions .action-menus.ss-ui-action-tabset ul.ui-tabs-nav .ui-state-active a.ui-tabs-anchor:hover { background: transparent url(../images/sprites-32x32/arrow_up_darker.png) no-repeat right top; } .cms .cms-content-actions .Actions .action-menus.ss-ui-action-tabset .ui-tabs-panel button.ss-ui-button { width: 190px; /* Width 100% not calculating by ie7 */ } - -/* Tempory fix as jquery loads too slow to add icons */ -button.ui-button-text-icon-primary { padding-left: 30px !important; } -button.ui-button-text-icon-primary span.ui-button-icon-primary { position: absolute !important; top: 5px !important; left: 8px !important; } -button.ui-button-text-icon-primary .ui-button-text { margin-left: 0 !important; } diff --git a/admin/css/screen.css b/admin/css/screen.css index b19bcdfe5..99cf90c38 100644 --- a/admin/css/screen.css +++ b/admin/css/screen.css @@ -129,8 +129,8 @@ body, html { font-size: 12px; line-height: 16px; font-family: Arial, sans-serif; .ui-widget-header .ui-dialog-title { padding: 6px 0; text-shadow: #ced7dc 1px 1px 0; } .ui-widget-header a.ui-dialog-titlebar-close { position: absolute; top: -8px; right: -15px; width: 30px; height: 30px; z-index: 100000; } .ui-widget-header a.ui-state-hover { border-color: transparent; background: transparent; } -.ui-widget-header a.ui-state-hover .ui-icon-closethick { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -216px no-repeat; } -.ui-widget-header .ui-icon-closethick { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -318px no-repeat; width: 30px; height: 30px; } +.ui-widget-header a.ui-state-hover .ui-icon-closethick { background: url('sprites-32x32-sf6890c994e.png') 0 -216px no-repeat; } +.ui-widget-header .ui-icon-closethick { background: url('sprites-32x32-sf6890c994e.png') 0 -318px no-repeat; width: 30px; height: 30px; } .ui-state-hover { cursor: pointer; } @@ -209,9 +209,7 @@ form.small .field input.text, form.small .field textarea, form.small .field sele .cms input.loading, .cms button.loading, .cms input.ui-state-default.loading, .cms .ui-widget-content input.ui-state-default.loading, .cms .ui-widget-header input.ui-state-default.loading { color: #525252; border-color: #d5d3d3; cursor: default; } .cms input.loading .ui-icon, .cms button.loading .ui-icon, .cms input.ui-state-default.loading .ui-icon, .cms .ui-widget-content input.ui-state-default.loading .ui-icon, .cms .ui-widget-header input.ui-state-default.loading .ui-icon { background: transparent url(../../images/network-save.gif) no-repeat 0 0; } .cms input.loading.ss-ui-action-constructive .ui-icon, .cms button.loading.ss-ui-action-constructive .ui-icon { background: transparent url(../../images/network-save-constructive.gif) no-repeat 0 0; } -.cms .ss-ui-button { font-size: 12px; margin-top: 0px; padding: 5px 10px; font-weight: bold; text-decoration: none; line-height: 16px; color: #393939; border: 1px solid #c0c0c2; border-bottom: 1px solid #a6a6a9; cursor: pointer; background-color: #e6e6e6; white-space: nowrap; background: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjUwJSIgeTE9IjAlIiB4Mj0iNTAlIiB5Mj0iMTAwJSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2ZmZmZmZiIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2Q5ZDlkOSIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=='); background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ffffff), color-stop(100%, #d9d9d9)); background: -webkit-linear-gradient(#ffffff, #d9d9d9); background: -moz-linear-gradient(#ffffff, #d9d9d9); background: -o-linear-gradient(#ffffff, #d9d9d9); background: linear-gradient(#ffffff, #d9d9d9); text-shadow: white 0 1px 1px; /* constructive */ /* destructive */ } -.cms .ss-ui-button .ui-icon, .cms .ss-ui-button .ui-button-text { display: inline-block; line-height: 16px; padding: 0; } -.cms .ss-ui-button .ui-icon { width: 16px; padding: 0 2px; position: relative; left: -2px; margin-top: 0; top: 0; height: 16px; float: left; } +.cms .ss-ui-button { margin-top: 0px; font-weight: bold; text-decoration: none; line-height: 16px; color: #393939; border: 1px solid #c0c0c2; border-bottom: 1px solid #a6a6a9; cursor: pointer; background-color: #e6e6e6; white-space: nowrap; background: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjUwJSIgeTE9IjAlIiB4Mj0iNTAlIiB5Mj0iMTAwJSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2ZmZmZmZiIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2Q5ZDlkOSIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=='); background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ffffff), color-stop(100%, #d9d9d9)); background: -webkit-linear-gradient(#ffffff, #d9d9d9); background: -moz-linear-gradient(#ffffff, #d9d9d9); background: -o-linear-gradient(#ffffff, #d9d9d9); background: linear-gradient(#ffffff, #d9d9d9); text-shadow: white 0 1px 1px; /* constructive */ /* destructive */ } .cms .ss-ui-button.ui-state-hover, .cms .ss-ui-button:hover { text-decoration: none; background-color: white; background: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjUwJSIgeTE9IjAlIiB4Mj0iNTAlIiB5Mj0iMTAwJSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2ZmZmZmZiIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2U2ZTZlNiIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=='); background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ffffff), color-stop(100%, #e6e6e6)); background: -webkit-linear-gradient(#ffffff, #e6e6e6); background: -moz-linear-gradient(#ffffff, #e6e6e6); background: -o-linear-gradient(#ffffff, #e6e6e6); background: linear-gradient(#ffffff, #e6e6e6); -webkit-box-shadow: 0 0 5px #b3b3b3; -moz-box-shadow: 0 0 5px #b3b3b3; box-shadow: 0 0 5px #b3b3b3; } .cms .ss-ui-button:active, .cms .ss-ui-button:focus, .cms .ss-ui-button.ui-state-active, .cms .ss-ui-button.ui-state-focus { border: 1px solid #b3b3b3; background-color: white; background: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjUwJSIgeTE9IjAlIiB4Mj0iNTAlIiB5Mj0iMTAwJSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2ZmZmZmZiIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2U2ZTZlNiIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=='); background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ffffff), color-stop(100%, #e6e6e6)); background: -webkit-linear-gradient(#ffffff, #e6e6e6); background: -moz-linear-gradient(#ffffff, #e6e6e6); background: -o-linear-gradient(#ffffff, #e6e6e6); background: linear-gradient(#ffffff, #e6e6e6); -webkit-box-shadow: 0 0 5px #b3b3b3 inset; -moz-box-shadow: 0 0 5px #b3b3b3 inset; box-shadow: 0 0 5px #b3b3b3 inset; } .cms .ss-ui-button.ss-ui-action-constructive { text-shadow: none; font-weight: bold; color: white; border-color: #1f9433; border-bottom-color: #166a24; background-color: #1f9433; background: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjUwJSIgeTE9IjAlIiB4Mj0iNTAlIiB5Mj0iMTAwJSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzkzYmU0MiIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzFmOTQzMyIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=='); background: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #93be42), color-stop(100%, #1f9433)); background: -webkit-linear-gradient(#93be42, #1f9433); background: -moz-linear-gradient(#93be42, #1f9433); background: -o-linear-gradient(#93be42, #1f9433); background: linear-gradient(#93be42, #1f9433); text-shadow: #1c872f 0 -1px -1px; } @@ -388,16 +386,16 @@ body.cms { overflow: hidden; } .ui-tabs .ui-tabs-nav.ui-state-active { border-color: gray; } .ui-tabs .ui-tabs-nav li.cms-tabset-icon { text-indent: -9999em; } .ui-tabs .ui-tabs-nav li.cms-tabset-icon a { display: block; padding-left: 40px; padding-right: 0; } -.ui-tabs .ui-tabs-nav li.cms-tabset-icon.list a { background: url('../images/sprites-64x64-s88957ee578.png') 0 -504px no-repeat; } -.ui-tabs .ui-tabs-nav li.cms-tabset-icon.tree a { background: url('../images/sprites-64x64-s88957ee578.png') 0 -354px no-repeat; } -.ui-tabs .ui-tabs-nav li.cms-tabset-icon.gallery a { background: url('../images/sprites-64x64-s88957ee578.png') 0 -454px no-repeat; } -.ui-tabs .ui-tabs-nav li.cms-tabset-icon.edit a { background: url('../images/sprites-64x64-s88957ee578.png') 0 -304px no-repeat; } -.ui-tabs .ui-tabs-nav li.cms-tabset-icon.search a { background: url('../images/sprites-64x64-s88957ee578.png') 0 -154px no-repeat; } -.ui-tabs .ui-tabs-nav li.cms-tabset-icon.list.ui-state-active a { background: url('../images/sprites-64x64-s88957ee578.png') 0 -204px no-repeat; } -.ui-tabs .ui-tabs-nav li.cms-tabset-icon.tree.ui-state-active a { background: url('../images/sprites-64x64-s88957ee578.png') 0 -254px no-repeat; } -.ui-tabs .ui-tabs-nav li.cms-tabset-icon.gallery.ui-state-active a { background: url('../images/sprites-64x64-s88957ee578.png') 0 -54px no-repeat; } -.ui-tabs .ui-tabs-nav li.cms-tabset-icon.edit.ui-state-active a { background: url('../images/sprites-64x64-s88957ee578.png') 0 -404px no-repeat; } -.ui-tabs .ui-tabs-nav li.cms-tabset-icon.search.ui-state-active a { background: url('../images/sprites-64x64-s88957ee578.png') 0 -104px no-repeat; } +.ui-tabs .ui-tabs-nav li.cms-tabset-icon.list a { background: url('sprites-64x64-s88957ee578.png') 0 -504px no-repeat; } +.ui-tabs .ui-tabs-nav li.cms-tabset-icon.tree a { background: url('sprites-64x64-s88957ee578.png') 0 -354px no-repeat; } +.ui-tabs .ui-tabs-nav li.cms-tabset-icon.gallery a { background: url('sprites-64x64-s88957ee578.png') 0 -454px no-repeat; } +.ui-tabs .ui-tabs-nav li.cms-tabset-icon.edit a { background: url('sprites-64x64-s88957ee578.png') 0 -304px no-repeat; } +.ui-tabs .ui-tabs-nav li.cms-tabset-icon.search a { background: url('sprites-64x64-s88957ee578.png') 0 -154px no-repeat; } +.ui-tabs .ui-tabs-nav li.cms-tabset-icon.list.ui-state-active a { background: url('sprites-64x64-s88957ee578.png') 0 -204px no-repeat; } +.ui-tabs .ui-tabs-nav li.cms-tabset-icon.tree.ui-state-active a { background: url('sprites-64x64-s88957ee578.png') 0 -254px no-repeat; } +.ui-tabs .ui-tabs-nav li.cms-tabset-icon.gallery.ui-state-active a { background: url('sprites-64x64-s88957ee578.png') 0 -54px no-repeat; } +.ui-tabs .ui-tabs-nav li.cms-tabset-icon.edit.ui-state-active a { background: url('sprites-64x64-s88957ee578.png') 0 -404px no-repeat; } +.ui-tabs .ui-tabs-nav li.cms-tabset-icon.search.ui-state-active a { background: url('sprites-64x64-s88957ee578.png') 0 -104px no-repeat; } .ui-tabs .cms-edit-form, .ui-tabs .cms-content-fields { /*not sure if .cms-content-fields effects other areas*/ } .ui-tabs .cms-edit-form .cms-panel-padded, .ui-tabs .cms-content-fields .cms-panel-padded { /* Has padded area inside it */ padding: 0; margin: 0; } .ui-tabs .cms-edit-form .ui-tabs-panel, .ui-tabs .cms-edit-form .ss-gridfield, .ui-tabs .cms-content-fields .ui-tabs-panel, .ui-tabs .cms-content-fields .ss-gridfield { margin: 12px; padding: 0 0 12px; } @@ -663,7 +661,7 @@ body.cms-dialog { overflow: auto; background: url("../images/textures/bg_cms_mai /** -------------------------------------------- Step labels -------------------------------------------- */ .step-label > * { display: inline-block; vertical-align: top; } .step-label .flyout { height: 18px; font-size: 14px; font-weight: bold; -moz-border-radius-topleft: 3px; -webkit-border-top-left-radius: 3px; border-top-left-radius: 3px; -moz-border-radius-bottomleft: 3px; -webkit-border-bottom-left-radius: 3px; border-bottom-left-radius: 3px; background-color: #667980; padding: 4px 3px 4px 6px; text-align: center; text-shadow: none; color: #fff; } -.step-label .arrow { height: 26px; width: 10px; background: url('../images/sprites-32x32-sf6890c994e.png') 0 -256px no-repeat; margin-right: 4px; } +.step-label .arrow { height: 26px; width: 10px; background: url('sprites-32x32-sf6890c994e.png') 0 -256px no-repeat; margin-right: 4px; } .step-label .title { height: 18px; padding: 4px; } /** -------------------------------------------- Item Edit Form -------------------------------------------- */ @@ -707,10 +705,10 @@ form.import-form label.left { width: 250px; } /** -------------------------------------------- Buttons for FileUpload -------------------------------------------- */ .ss-uploadfield-item-edit-all .ui-button-text { padding-right: 0; } -.toggle-details-icon { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -433px no-repeat; } -.ss-uploadfield-item-edit-all .toggle-details-icon { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -375px no-repeat; display: inline-block; width: 8px; height: 8px; padding-left: 5px; } -.toggle-details-icon.opened { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -1121px no-repeat; } -.ss-uploadfield-item-edit-all .toggle-details-icon.opened { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -359px no-repeat; } +.toggle-details-icon { background: url('sprites-32x32-sf6890c994e.png') 0 -433px no-repeat; } +.ss-uploadfield-item-edit-all .toggle-details-icon { background: url('sprites-32x32-sf6890c994e.png') 0 -375px no-repeat; display: inline-block; width: 8px; height: 8px; padding-left: 5px; } +.toggle-details-icon.opened { background: url('sprites-32x32-sf6890c994e.png') 0 -1121px no-repeat; } +.ss-uploadfield-item-edit-all .toggle-details-icon.opened { background: url('sprites-32x32-sf6890c994e.png') 0 -359px no-repeat; } /** -------------------------------------------- Hide preview toggle link by default. May be shown in IE7 stylesheet and forced to show with js if needed -------------------------------------------- */ .cms .Actions > .cms-preview-toggle-link, .cms .cms-navigator > .cms-preview-toggle-link { display: none; } @@ -825,7 +823,7 @@ li.class-ErrorPage > a a .jstree-pageicon { background-position: 0 -112px; } .cms-logo span { font-weight: bold; font-size: 12px; line-height: 16px; padding: 2px 0; margin-left: 30px; } .cms-login-status { border-top: 1px solid #19435c; padding: 12px 0 17px; line-height: 16px; font-size: 11px; } -.cms-login-status .logout-link { display: inline-block; height: 16px; width: 16px; float: left; margin: 0 8px 0 5px; background: url('../images/sprites-32x32-sf6890c994e.png') 0 -292px no-repeat; text-indent: -9999em; } +.cms-login-status .logout-link { display: inline-block; height: 16px; width: 16px; float: left; margin: 0 8px 0 5px; background: url('sprites-32x32-sf6890c994e.png') 0 -292px no-repeat; text-indent: -9999em; } .cms-menu { z-index: 80; background: #b0bec7; width: 160px; -webkit-box-shadow: rgba(0, 0, 0, 0.9) 0 0 3px; -moz-box-shadow: rgba(0, 0, 0, 0.9) 0 0 3px; box-shadow: rgba(0, 0, 0, 0.9) 0 0 3px; } .cms-menu a { text-decoration: none; } @@ -849,12 +847,12 @@ li.class-ErrorPage > a a .jstree-pageicon { background-position: 0 -112px; } .cms-menu-list li a .icon { display: inline-block; float: left; margin: 4px 10px 0 4px; filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=70); opacity: 0.7; } .cms-menu-list li a .text { display: inline-block; float: left; } .cms-menu-list li a .toggle-children { display: inline-block; float: right; width: 20px; height: 100%; cursor: pointer; } -.cms-menu-list li a .toggle-children .toggle-children-icon { display: inline-block; width: 8px; height: 8px; background: url('../images/sprites-32x32-sf6890c994e.png') 0 -375px no-repeat; vertical-align: middle; } -.cms-menu-list li a .toggle-children.opened .toggle-children-icon { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -359px no-repeat; } +.cms-menu-list li a .toggle-children .toggle-children-icon { display: inline-block; width: 8px; height: 8px; background: url('sprites-32x32-sf6890c994e.png') 0 -375px no-repeat; vertical-align: middle; } +.cms-menu-list li a .toggle-children.opened .toggle-children-icon { background: url('sprites-32x32-sf6890c994e.png') 0 -359px no-repeat; } .cms-menu-list li ul li a { border-top: 1px solid #b6c3cb; } .cms-menu-list li.current a { color: white; text-shadow: #1e5270 0 -1px 0; border-top: 1px solid #55a4d2; border-bottom: 1px solid #236184; background-color: #338dc1; background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjUwJSIgeTE9IjAlIiB4Mj0iNTAlIiB5Mj0iMTAwJSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzMzOGRjMSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzI4NzA5OSIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=='); background-size: 100%; background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #338dc1), color-stop(100%, #287099)); background-image: -webkit-linear-gradient(#338dc1, #287099); background-image: -moz-linear-gradient(#338dc1, #287099); background-image: -o-linear-gradient(#338dc1, #287099); background-image: linear-gradient(#338dc1, #287099); } -.cms-menu-list li.current a .toggle-children .toggle-children-icon { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -433px no-repeat; } -.cms-menu-list li.current a .toggle-children.opened .toggle-children-icon { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -1121px no-repeat; } +.cms-menu-list li.current a .toggle-children .toggle-children-icon { background: url('sprites-32x32-sf6890c994e.png') 0 -433px no-repeat; } +.cms-menu-list li.current a .toggle-children.opened .toggle-children-icon { background: url('sprites-32x32-sf6890c994e.png') 0 -1121px no-repeat; } .cms-menu-list li.current ul { border-top: none; display: block; } .cms-menu-list li.current li { background-color: #287099; } .cms-menu-list li.current li a { font-size: 11px; padding: 0 10px 0 40px; height: 32px; line-height: 32px; color: #e2f0f7; background: none; border-top: 1px solid #2f81b1; border-bottom: 1px solid #1e5270; } @@ -877,14 +875,14 @@ li.class-ErrorPage > a a .jstree-pageicon { background-position: 0 -112px; } .cms-content-controls.cms-preview-controls { z-index: 1; background: #eceff1; height: 30px; /* should be set in js Layout to match page actions */ padding: 12px 12px; } .cms-content-controls .icon-view, .cms-content-controls .preview-selector.dropdown a.chzn-single { white-space: nowrap; } .cms-content-controls .icon-view:before, .cms-content-controls .preview-selector.dropdown a.chzn-single:before { display: inline-block; float: left; content: ''; width: 23px; height: 17px; overflow: hidden; } -.cms-content-controls .icon-auto:before { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -108px no-repeat; } -.cms-content-controls .icon-desktop:before { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -81px no-repeat; } -.cms-content-controls .icon-tablet:before { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -162px no-repeat; } -.cms-content-controls .icon-mobile:before { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -189px no-repeat; } -.cms-content-controls .icon-split:before { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -135px no-repeat; } -.cms-content-controls .icon-edit:before { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -27px no-repeat; } -.cms-content-controls .icon-preview:before { background: url('../images/sprites-32x32-sf6890c994e.png') 0 0 no-repeat; } -.cms-content-controls .icon-window:before { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -54px no-repeat; } +.cms-content-controls .icon-auto:before { background: url('sprites-32x32-sf6890c994e.png') 0 -108px no-repeat; } +.cms-content-controls .icon-desktop:before { background: url('sprites-32x32-sf6890c994e.png') 0 -81px no-repeat; } +.cms-content-controls .icon-tablet:before { background: url('sprites-32x32-sf6890c994e.png') 0 -162px no-repeat; } +.cms-content-controls .icon-mobile:before { background: url('sprites-32x32-sf6890c994e.png') 0 -189px no-repeat; } +.cms-content-controls .icon-split:before { background: url('sprites-32x32-sf6890c994e.png') 0 -135px no-repeat; } +.cms-content-controls .icon-edit:before { background: url('sprites-32x32-sf6890c994e.png') 0 -27px no-repeat; } +.cms-content-controls .icon-preview:before { background: url('sprites-32x32-sf6890c994e.png') 0 0 no-repeat; } +.cms-content-controls .icon-window:before { background: url('sprites-32x32-sf6890c994e.png') 0 -54px no-repeat; } .cms-content-controls .cms-navigator { width: 100%; } .cms-content-controls .preview-selector.dropdown a.chzn-single { text-indent: -200px; } .cms-content-controls .preview-selector { float: right; border-bottom: none; position: relative; -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; margin: 3px 0 0 4px; padding: 0; height: 28px; } @@ -922,7 +920,7 @@ li.class-ErrorPage > a a .jstree-pageicon { background-position: 0 -112px; } /* Styling for the preview screen sizes */ .cms-preview { background-color: #eceff1; height: 100%; width: 100%; } .cms-preview .preview-note { color: #CDD7DC; display: block; font-size: 22px; font-weight: bold; height: 82px; margin-top: -50px; margin-left: -150px; /* half of width */ position: absolute; text-align: center; text-shadow: 0 1px 0 #fff; top: 50%; left: 50%; width: 300px; } -.cms-preview .preview-note span { background: url('../images/sprites-64x64-s88957ee578.png') 0 0 no-repeat; display: block; height: 41px; margin: 0 auto 20px; width: 50px; } +.cms-preview .preview-note span { background: url('sprites-64x64-s88957ee578.png') 0 0 no-repeat; display: block; height: 41px; margin: 0 auto 20px; width: 50px; } .cms-preview .preview-scroll { height: 100%; overflow: auto; position: relative; width: 100%; } .cms-preview .preview-scroll .preview-device-outer { height: 100%; width: 100%; } .cms-preview .preview-scroll .preview-device-outer .preview-device-inner { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; width: 100%; height: 100%; } @@ -1030,10 +1028,10 @@ visible. Added and removed with js in TabSet.js */ /*************************** .cms .ss-ui-action-tabset.action-menus.ss-tabset ul.ui-tabs-nav li a { text-shadow: white 0 1px 1px; color: #0073c1; font-size: 13px; font-weight: normal; line-height: 24px; padding: 0 25px 0 10px; /* Arrow */ } .cms .ss-ui-action-tabset.action-menus.ss-tabset ul.ui-tabs-nav li a:hover, .cms .ss-ui-action-tabset.action-menus.ss-tabset ul.ui-tabs-nav li a:active { -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; outline: none; } .cms .ss-ui-action-tabset.action-menus.ss-tabset ul.ui-tabs-nav li a:hover { text-shadow: white 0 10px 10px; color: #005b98; } -.cms .ss-ui-action-tabset.action-menus.ss-tabset ul.ui-tabs-nav li a:after { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -1189px no-repeat; border-bottom: 0; content: ""; display: inline-block; height: 16px; margin-left: 6px; width: 16px; } -.cms .ss-ui-action-tabset.action-menus.ss-tabset ul.ui-tabs-nav li a:hover:after { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -1163px no-repeat; } -.cms .ss-ui-action-tabset.action-menus.ss-tabset ul.ui-tabs-nav li.ui-state-active a:after { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -1215px no-repeat; } -.cms .ss-ui-action-tabset.action-menus.ss-tabset ul.ui-tabs-nav li.ui-state-active a:hover:after { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -1137px no-repeat; } +.cms .ss-ui-action-tabset.action-menus.ss-tabset ul.ui-tabs-nav li a:after { background: url('sprites-32x32-sf6890c994e.png') 0 -1189px no-repeat; border-bottom: 0; content: ""; display: inline-block; height: 16px; margin-left: 6px; width: 16px; } +.cms .ss-ui-action-tabset.action-menus.ss-tabset ul.ui-tabs-nav li a:hover:after { background: url('sprites-32x32-sf6890c994e.png') 0 -1163px no-repeat; } +.cms .ss-ui-action-tabset.action-menus.ss-tabset ul.ui-tabs-nav li.ui-state-active a:after { background: url('sprites-32x32-sf6890c994e.png') 0 -1215px no-repeat; } +.cms .ss-ui-action-tabset.action-menus.ss-tabset ul.ui-tabs-nav li.ui-state-active a:hover:after { background: url('sprites-32x32-sf6890c994e.png') 0 -1137px no-repeat; } .cms .ss-ui-action-tabset.action-menus.ss-tabset .ui-tabs-panel { overflow: hidden; *zoom: 1; -moz-border-radius-topleft: 3px; -webkit-border-top-left-radius: 3px; border-top-left-radius: 3px; -moz-border-radius-topright: 3px; -webkit-border-top-right-radius: 3px; border-top-right-radius: 3px; -moz-border-radius-bottomleft: 0; -webkit-border-bottom-left-radius: 0; border-bottom-left-radius: 0; -moz-border-radius-bottomright: 0; -webkit-border-bottom-right-radius: 0; border-bottom-right-radius: 0; /* Restyle for smaller area*/ clear: both; display: block; background-color: #eceff1; border: 1px solid #ccc; border-bottom: 1px solid #eceff1; margin: 0; margin-top: 2px; max-width: 250px; padding: 8px 0 2px; position: absolute; z-index: 1; min-width: 190px; } .cms .ss-ui-action-tabset.action-menus.ss-tabset .ui-tabs-panel h3, .cms .ss-ui-action-tabset.action-menus.ss-tabset .ui-tabs-panel h4, .cms .ss-ui-action-tabset.action-menus.ss-tabset .ui-tabs-panel h5 { font-weight: bold; line-height: 16px; } .cms .ss-ui-action-tabset.action-menus.ss-tabset .ui-tabs-panel h3 { font-size: 13px; } diff --git a/admin/scss/_forms.scss b/admin/scss/_forms.scss index 79c68631c..ee53c3033 100644 --- a/admin/scss/_forms.scss +++ b/admin/scss/_forms.scss @@ -361,9 +361,7 @@ form.small .field, .field.small { } .ss-ui-button { - font-size: 12px; margin-top:0px; - padding: 5px 10px; font-weight: bold; text-decoration: none; line-height: $grid-y * 2; @@ -374,22 +372,6 @@ form.small .field, .field.small { background-color: $color-button-generic; white-space: nowrap; - .ui-icon, .ui-button-text { - display: inline-block; - line-height: $grid-x*2; - padding: 0; - } - .ui-icon { - width: 16px; - padding: 0 2px; - position: relative; - left: -2px; - margin-top: 0; - top: 0; - height: 16px; - float: left; - } - @include background( linear-gradient(color-stops( lighten($color-button-generic, 10%), diff --git a/admin/scss/ie7.scss b/admin/scss/ie7.scss index 4c5833e40..dba1f8290 100644 --- a/admin/scss/ie7.scss +++ b/admin/scss/ie7.scss @@ -303,17 +303,3 @@ table.ss-gridfield-table { width: 190px; /* Width 100% not calculating by ie7 */ } } - - -/* Tempory fix as jquery loads too slow to add icons */ -button.ui-button-text-icon-primary { - padding-left: 30px !important; - span.ui-button-icon-primary { - position: absolute !important; - top: 5px !important; - left: 8px !important; - } - .ui-button-text { - margin-left: 0 !important; - } -} From 9cfa7b75f1dd31a3d21dbf5bf9ae3ca6a7fdb852 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Mon, 17 Dec 2012 11:27:24 +0100 Subject: [PATCH 14/73] Wider side panel to fit "add" and "edit" button Moved "edit tree" button into same DOM structure so we can layout them more easily through inline-block. --- admin/css/screen.css | 76 +++++++++++++++++++++--------------------- admin/scss/_style.scss | 6 ++-- 2 files changed, 40 insertions(+), 42 deletions(-) diff --git a/admin/css/screen.css b/admin/css/screen.css index 99cf90c38..4fd318fc3 100644 --- a/admin/css/screen.css +++ b/admin/css/screen.css @@ -129,8 +129,8 @@ body, html { font-size: 12px; line-height: 16px; font-family: Arial, sans-serif; .ui-widget-header .ui-dialog-title { padding: 6px 0; text-shadow: #ced7dc 1px 1px 0; } .ui-widget-header a.ui-dialog-titlebar-close { position: absolute; top: -8px; right: -15px; width: 30px; height: 30px; z-index: 100000; } .ui-widget-header a.ui-state-hover { border-color: transparent; background: transparent; } -.ui-widget-header a.ui-state-hover .ui-icon-closethick { background: url('sprites-32x32-sf6890c994e.png') 0 -216px no-repeat; } -.ui-widget-header .ui-icon-closethick { background: url('sprites-32x32-sf6890c994e.png') 0 -318px no-repeat; width: 30px; height: 30px; } +.ui-widget-header a.ui-state-hover .ui-icon-closethick { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -216px no-repeat; } +.ui-widget-header .ui-icon-closethick { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -318px no-repeat; width: 30px; height: 30px; } .ui-state-hover { cursor: pointer; } @@ -386,16 +386,16 @@ body.cms { overflow: hidden; } .ui-tabs .ui-tabs-nav.ui-state-active { border-color: gray; } .ui-tabs .ui-tabs-nav li.cms-tabset-icon { text-indent: -9999em; } .ui-tabs .ui-tabs-nav li.cms-tabset-icon a { display: block; padding-left: 40px; padding-right: 0; } -.ui-tabs .ui-tabs-nav li.cms-tabset-icon.list a { background: url('sprites-64x64-s88957ee578.png') 0 -504px no-repeat; } -.ui-tabs .ui-tabs-nav li.cms-tabset-icon.tree a { background: url('sprites-64x64-s88957ee578.png') 0 -354px no-repeat; } -.ui-tabs .ui-tabs-nav li.cms-tabset-icon.gallery a { background: url('sprites-64x64-s88957ee578.png') 0 -454px no-repeat; } -.ui-tabs .ui-tabs-nav li.cms-tabset-icon.edit a { background: url('sprites-64x64-s88957ee578.png') 0 -304px no-repeat; } -.ui-tabs .ui-tabs-nav li.cms-tabset-icon.search a { background: url('sprites-64x64-s88957ee578.png') 0 -154px no-repeat; } -.ui-tabs .ui-tabs-nav li.cms-tabset-icon.list.ui-state-active a { background: url('sprites-64x64-s88957ee578.png') 0 -204px no-repeat; } -.ui-tabs .ui-tabs-nav li.cms-tabset-icon.tree.ui-state-active a { background: url('sprites-64x64-s88957ee578.png') 0 -254px no-repeat; } -.ui-tabs .ui-tabs-nav li.cms-tabset-icon.gallery.ui-state-active a { background: url('sprites-64x64-s88957ee578.png') 0 -54px no-repeat; } -.ui-tabs .ui-tabs-nav li.cms-tabset-icon.edit.ui-state-active a { background: url('sprites-64x64-s88957ee578.png') 0 -404px no-repeat; } -.ui-tabs .ui-tabs-nav li.cms-tabset-icon.search.ui-state-active a { background: url('sprites-64x64-s88957ee578.png') 0 -104px no-repeat; } +.ui-tabs .ui-tabs-nav li.cms-tabset-icon.list a { background: url('../images/sprites-64x64-s88957ee578.png') 0 -504px no-repeat; } +.ui-tabs .ui-tabs-nav li.cms-tabset-icon.tree a { background: url('../images/sprites-64x64-s88957ee578.png') 0 -354px no-repeat; } +.ui-tabs .ui-tabs-nav li.cms-tabset-icon.gallery a { background: url('../images/sprites-64x64-s88957ee578.png') 0 -454px no-repeat; } +.ui-tabs .ui-tabs-nav li.cms-tabset-icon.edit a { background: url('../images/sprites-64x64-s88957ee578.png') 0 -304px no-repeat; } +.ui-tabs .ui-tabs-nav li.cms-tabset-icon.search a { background: url('../images/sprites-64x64-s88957ee578.png') 0 -154px no-repeat; } +.ui-tabs .ui-tabs-nav li.cms-tabset-icon.list.ui-state-active a { background: url('../images/sprites-64x64-s88957ee578.png') 0 -204px no-repeat; } +.ui-tabs .ui-tabs-nav li.cms-tabset-icon.tree.ui-state-active a { background: url('../images/sprites-64x64-s88957ee578.png') 0 -254px no-repeat; } +.ui-tabs .ui-tabs-nav li.cms-tabset-icon.gallery.ui-state-active a { background: url('../images/sprites-64x64-s88957ee578.png') 0 -54px no-repeat; } +.ui-tabs .ui-tabs-nav li.cms-tabset-icon.edit.ui-state-active a { background: url('../images/sprites-64x64-s88957ee578.png') 0 -404px no-repeat; } +.ui-tabs .ui-tabs-nav li.cms-tabset-icon.search.ui-state-active a { background: url('../images/sprites-64x64-s88957ee578.png') 0 -104px no-repeat; } .ui-tabs .cms-edit-form, .ui-tabs .cms-content-fields { /*not sure if .cms-content-fields effects other areas*/ } .ui-tabs .cms-edit-form .cms-panel-padded, .ui-tabs .cms-content-fields .cms-panel-padded { /* Has padded area inside it */ padding: 0; margin: 0; } .ui-tabs .cms-edit-form .ui-tabs-panel, .ui-tabs .cms-edit-form .ss-gridfield, .ui-tabs .cms-content-fields .ui-tabs-panel, .ui-tabs .cms-content-fields .ss-gridfield { margin: 12px; padding: 0 0 12px; } @@ -475,7 +475,7 @@ p.message { margin-bottom: 12px; } #PageType ul li .description { font-style: italic; } /** -------------------------------------------- Content toolbar -------------------------------------------- */ -.cms-content-toolbar { min-height: 29px; display: block; margin: 0 0 15px 0; padding-bottom: 9px; border-bottom: 1px solid #d0d3d5; -webkit-box-shadow: 0 1px 0 rgba(248, 248, 248, 0.9); -moz-box-shadow: 0 1px 0 rgba(248, 248, 248, 0.9); -o-box-shadow: 0 1px 0 rgba(248, 248, 248, 0.9); box-shadow: 0 1px 0 rgba(248, 248, 248, 0.9); *zoom: 1; /* smaller treedropdown */ } +.cms-content-toolbar { min-height: 29px; display: block; margin: 0 0 8px 0; border-bottom: 1px solid #d0d3d5; -webkit-box-shadow: 0 1px 0 rgba(248, 248, 248, 0.9); -moz-box-shadow: 0 1px 0 rgba(248, 248, 248, 0.9); -o-box-shadow: 0 1px 0 rgba(248, 248, 248, 0.9); box-shadow: 0 1px 0 rgba(248, 248, 248, 0.9); *zoom: 1; /* smaller treedropdown */ } .cms-content-toolbar:after { content: "\0020"; display: block; height: 0; clear: both; overflow: hidden; visibility: hidden; } .cms-content-toolbar .cms-tree-view-modes { float: right; padding-top: 5px; } .cms-content-toolbar .cms-tree-view-modes * { display: inline-block; } @@ -489,7 +489,7 @@ p.message { margin-bottom: 12px; } .cms-content-toolbar .ss-ui-button { margin-bottom: 8px; } /* -------------------------------------------------------- Content Tools is the sidebar on the left of the main content panel */ -.cms-content-tools { background: #eceff1; width: 192px; overflow-y: auto; overflow-x: hidden; z-index: 70; border-right: 1px solid #c0c0c2; -webkit-box-shadow: rgba(248, 248, 248, 0.9) -1px 0 0 inset, 0 0 1px rgba(201, 205, 206, 0.8); -moz-box-shadow: rgba(248, 248, 248, 0.9) -1px 0 0 inset, 0 0 1px rgba(201, 205, 206, 0.8); box-shadow: rgba(248, 248, 248, 0.9) -1px 0 0 inset, 0 0 1px rgba(201, 205, 206, 0.8); float: left; position: relative; } +.cms-content-tools { background: #eceff1; width: 200px; overflow-y: auto; overflow-x: hidden; z-index: 70; border-right: 1px solid #c0c0c2; -webkit-box-shadow: rgba(248, 248, 248, 0.9) -1px 0 0 inset, 0 0 1px rgba(201, 205, 206, 0.8); -moz-box-shadow: rgba(248, 248, 248, 0.9) -1px 0 0 inset, 0 0 1px rgba(201, 205, 206, 0.8); box-shadow: rgba(248, 248, 248, 0.9) -1px 0 0 inset, 0 0 1px rgba(201, 205, 206, 0.8); float: left; position: relative; } .cms-content-tools.filter { padding: 0 !important; } .cms-content-tools .cms-panel-header { clear: both; margin: 0 0 7px; line-height: 24px; border-bottom: 1px solid #d0d3d5; -webkit-box-shadow: 0 1px 0 rgba(248, 248, 248, 0.9); -moz-box-shadow: 0 1px 0 rgba(248, 248, 248, 0.9); -o-box-shadow: 0 1px 0 rgba(248, 248, 248, 0.9); box-shadow: 0 1px 0 rgba(248, 248, 248, 0.9); } .cms-content-tools .cms-panel-content { width: 176px; padding: 8px 8px 0; overflow: auto; height: 100%; } @@ -517,7 +517,7 @@ p.message { margin-bottom: 12px; } .cms-content-tools td { border-bottom: 1px solid #ced7dc; padding: 7px 2px; font-size: 11px; } /** CMS Batch actions */ -.cms-content-batchactions { float: left; position: relative; display: block; margin-left: 8px; } +.cms-content-batchactions { float: left; position: relative; display: block; } .cms-content-batchactions .view-mode-batchactions-wrapper { float: left; padding: 4px 6px; border: 1px solid #aaa; margin-bottom: 8px; background-color: #D9D9D9; background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjUwJSIgeTE9IjAlIiB4Mj0iNTAlIiB5Mj0iMTAwJSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2ZmZmZmZiIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iI2Q5ZDlkOSIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=='); background-size: 100%; background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ffffff), color-stop(100%, #d9d9d9)); background-image: -webkit-linear-gradient(top, #ffffff, #d9d9d9); background-image: -moz-linear-gradient(top, #ffffff, #d9d9d9); background-image: -o-linear-gradient(top, #ffffff, #d9d9d9); background-image: linear-gradient(top, #ffffff, #d9d9d9); border-top-left-radius: 4px; border-bottom-left-radius: 4px; } .cms-content-batchactions .view-mode-batchactions-wrapper label { display: none; } .cms-content-batchactions .view-mode-batchactions-wrapper fieldset, .cms-content-batchactions .view-mode-batchactions-wrapper .Actions { display: inline-block; } @@ -661,7 +661,7 @@ body.cms-dialog { overflow: auto; background: url("../images/textures/bg_cms_mai /** -------------------------------------------- Step labels -------------------------------------------- */ .step-label > * { display: inline-block; vertical-align: top; } .step-label .flyout { height: 18px; font-size: 14px; font-weight: bold; -moz-border-radius-topleft: 3px; -webkit-border-top-left-radius: 3px; border-top-left-radius: 3px; -moz-border-radius-bottomleft: 3px; -webkit-border-bottom-left-radius: 3px; border-bottom-left-radius: 3px; background-color: #667980; padding: 4px 3px 4px 6px; text-align: center; text-shadow: none; color: #fff; } -.step-label .arrow { height: 26px; width: 10px; background: url('sprites-32x32-sf6890c994e.png') 0 -256px no-repeat; margin-right: 4px; } +.step-label .arrow { height: 26px; width: 10px; background: url('../images/sprites-32x32-sf6890c994e.png') 0 -256px no-repeat; margin-right: 4px; } .step-label .title { height: 18px; padding: 4px; } /** -------------------------------------------- Item Edit Form -------------------------------------------- */ @@ -705,10 +705,10 @@ form.import-form label.left { width: 250px; } /** -------------------------------------------- Buttons for FileUpload -------------------------------------------- */ .ss-uploadfield-item-edit-all .ui-button-text { padding-right: 0; } -.toggle-details-icon { background: url('sprites-32x32-sf6890c994e.png') 0 -433px no-repeat; } -.ss-uploadfield-item-edit-all .toggle-details-icon { background: url('sprites-32x32-sf6890c994e.png') 0 -375px no-repeat; display: inline-block; width: 8px; height: 8px; padding-left: 5px; } -.toggle-details-icon.opened { background: url('sprites-32x32-sf6890c994e.png') 0 -1121px no-repeat; } -.ss-uploadfield-item-edit-all .toggle-details-icon.opened { background: url('sprites-32x32-sf6890c994e.png') 0 -359px no-repeat; } +.toggle-details-icon { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -433px no-repeat; } +.ss-uploadfield-item-edit-all .toggle-details-icon { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -375px no-repeat; display: inline-block; width: 8px; height: 8px; padding-left: 5px; } +.toggle-details-icon.opened { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -1121px no-repeat; } +.ss-uploadfield-item-edit-all .toggle-details-icon.opened { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -359px no-repeat; } /** -------------------------------------------- Hide preview toggle link by default. May be shown in IE7 stylesheet and forced to show with js if needed -------------------------------------------- */ .cms .Actions > .cms-preview-toggle-link, .cms .cms-navigator > .cms-preview-toggle-link { display: none; } @@ -823,7 +823,7 @@ li.class-ErrorPage > a a .jstree-pageicon { background-position: 0 -112px; } .cms-logo span { font-weight: bold; font-size: 12px; line-height: 16px; padding: 2px 0; margin-left: 30px; } .cms-login-status { border-top: 1px solid #19435c; padding: 12px 0 17px; line-height: 16px; font-size: 11px; } -.cms-login-status .logout-link { display: inline-block; height: 16px; width: 16px; float: left; margin: 0 8px 0 5px; background: url('sprites-32x32-sf6890c994e.png') 0 -292px no-repeat; text-indent: -9999em; } +.cms-login-status .logout-link { display: inline-block; height: 16px; width: 16px; float: left; margin: 0 8px 0 5px; background: url('../images/sprites-32x32-sf6890c994e.png') 0 -292px no-repeat; text-indent: -9999em; } .cms-menu { z-index: 80; background: #b0bec7; width: 160px; -webkit-box-shadow: rgba(0, 0, 0, 0.9) 0 0 3px; -moz-box-shadow: rgba(0, 0, 0, 0.9) 0 0 3px; box-shadow: rgba(0, 0, 0, 0.9) 0 0 3px; } .cms-menu a { text-decoration: none; } @@ -847,12 +847,12 @@ li.class-ErrorPage > a a .jstree-pageicon { background-position: 0 -112px; } .cms-menu-list li a .icon { display: inline-block; float: left; margin: 4px 10px 0 4px; filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=70); opacity: 0.7; } .cms-menu-list li a .text { display: inline-block; float: left; } .cms-menu-list li a .toggle-children { display: inline-block; float: right; width: 20px; height: 100%; cursor: pointer; } -.cms-menu-list li a .toggle-children .toggle-children-icon { display: inline-block; width: 8px; height: 8px; background: url('sprites-32x32-sf6890c994e.png') 0 -375px no-repeat; vertical-align: middle; } -.cms-menu-list li a .toggle-children.opened .toggle-children-icon { background: url('sprites-32x32-sf6890c994e.png') 0 -359px no-repeat; } +.cms-menu-list li a .toggle-children .toggle-children-icon { display: inline-block; width: 8px; height: 8px; background: url('../images/sprites-32x32-sf6890c994e.png') 0 -375px no-repeat; vertical-align: middle; } +.cms-menu-list li a .toggle-children.opened .toggle-children-icon { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -359px no-repeat; } .cms-menu-list li ul li a { border-top: 1px solid #b6c3cb; } .cms-menu-list li.current a { color: white; text-shadow: #1e5270 0 -1px 0; border-top: 1px solid #55a4d2; border-bottom: 1px solid #236184; background-color: #338dc1; background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjUwJSIgeTE9IjAlIiB4Mj0iNTAlIiB5Mj0iMTAwJSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzMzOGRjMSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzI4NzA5OSIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=='); background-size: 100%; background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #338dc1), color-stop(100%, #287099)); background-image: -webkit-linear-gradient(#338dc1, #287099); background-image: -moz-linear-gradient(#338dc1, #287099); background-image: -o-linear-gradient(#338dc1, #287099); background-image: linear-gradient(#338dc1, #287099); } -.cms-menu-list li.current a .toggle-children .toggle-children-icon { background: url('sprites-32x32-sf6890c994e.png') 0 -433px no-repeat; } -.cms-menu-list li.current a .toggle-children.opened .toggle-children-icon { background: url('sprites-32x32-sf6890c994e.png') 0 -1121px no-repeat; } +.cms-menu-list li.current a .toggle-children .toggle-children-icon { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -433px no-repeat; } +.cms-menu-list li.current a .toggle-children.opened .toggle-children-icon { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -1121px no-repeat; } .cms-menu-list li.current ul { border-top: none; display: block; } .cms-menu-list li.current li { background-color: #287099; } .cms-menu-list li.current li a { font-size: 11px; padding: 0 10px 0 40px; height: 32px; line-height: 32px; color: #e2f0f7; background: none; border-top: 1px solid #2f81b1; border-bottom: 1px solid #1e5270; } @@ -875,14 +875,14 @@ li.class-ErrorPage > a a .jstree-pageicon { background-position: 0 -112px; } .cms-content-controls.cms-preview-controls { z-index: 1; background: #eceff1; height: 30px; /* should be set in js Layout to match page actions */ padding: 12px 12px; } .cms-content-controls .icon-view, .cms-content-controls .preview-selector.dropdown a.chzn-single { white-space: nowrap; } .cms-content-controls .icon-view:before, .cms-content-controls .preview-selector.dropdown a.chzn-single:before { display: inline-block; float: left; content: ''; width: 23px; height: 17px; overflow: hidden; } -.cms-content-controls .icon-auto:before { background: url('sprites-32x32-sf6890c994e.png') 0 -108px no-repeat; } -.cms-content-controls .icon-desktop:before { background: url('sprites-32x32-sf6890c994e.png') 0 -81px no-repeat; } -.cms-content-controls .icon-tablet:before { background: url('sprites-32x32-sf6890c994e.png') 0 -162px no-repeat; } -.cms-content-controls .icon-mobile:before { background: url('sprites-32x32-sf6890c994e.png') 0 -189px no-repeat; } -.cms-content-controls .icon-split:before { background: url('sprites-32x32-sf6890c994e.png') 0 -135px no-repeat; } -.cms-content-controls .icon-edit:before { background: url('sprites-32x32-sf6890c994e.png') 0 -27px no-repeat; } -.cms-content-controls .icon-preview:before { background: url('sprites-32x32-sf6890c994e.png') 0 0 no-repeat; } -.cms-content-controls .icon-window:before { background: url('sprites-32x32-sf6890c994e.png') 0 -54px no-repeat; } +.cms-content-controls .icon-auto:before { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -108px no-repeat; } +.cms-content-controls .icon-desktop:before { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -81px no-repeat; } +.cms-content-controls .icon-tablet:before { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -162px no-repeat; } +.cms-content-controls .icon-mobile:before { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -189px no-repeat; } +.cms-content-controls .icon-split:before { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -135px no-repeat; } +.cms-content-controls .icon-edit:before { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -27px no-repeat; } +.cms-content-controls .icon-preview:before { background: url('../images/sprites-32x32-sf6890c994e.png') 0 0 no-repeat; } +.cms-content-controls .icon-window:before { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -54px no-repeat; } .cms-content-controls .cms-navigator { width: 100%; } .cms-content-controls .preview-selector.dropdown a.chzn-single { text-indent: -200px; } .cms-content-controls .preview-selector { float: right; border-bottom: none; position: relative; -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; margin: 3px 0 0 4px; padding: 0; height: 28px; } @@ -920,7 +920,7 @@ li.class-ErrorPage > a a .jstree-pageicon { background-position: 0 -112px; } /* Styling for the preview screen sizes */ .cms-preview { background-color: #eceff1; height: 100%; width: 100%; } .cms-preview .preview-note { color: #CDD7DC; display: block; font-size: 22px; font-weight: bold; height: 82px; margin-top: -50px; margin-left: -150px; /* half of width */ position: absolute; text-align: center; text-shadow: 0 1px 0 #fff; top: 50%; left: 50%; width: 300px; } -.cms-preview .preview-note span { background: url('sprites-64x64-s88957ee578.png') 0 0 no-repeat; display: block; height: 41px; margin: 0 auto 20px; width: 50px; } +.cms-preview .preview-note span { background: url('../images/sprites-64x64-s88957ee578.png') 0 0 no-repeat; display: block; height: 41px; margin: 0 auto 20px; width: 50px; } .cms-preview .preview-scroll { height: 100%; overflow: auto; position: relative; width: 100%; } .cms-preview .preview-scroll .preview-device-outer { height: 100%; width: 100%; } .cms-preview .preview-scroll .preview-device-outer .preview-device-inner { -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box; width: 100%; height: 100%; } @@ -1028,10 +1028,10 @@ visible. Added and removed with js in TabSet.js */ /*************************** .cms .ss-ui-action-tabset.action-menus.ss-tabset ul.ui-tabs-nav li a { text-shadow: white 0 1px 1px; color: #0073c1; font-size: 13px; font-weight: normal; line-height: 24px; padding: 0 25px 0 10px; /* Arrow */ } .cms .ss-ui-action-tabset.action-menus.ss-tabset ul.ui-tabs-nav li a:hover, .cms .ss-ui-action-tabset.action-menus.ss-tabset ul.ui-tabs-nav li a:active { -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; outline: none; } .cms .ss-ui-action-tabset.action-menus.ss-tabset ul.ui-tabs-nav li a:hover { text-shadow: white 0 10px 10px; color: #005b98; } -.cms .ss-ui-action-tabset.action-menus.ss-tabset ul.ui-tabs-nav li a:after { background: url('sprites-32x32-sf6890c994e.png') 0 -1189px no-repeat; border-bottom: 0; content: ""; display: inline-block; height: 16px; margin-left: 6px; width: 16px; } -.cms .ss-ui-action-tabset.action-menus.ss-tabset ul.ui-tabs-nav li a:hover:after { background: url('sprites-32x32-sf6890c994e.png') 0 -1163px no-repeat; } -.cms .ss-ui-action-tabset.action-menus.ss-tabset ul.ui-tabs-nav li.ui-state-active a:after { background: url('sprites-32x32-sf6890c994e.png') 0 -1215px no-repeat; } -.cms .ss-ui-action-tabset.action-menus.ss-tabset ul.ui-tabs-nav li.ui-state-active a:hover:after { background: url('sprites-32x32-sf6890c994e.png') 0 -1137px no-repeat; } +.cms .ss-ui-action-tabset.action-menus.ss-tabset ul.ui-tabs-nav li a:after { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -1189px no-repeat; border-bottom: 0; content: ""; display: inline-block; height: 16px; margin-left: 6px; width: 16px; } +.cms .ss-ui-action-tabset.action-menus.ss-tabset ul.ui-tabs-nav li a:hover:after { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -1163px no-repeat; } +.cms .ss-ui-action-tabset.action-menus.ss-tabset ul.ui-tabs-nav li.ui-state-active a:after { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -1215px no-repeat; } +.cms .ss-ui-action-tabset.action-menus.ss-tabset ul.ui-tabs-nav li.ui-state-active a:hover:after { background: url('../images/sprites-32x32-sf6890c994e.png') 0 -1137px no-repeat; } .cms .ss-ui-action-tabset.action-menus.ss-tabset .ui-tabs-panel { overflow: hidden; *zoom: 1; -moz-border-radius-topleft: 3px; -webkit-border-top-left-radius: 3px; border-top-left-radius: 3px; -moz-border-radius-topright: 3px; -webkit-border-top-right-radius: 3px; border-top-right-radius: 3px; -moz-border-radius-bottomleft: 0; -webkit-border-bottom-left-radius: 0; border-bottom-left-radius: 0; -moz-border-radius-bottomright: 0; -webkit-border-bottom-right-radius: 0; border-bottom-right-radius: 0; /* Restyle for smaller area*/ clear: both; display: block; background-color: #eceff1; border: 1px solid #ccc; border-bottom: 1px solid #eceff1; margin: 0; margin-top: 2px; max-width: 250px; padding: 8px 0 2px; position: absolute; z-index: 1; min-width: 190px; } .cms .ss-ui-action-tabset.action-menus.ss-tabset .ui-tabs-panel h3, .cms .ss-ui-action-tabset.action-menus.ss-tabset .ui-tabs-panel h4, .cms .ss-ui-action-tabset.action-menus.ss-tabset .ui-tabs-panel h5 { font-weight: bold; line-height: 16px; } .cms .ss-ui-action-tabset.action-menus.ss-tabset .ui-tabs-panel h3 { font-size: 13px; } diff --git a/admin/scss/_style.scss b/admin/scss/_style.scss index 31265f62c..dc36c0447 100644 --- a/admin/scss/_style.scss +++ b/admin/scss/_style.scss @@ -609,8 +609,7 @@ p.message { .cms-content-toolbar { min-height: 29px; display: block; - margin: 0 0 15px 0; - padding-bottom: 9px; + margin: 0 0 $grid-y 0; @include doubleborder(bottom, $color-light-separator, $box-shadow-shine); @include legacy-pie-clearfix(); @@ -681,7 +680,7 @@ p.message { */ .cms-content-tools { background: $tab-panel-texture-color; - width: $grid-x * 24; + width: $grid-x * 25; overflow-y: auto; overflow-x: hidden; z-index: 70; @@ -837,7 +836,6 @@ p.message { float: left; position: relative; display: block; - margin-left: 8px; .view-mode-batchactions-wrapper { float: left; From a823c38c3f6ab12ecac0d358e65772b0e955608c Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Mon, 17 Dec 2012 11:31:39 +0100 Subject: [PATCH 15/73] Fixed JS syntax error --- admin/javascript/LeftAndMain.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/admin/javascript/LeftAndMain.js b/admin/javascript/LeftAndMain.js index 671e8e3cd..d90f991d0 100644 --- a/admin/javascript/LeftAndMain.js +++ b/admin/javascript/LeftAndMain.js @@ -8,7 +8,7 @@ jQuery.noConflict(); window.onresize = function(e) { // Entwine's 'fromWindow::onresize' does not trigger on IE8. Use synthetic event. $('.cms-container').trigger('windowresize'); - } + }; // setup jquery.entwine $.entwine.warningLevel = $.entwine.WARN_LEVEL_BESTPRACTISE; @@ -33,7 +33,7 @@ jQuery.noConflict(); disable_search_threshold: 20 }); - var title = el.prop('title') + var title = el.prop('title'); if(title) { el.siblings('.chzn-container').prop('title', title); @@ -149,7 +149,7 @@ jQuery.noConflict(); }, fromWindow: { - onstatechange: function(){ this.handleStateChange(); }, + onstatechange: function(){ this.handleStateChange(); } }, 'onwindowresize': function() { @@ -577,7 +577,7 @@ jQuery.noConflict(); * Requires HTML5 sessionStorage support. */ saveTabState: function() { - if(typeof(window.sessionStorage)=="undefined" || window.sessionStorage == null) return; + if(typeof(window.sessionStorage)=="undefined" || window.sessionStorage === null) return; var selectedTabs = [], url = this._tabStateUrl(); this.find('.cms-tabset,.ss-tabset').each(function(i, el) { @@ -613,7 +613,7 @@ jQuery.noConflict(); * Requires HTML5 sessionStorage support. */ restoreTabState: function() { - if(typeof(window.sessionStorage)=="undefined" || window.sessionStorage == null) return; + if(typeof(window.sessionStorage)=="undefined" || window.sessionStorage === null) return; var self = this, url = this._tabStateUrl(), data = window.sessionStorage.getItem('tabs-' + url), @@ -735,7 +735,7 @@ jQuery.noConflict(); var msg = (xmlhttp.getResponseHeader('X-Status')) ? xmlhttp.getResponseHeader('X-Status') : xmlhttp.responseText; try { - if (typeof msg != "undefined" && msg != null) eval(msg); + if (typeof msg != "undefined" && msg !== null) eval(msg); } catch(e) {} From e8f3e7b36e09bb8cb050589392caaf902e321ca6 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Fri, 14 Dec 2012 11:45:26 +0100 Subject: [PATCH 16/73] Only reset test state in SapphireTest if its previously been set That's not the case e.g. if the *first* test in a suite is skipped, so setUp() is never executed completely. --- dev/SapphireTest.php | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/dev/SapphireTest.php b/dev/SapphireTest.php index 463b3ea46..5e5d75a77 100644 --- a/dev/SapphireTest.php +++ b/dev/SapphireTest.php @@ -460,22 +460,30 @@ class SapphireTest extends PHPUnit_Framework_TestCase { ini_set('memory_limit', ($this->originalMemoryLimit) ? $this->originalMemoryLimit : -1); // Restore email configuration - Email::set_mailer($this->originalMailer); - $this->originalMailer = null; - $this->mailer = null; + if($this->originalMailer) { + Email::set_mailer($this->originalMailer); + $this->originalMailer = null; + } + $this->mailer = null; // Restore password validation - Member::set_password_validator($this->originalMemberPasswordValidator); + if($this->originalMemberPasswordValidator) { + Member::set_password_validator($this->originalMemberPasswordValidator); + } // Restore requirements - Requirements::set_backend($this->originalRequirements); + if($this->originalRequirements) { + Requirements::set_backend($this->originalRequirements); + } // Mark test as no longer being run - we use originalIsRunningTest to allow for nested SapphireTest calls self::$is_running_test = $this->originalIsRunningTest; $this->originalIsRunningTest = null; // Reset theme setting - SSViewer::set_theme($this->originalTheme); + if($this->originalTheme) { + SSViewer::set_theme($this->originalTheme); + } // Reset mocked datetime SS_Datetime::clear_mock_now(); From 3b59d4a7628ab984505fd2a0e37a85ec9ef976c5 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Mon, 17 Dec 2012 11:45:09 +0100 Subject: [PATCH 17/73] Updated translations --- lang/af.yml | 632 ++++++++++++++++++++++++------------------------- lang/ast.yml | 2 +- lang/bg.yml | 174 +++++++------- lang/cs.yml | 12 +- lang/de.yml | 8 +- lang/en.yml | 6 +- lang/fi.yml | 6 +- lang/fr.yml | 30 +-- lang/it.yml | 58 ++--- lang/ja_JP.yml | 2 +- lang/mi_NZ.yml | 10 +- lang/nl.yml | 26 +- lang/ro.yml | 2 +- lang/sk.yml | 28 +-- 14 files changed, 496 insertions(+), 500 deletions(-) diff --git a/lang/af.yml b/lang/af.yml index 9cd84e9f4..62f371557 100644 --- a/lang/af.yml +++ b/lang/af.yml @@ -1,98 +1,98 @@ af: AssetAdmin: ALLOWEDEXTS: 'Allowed extensions' - NEWFOLDER: NewFolder + NEWFOLDER: 'Nuwe Dossier' AssetTableField: - CREATED: 'First uploaded' - DIM: Dimensions - FILENAME: Filename - FOLDER: Folder - LASTEDIT: 'Last changed' - OWNER: Owner - SIZE: 'File size' - TITLE: Title - TYPE: 'File type' + CREATED: 'Eerste opgelaai' + DIM: Afmetings + FILENAME: 'Lêer naam' + FOLDER: Dossier + LASTEDIT: 'Laaste verander' + OWNER: Eienaar + SIZE: 'Lêer grootte' + TITLE: Titel + TYPE: 'Lêer tipe' URL: URL AssetUploadField: - ChooseFiles: 'Choose files' - DRAGFILESHERE: 'Drag files here' - DROPAREA: 'Drop Area' - EDITALL: 'Edit all' - EDITANDORGANIZE: 'Edit & organize' - EDITINFO: 'Edit files' - FILES: Files - FROMCOMPUTER: 'Choose files from your computer' - FROMCOMPUTERINFO: 'Upload from your computer' - TOTAL: Total - TOUPLOAD: 'Choose files to upload...' + ChooseFiles: 'Kies lêers' + DRAGFILESHERE: 'Trek lêers hiernatoe' + DROPAREA: 'Laat val area' + EDITALL: 'Verander alles' + EDITANDORGANIZE: 'Verander en organiseer' + EDITINFO: 'Verander lêers' + FILES: Lêers + FROMCOMPUTER: 'Kies lêers van jou rekenaar af' + FROMCOMPUTERINFO: 'Laai op van jou rekenaar af' + TOTAL: Totaal + TOUPLOAD: 'Kies lêers om op te laai...' UPLOADINPROGRESS: 'Please wait… upload in progress' - UPLOADOR: OR + UPLOADOR: OF BBCodeParser: ALIGNEMENT: Belyning - ALIGNEMENTEXAMPLE: 'right aligned' + ALIGNEMENTEXAMPLE: 'Rig na regs' BOLD: 'Vet Teks' BOLDEXAMPLE: Vet - CODE: 'Code Block' - CODEDESCRIPTION: 'Unformatted code block' - CODEEXAMPLE: 'Code block' + CODE: 'Kode blok' + CODEDESCRIPTION: 'Ongeformateerde kode blok' + CODEEXAMPLE: 'Kode blok' COLORED: 'Gekleurde teks' COLOREDEXAMPLE: 'blou teks' - EMAILLINK: 'Email link' - EMAILLINKDESCRIPTION: 'Create link to an email address' - IMAGE: Image - IMAGEDESCRIPTION: 'Show an image in your post' + EMAILLINK: 'Epos skakel' + EMAILLINKDESCRIPTION: 'Skep skakel na epos adres' + IMAGE: 'Geen prentjie gelaai nie' + IMAGEDESCRIPTION: 'Wys ''n foto in wat jy gepos het' ITALIC: 'Skuinsstrepe Teks' ITALICEXAMPLE: Skuinsstrepe - LINK: 'Website link' - LINKDESCRIPTION: 'Link to another website or URL' + LINK: 'Webwerf skakel' + LINKDESCRIPTION: 'Koppel aan ''n ander webwerf of URL' STRUCK: 'Deur-gestreepde Teks' STRUCKEXAMPLE: Deur-gestreep UNDERLINE: 'Beklemtoonde Teks' UNDERLINEEXAMPLE: Beklemtoon - UNORDERED: 'Unordered list' - UNORDEREDDESCRIPTION: 'Unordered list' - UNORDEREDEXAMPLE1: 'unordered item 1' + UNORDERED: 'Ongeorganiseerde lys' + UNORDEREDDESCRIPTION: 'Ongeorganiseerde lys' + UNORDEREDEXAMPLE1: 'Ongeorganiseerde item 1' BackLink_Button.ss: - Back: Back + Back: Terug BasicAuth: - ENTERINFO: 'Please enter a username and password.' - ERRORNOTADMIN: 'That user is not an administrator.' - ERRORNOTREC: 'That username / password isn''t recognised' + ENTERINFO: 'Tik asseblief ''n verbruikersnaam en wagwoord in' + ERRORNOTADMIN: 'Daardie verbruiker is nie ''n administreerder nie' + ERRORNOTREC: 'Daar die verbruikersnaam / wagwoord is nie herken nie' Boolean: - 0: 'False' - ANY: Any - 1: 'True' + 0: Onwaar + ANY: Enige + 1: Waar CMSLoadingScreen.ss: - LOADING: Loading... - REQUIREJS: 'The CMS requires that you have JavaScript enabled.' + LOADING: 'Besig om te laai...' + REQUIREJS: 'Die IBS vereis dat JavaScript aangeskakel is' CMSMain: ACCESS: 'Access to ''{title}'' section' - ACCESSALLINTERFACES: 'Access to all CMS sections' - ACCESSALLINTERFACESHELP: 'Overrules more specific access settings.' - SAVE: Save + ACCESSALLINTERFACES: 'Toegang tot alle IBS gedeeltes' + ACCESSALLINTERFACESHELP: 'Oorheers meer spesifieke toegans verstellings' + SAVE: Stoor CMSProfileController: - MENUTITLE: 'My Profile' + MENUTITLE: 'My profiel' ChangePasswordEmail.ss: CHANGEPASSWORDTEXT1: 'U het die wagwoord vir' - CHANGEPASSWORDTEXT2: 'You can now use the following credentials to log in:' - EMAIL: Email - HELLO: Hi - PASSWORD: Password + CHANGEPASSWORDTEXT2: 'Jy kan nou die volgende sekuriteitsbesonderhede gebruik om in te teken' + EMAIL: Epos + HELLO: 'Hi daar' + PASSWORD: Wagwoord CheckboxField: - - 'False' - - 'True' + - Onwaar + - Waar ComplexTableField: - CLOSEPOPUP: 'Close Popup' - SUCCESSADD2: 'Added {name}' - SUCCESSEDIT: 'Saved %s %s %s' + CLOSEPOPUP: 'Maak wipop toe' + SUCCESSADD2: '{name} bygesit' + SUCCESSEDIT: 'Gestoor %s %s %s' ComplexTableField.ss: ADDITEM: 'Byvoeg %s' - NOITEMSFOUND: 'No items found' - SORTASC: 'Sort ascending' - SORTDESC: 'Sort descending' + NOITEMSFOUND: 'Geen item gevind nie' + SORTASC: 'Sorteer in stygende orde' + SORTDESC: 'Sorteer in dalende orde' ComplexTableField_popup.ss: - NEXT: Next - PREVIOUS: Previous + NEXT: Volgende + PREVIOUS: Vorige ConfirmedPasswordField: ATLEAST: 'Passwords must be at least {min} characters long.' BETWEEN: 'Passwords must be {min} to {max} characters long.' @@ -109,20 +109,20 @@ af: PLURALNAME: 'Data Voorwerpe' SINGULARNAME: 'Data Voorwerp' Date: - DAY: ' day' - DAYS: ' days' - HOUR: ' hour' - HOURS: ' hours' - MIN: ' min' - MINS: ' mins' - MONTH: ' month' - MONTHS: ' months' - SEC: ' sec' - SECS: ' secs' - TIMEDIFFAGO: '{difference} ago' + DAY: dag + DAYS: dae + HOUR: uur + HOURS: ure + MIN: minuut + MINS: minute + MONTH: maand + MONTHS: maande + SEC: sekonde + SECS: sekondes + TIMEDIFFAGO: '{difference} terug' TIMEDIFFIN: 'in {difference}' - YEAR: ' year' - YEARS: ' years' + YEAR: jaar + YEARS: jare DateField: NOTSET: 'nier gestel' TODAY: vandag @@ -130,68 +130,68 @@ af: VALIDDATEMAXDATE: 'Your date has to be older or matching the maximum allowed date ({date})' VALIDDATEMINDATE: 'Your date has to be newer or matching the minimum allowed date ({date})' DatetimeField: - NOTSET: 'Not set' + NOTSET: 'Nie gestel nie' Director: - INVALID_REQUEST: 'Invalid request' + INVALID_REQUEST: 'Ongeldige versoek' DropdownField: CHOOSE: (Kies) EmailField: - VALIDATION: 'Please enter an email address' + VALIDATION: 'Verskaf asseblief ''n epos adres ' Email_BounceRecord: - PLURALNAME: 'Email Bounce Records' - SINGULARNAME: 'Email Bounce Record' + PLURALNAME: 'Epos hop rekords' + SINGULARNAME: 'Epos hop rekord' Enum: - ANY: Any + ANY: Enige File: AviType: 'AVI video file' - Content: Content - CssType: 'CSS file' + Content: Inhoud + CssType: 'CSS lêer' DmgType: 'Apple disk image' - DocType: 'Word document' - Filename: Filename + DocType: 'Word dokument' + Filename: 'Lêer naam' GifType: 'GIF image - good for diagrams' GzType: 'GZIP compressed file' - HtlType: 'HTML file' + HtlType: 'HTML lêer' HtmlType: 'HTML file' INVALIDEXTENSION: 'Extension is not allowed (valid: {extensions})' INVALIDEXTENSIONSHORT: 'Extension is not allowed' - IcoType: 'Icon image' - JpgType: 'JPEG image - good for photos' + IcoType: 'Ikoon prentjie' + JpgType: 'JPEG prentjie - werk goed vir fotos' JsType: 'Javascript file' - Mp3Type: 'MP3 audio file' + Mp3Type: 'MP3 klank lêer' MpgType: 'MPEG video file' NOFILESIZE: 'Lêergrootte is nul grepe.' - NOVALIDUPLOAD: 'File is not a valid upload' - Name: Name + NOVALIDUPLOAD: 'Lêer is nie geld vir oplaai nie' + Name: Naam PLURALNAME: Lêers PdfType: 'Adobe Acrobat PDF file' PngType: 'PNG image - good general-purpose format' SINGULARNAME: Lêer TOOLARGE: 'Filesize is too large, maximum {size} allowed' - TOOLARGESHORT: 'Filesize exceeds {size}' + TOOLARGESHORT: 'Lêer is groter as {size}' TiffType: 'Tagged image format' - Title: Title - WavType: 'WAV audo file' + Title: Titel + WavType: 'WAV klank lêer' XlsType: 'Excel spreadsheet' ZipType: 'ZIP compressed file' FileIFrameField: - ATTACH: 'Attach {type}' - ATTACHONCESAVED: '{type}s can be attached once you have saved the record for the first time.' + ATTACH: 'Heg {type} aan' + ATTACHONCESAVED: '{type}e kan aangeheg word sodra jy die rekord vir die eerste keer gestoor het' ATTACHONCESAVED2: 'Files can be attached once you have saved the record for the first time.' - DELETE: 'Delete {type}' - DISALLOWEDFILETYPE: 'This filetype is not allowed to be uploaded' - FILE: File - FROMCOMPUTER: 'From your Computer' - FROMFILESTORE: 'From the File Store' + DELETE: 'Verwyder {type}' + DISALLOWEDFILETYPE: 'Dit word nie toegelaat om hierde lêer tipe op te laai nie' + FILE: Lêer + FROMCOMPUTER: 'Van jou rekenaar' + FROMFILESTORE: 'Vanuit die lêer stoor' NOSOURCE: 'Kies asseblief ''n bron lêer om by te voeg' - REPLACE: 'Replace {type}' + REPLACE: 'Vervang {type}' FileIFrameField_iframe.ss: - TITLE: 'Image Uploading Iframe' + TITLE: 'Prentjie oplaaiende ''Iframe''' Filesystem: SYNCRESULTS: 'Sync complete: {createdcount} items created, {deletedcount} items deleted' Folder: - PLURALNAME: Folders - SINGULARNAME: Folder + PLURALNAME: Dossiers + SINGULARNAME: Dossier ForgotPasswordEmail.ss: HELLO: Hi TEXT1: 'Hier is u' @@ -199,214 +199,214 @@ af: TEXT3: vir Form: FIELDISREQUIRED: '%s word benodig.' - SubmitBtnLabel: Go + SubmitBtnLabel: Gaan VALIDATIONCREDITNUMBER: 'Please ensure you have entered the {number} credit card number correctly' VALIDATIONNOTUNIQUE: 'The waarde wat ingesleutel is is nie uniek nie' VALIDATIONPASSWORDSDONTMATCH: 'Wagwoorde pas nie' VALIDATIONPASSWORDSNOTEMPTY: 'Wagwoorde kan nie leeg wees nie' - VALIDATIONSTRONGPASSWORD: 'Passwords must have at least one digit and one alphanumeric character' + VALIDATIONSTRONGPASSWORD: 'Wagwoorde moet minstens een nommer en een alfa-numeriese karaketer bevat' VALIDATOR: Vergeldiger - VALIDCURRENCY: 'Please enter a valid currency' + VALIDCURRENCY: 'Tik asseblief ''n geldige geldeenheid in ' FormField: NONE: geen GridAction: - DELETE_DESCRIPTION: Delete - Delete: Delete - UnlinkRelation: Unlink + DELETE_DESCRIPTION: Verwyder + Delete: Verwyder + UnlinkRelation: Ontkoppel GridField: - Add: 'Add {name}' + Add: 'Voeg {name}' Filter: Filter FilterBy: 'Filter by ' - Find: Find - LEVELUP: 'Level up' - LinkExisting: 'Link Existing' - NewRecord: 'New %s' - NoItemsFound: 'No items found' - PRINTEDAT: 'Printed at' - PRINTEDBY: 'Printed by' - PlaceHolder: 'Find {type}' + Find: Vind + LEVELUP: 'Op een vlak' + LinkExisting: 'Koppel bestaande' + NewRecord: 'Nuwe %s' + NoItemsFound: 'Geen items gevind nie' + PRINTEDAT: 'Gedruk te' + PRINTEDBY: 'Gedruk deur' + PlaceHolder: 'Vind {type}' PlaceHolderWithLabels: 'Find {type} by {name}' - RelationSearch: 'Relation search' - ResetFilter: Reset + RelationSearch: 'Soek vir verwantskap' + ResetFilter: Herstel GridFieldAction_Delete: - DeletePermissionsFailure: 'No delete permissions' + DeletePermissionsFailure: 'Geen toestemming om te verwyder nie' GridFieldDetailForm: - CancelBtn: Cancel - Create: Create - Delete: Delete - DeletePermissionsFailure: 'No delete permissions' - Deleted: 'Deleted %s %s' - Save: Save - Saved: 'Saved %s %s' + CancelBtn: 'Kanselleer ' + Create: Skep + Delete: Verwyder + DeletePermissionsFailure: 'Geen toestemming om te verwyder nie' + Deleted: 'Verwyderde %s %s' + Save: Stoor + Saved: 'Gestoor %s %s' GridFieldItemEditView.ss: null Group: - AddRole: 'Add a role for this group' + AddRole: 'Voeg nog ''n rol by hierdie groep' Code: 'Groep Kode' DefaultGroupTitleAdministrators: Administrateurs DefaultGroupTitleContentAuthors: 'Inhouds Outeurs' - Description: Description - GroupReminder: 'If you choose a parent group, this group will take all it''s roles' + Description: Beskrywing + GroupReminder: 'As jy ''n ouer groep kies sal hierdie groep al daardie rolle aanneem' Locked: 'Gesluit?' - NoRoles: 'No roles found' - PLURALNAME: Groups + NoRoles: 'Geen rolle gevind nie' + PLURALNAME: Groepe Parent: 'Ouer Groep' - RolesAddEditLink: 'Manage roles' - SINGULARNAME: Group - Sort: 'Sort Order' + RolesAddEditLink: 'Bestuur rolle' + SINGULARNAME: Groep + Sort: 'Sorteerings orde' has_many_Permissions: Toestemmings many_many_Members: Lidde GroupImportForm: - Help1: '

Import one or more groups in CSV format (comma-separated values). Show advanced usage

' + Help1: '

Voer een of meer groepe in CSVformaat (komma geskeide waardes). Wys gevorderde gebruike

' Help2: '

Advanced usage

  • Allowed columns: %s
  • Existing groups are matched by their unique Code value, and updated with any new values from the imported file
  • Group hierarchies can be created by using a ParentCode column.
  • Permission codes can be assigned by the PermissionCode column. Existing permission codes are not cleared.
' ResultCreated: 'Created {count} groups' - ResultDeleted: 'Deleted %d groups' - ResultUpdated: 'Updated %d groups' + ResultDeleted: 'Verwyderde %d groepe' + ResultUpdated: '%d Groepe was opgedateer' Hierarchy: InfiniteLoopNotAllowed: 'Infinite loop found within the "{type}" hierarchy. Please change the parent to resolve this' HtmlEditorField: ADDURL: 'Add URL' ADJUSTDETAILSDIMENSIONS: 'Details & dimensions' ANCHORVALUE: Anker - BUTTONINSERT: Insert - BUTTONINSERTLINK: 'Insert link' - BUTTONREMOVELINK: 'Remove link' - BUTTONUpdate: Update - CAPTIONTEXT: 'Caption text' - CSSCLASS: 'Alignment / style' - CSSCLASSCENTER: 'Centered, on its own.' - CSSCLASSLEFT: 'On the left, with text wrapping around.' + BUTTONINSERT: 'Plaas in' + BUTTONINSERTLINK: 'Sit in' + BUTTONREMOVELINK: 'Verwyder skakel' + BUTTONUpdate: Verander + CAPTIONTEXT: 'Onderskrif teks' + CSSCLASS: 'Belyning styl' + CSSCLASSCENTER: 'In die middel op sy eie' + CSSCLASSLEFT: ' Links met teks wat rondom vloei' CSSCLASSLEFTALONE: 'Op die linkerkant, op sy eie.' - CSSCLASSRIGHT: 'On the right, with text wrapping around.' - DETAILS: Details - EMAIL: 'Email address' - FILE: File - FOLDER: Folder - FROMCMS: 'From the CMS' - FROMCOMPUTER: 'From your computer' + CSSCLASSRIGHT: 'Regs met teks wat rondom vloei' + DETAILS: Besonderhede + EMAIL: 'Epos Adres' + FILE: Lêer + FOLDER: Dossier + FROMCMS: 'Van die IBS' + FROMCOMPUTER: 'Van you rekenaar' FROMWEB: 'From the web' - FindInFolder: 'Find in Folder' + FindInFolder: 'Find in dossier' IMAGEALT: 'Alternative text (alt)' - IMAGEALTTEXT: 'Alternative text (alt) - shown if image cannot be displayed' + IMAGEALTTEXT: 'Alternatiewe teks (alt) - word gewys as prentjie nie beskikbaar is nie' IMAGEALTTEXTDESC: 'Shown to screen readers or if image can not be displayed' - IMAGEDIMENSIONS: Dimensions - IMAGEHEIGHTPX: Height - IMAGETITLE: 'Title text (tooltip) - for additional information about the image' - IMAGETITLETEXT: 'Title text (tooltip)' + IMAGEDIMENSIONS: Afmetings + IMAGEHEIGHTPX: Hoogte + IMAGETITLE: 'Titel teks (leidraad) - vir addisionele informasie oor die prentjie' + IMAGETITLETEXT: 'Titel teks (leidraad)' IMAGETITLETEXTDESC: 'For additional information about the image' - IMAGEWIDTHPX: Width - INSERTMEDIA: 'Insert Media' - LINK: 'Insert Link' + IMAGEWIDTHPX: Wydte + INSERTMEDIA: 'Voeg Media In' + LINK: 'Sit skakel in' LINKANCHOR: 'Anker op hierdie bladsy' - LINKDESCR: 'Link description' - LINKEMAIL: 'Email address' - LINKEXTERNAL: 'Another website' - LINKFILE: 'Download a file' - LINKINTERNAL: 'Page on the site' - LINKOPENNEWWIN: 'Open link in a new window?' - LINKTO: 'Link to' - PAGE: Page + LINKDESCR: 'Skakel beskrywing' + LINKEMAIL: 'Epos Adres' + LINKEXTERNAL: 'Ander webwerf' + LINKFILE: 'Laai ''n lêer af' + LINKINTERNAL: 'Bladsy op die webwerf' + LINKOPENNEWWIN: 'Wil jy die skakel in ''n nuwe venster oop maak?' + LINKTO: 'Koppel aan' + PAGE: Bladsy URL: URL URLNOTANOEMBEDRESOURCE: 'The URL ''{url}'' could not be turned into a media resource.' - UpdateMEDIA: 'Update Media' + UpdateMEDIA: 'Verander Media' Image: - PLURALNAME: Files - SINGULARNAME: File + PLURALNAME: Lêers + SINGULARNAME: Lêer ImageField: - IMAGE: Image + IMAGE: 'Geen prentjie gelaai nie' Image_Cached: - PLURALNAME: Files - SINGULARNAME: File + PLURALNAME: Lêers + SINGULARNAME: Lêer Image_iframe.ss: - TITLE: 'Image Uploading Iframe' + TITLE: 'Iframe wat fotos laai' LeftAndMain: CANT_REORGANISE: 'You do not have permission to alter Top level pages. Your change was not saved.' - DELETED: Deleted. - DropdownBatchActionsDefault: Actions + DELETED: 'Was verwyder' + DropdownBatchActionsDefault: Aksies HELP: Help - PAGETYPE: 'Page type: ' - PERMAGAIN: 'You have been logged out of the CMS. If you would like to log in again, enter a username and password below.' - PERMALREADY: 'I''m sorry, but you can''t access that part of the CMS. If you want to log in as someone else, do so below' + PAGETYPE: 'Bladsy tipe:' + PERMAGAIN: 'Jy is uit die IBS uitgeteken. As jy weer wil inteken, moet jy ''n gebruikersnaam en wagwoord onder in tik' + PERMALREADY: 'Ek is jammer, maar jy het nie toestemming om dié gedeelte van die IBS te besugtig nie. As jy as iemand anders wil inteken doen so hieronder' PERMDEFAULT: 'Please choose an authentication method and enter your credentials to access the CMS.' - PLEASESAVE: 'Please Save Page: This page could not be upated because it hasn''t been saved yet.' - PreviewButton: Preview + PLEASESAVE: 'Stoor asseblief die bladsy: Die bladsy kon nie opgedateer word nie omdat dit nog nie gestoor is nie' + PreviewButton: Beskou REORGANISATIONSUCCESSFUL: 'Reorganised the site tree successfully.' - SAVEDUP: Saved. + SAVEDUP: Gestoor VersionUnknown: Unknown LeftAndMain_Menu.ss: Hello: Hi - LOGOUT: 'Log out' + LOGOUT: 'Teken af' LoginAttempt: - Email: 'Email Address' - IP: 'IP Address' - PLURALNAME: 'Login Attempts' - SINGULARNAME: 'Login Attempt' - Status: Status + Email: 'Epos Adres' + IP: 'IP Adres' + PLURALNAME: 'Inteken Pogings' + SINGULARNAME: 'Inteken Poging' + Status: Posisie Member: - ADDGROUP: 'Add group' + ADDGROUP: 'Voeg groep by' BUTTONCHANGEPASSWORD: 'Verander Wagwoord' - BUTTONLOGIN: 'Log in' - BUTTONLOGINOTHER: 'Log in as someone else' - BUTTONLOSTPASSWORD: 'I''ve lost my password' - CANTEDIT: 'You don''t have permission to do that' + BUTTONLOGIN: 'Teken in' + BUTTONLOGINOTHER: 'Teken in as iemand anders' + BUTTONLOSTPASSWORD: 'Ek het my wagwoord verloor' + CANTEDIT: 'Jy het nie toestemming om dit te doen nie' CONFIRMNEWPASSWORD: 'Bevestig Nuwe Wagwoord' CONFIRMPASSWORD: 'Bevestig wagwoord' - DATEFORMAT: 'Date format' + DATEFORMAT: 'Datum formaat' DefaultAdminFirstname: 'Verstek Admin' - DefaultDateTime: default + DefaultDateTime: Gewone EMAIL: Epos - EMPTYNEWPASSWORD: 'The new password can''t be empty, please try again' - ENTEREMAIL: 'Please enter an email address to get a password reset link.' - ERRORLOCKEDOUT: 'Your account has been temporarily disabled because of too many failed attempts at logging in. Please try again in 20 minutes.' - ERRORNEWPASSWORD: 'You have entered your new password differently, try again' + EMPTYNEWPASSWORD: 'Die nuwe wagwoord kan nie leeg wees nie. Probeer asseblief weer' + ENTEREMAIL: 'Verskaf asseblief ''n epos adres sodat ons vir u ''n wagwoord herstel skakel kan epos' + ERRORLOCKEDOUT: 'Jou rekening is tydelik onklaar gemaak weens die feit dat jy te veel keer verkeerdelik probeer inteken het. Probeer asseblief weer in 20 minute.' + ERRORNEWPASSWORD: 'Jy het jou nuwe wagwoord anders ingetik. Probeer weer' ERRORPASSWORDNOTMATCH: 'U huidige wagwoord pas nie, probeer asseblief weer' - ERRORWRONGCRED: 'That doesn''t seem to be the right e-mail address or password. Please try again.' - FIRSTNAME: 'First Name' + ERRORWRONGCRED: 'Dit blyk nie of dit die regte e-pos adres of wagwoord is nie. Probeer asseblief weer.' + FIRSTNAME: Voornaam INTERFACELANG: 'Koppelvlak Taal' INVALIDNEWPASSWORD: 'We couldn''t accept that password: {password}' - LOGGEDINAS: 'You''re logged in as {name}.' + LOGGEDINAS: 'Jy is ingeteken as {name}' NEWPASSWORD: 'Nuwe wagwoord' - PASSWORD: Password + PASSWORD: Wagwoord PLURALNAME: Lidde - REMEMBERME: 'Remember me next time?' + REMEMBERME: 'Onthou volgende keer vir my?' SINGULARNAME: Lid SUBJECTPASSWORDCHANGED: 'U wagwoord het verander.' SUBJECTPASSWORDRESET: 'U wagwoord herlaai skakel' - SURNAME: Surname - TIMEFORMAT: 'Time format' - VALIDATIONMEMBEREXISTS: 'A member already exists with the same %s' + SURNAME: Van + TIMEFORMAT: 'Tyd formaat' + VALIDATIONMEMBEREXISTS: '''n Ander lid bestaan al klaar met dieselfde %s' ValidationIdentifierFailed: 'Can''t overwrite existing member #{id} with identical identifier ({name} = {value}))' - WELCOMEBACK: 'Welcome Back, {firstname}' + WELCOMEBACK: 'Welkom terug, {firstname}' YOUROLDPASSWORD: 'U ou wagwoord' belongs_many_many_Groups: Groepe - db_LastVisited: 'Last Visited Date' + db_LastVisited: 'Laaste datum besoek' db_Locale: 'Interface Locale' db_LockedOutUntil: 'Utgesluit tot en met' - db_NumVisit: 'Number of Visits' - db_Password: Password + db_NumVisit: 'Aantal besoeke' + db_Password: Wagwoord db_PasswordExpiry: 'Wagwoord Vervaldatum' MemberAuthenticator: - TITLE: 'E-mail & Password' + TITLE: 'Epos & Wagwoord' MemberDatetimeOptionsetField: - AMORPM: 'AM (Ante meridiem) or PM (Post meridiem)' - 'APPLY FILTER': 'Apply Filter' - Custom: Custom - DATEFORMATBAD: 'Date format is invalid' - DAYNOLEADING: 'Day of month without leading zero' + AMORPM: 'AM (Oggend) of PM (Middag)' + 'APPLY FILTER': 'Wend filter aan' + Custom: 'Maak pas' + DATEFORMATBAD: 'Die datum formaat is ongeldig' + DAYNOLEADING: 'Dag van die maand sonder ''n zero vooraan' DIGITSDECFRACTIONSECOND: 'One or more digits representing a decimal fraction of a second' - FOURDIGITYEAR: 'Four-digit year' - FULLNAMEMONTH: 'Full name of month (e.g. June)' + FOURDIGITYEAR: 'View syfer jaar' + FULLNAMEMONTH: 'Volle naam van maand (bv Junie)' HOURNOLEADING: 'Hour without leading zero' MINUTENOLEADING: 'Minute without leading zero' MONTHNOLEADING: 'Month digit without leading zero' - Preview: Preview + Preview: Voorskou SHORTMONTH: 'Short name of month (e.g. Jun)' - TOGGLEHELP: 'Toggle formatting help' - TWODIGITDAY: 'Two-digit day of month' + TOGGLEHELP: 'Skakel formateringshelp aan' + TWODIGITDAY: 'Twee syfer dag van die maand' TWODIGITHOUR: 'Two digits of hour (00 through 23)' TWODIGITMINUTE: 'Two digits of minute (00 through 59)' TWODIGITMONTH: 'Two-digit month (01=January, etc.)' TWODIGITSECOND: 'Two digits of second (00 through 59)' - TWODIGITYEAR: 'Two-digit year' + TWODIGITYEAR: 'Twee syfer jaar' MemberImportForm: Help1: '

Import users in CSV format (comma-separated values). Show advanced usage

' Help2: '

Advanced usage

  • Allowed columns: %s
  • Existing users are matched by their unique Code property, and updated with any new values from the imported file.
  • Groups can be assigned by the Groups column. Groups are identified by their Code property, multiple groups can be separated by comma. Existing group memberships are not cleared.
' @@ -415,58 +415,58 @@ af: ResultNone: 'Geen veranderinge' ResultUpdated: 'Updated {count} members' MemberPassword: - PLURALNAME: 'Member Passwords' - SINGULARNAME: 'Member Password' + PLURALNAME: 'Lid Wagwoorde' + SINGULARNAME: 'Lid Wagwoord' MemberTableField: null ModelAdmin: - DELETE: Delete - DELETEDRECORDS: 'Deleted {count} records.' - EMPTYBEFOREIMPORT: 'Clear Database before import' - IMPORT: 'Import from CSV' + DELETE: Verwyder + DELETEDRECORDS: 'Verwyder {count} rekords' + EMPTYBEFOREIMPORT: 'Maak databasis skoon voordat data ingevoer word' + IMPORT: 'Voer in van CSV' IMPORTEDRECORDS: 'Imported {count} records.' NOCSVFILE: 'Please browse for a CSV file to import' - NOIMPORT: 'Nothing to import' - RESET: Reset - Title: 'Data Models' + NOIMPORT: 'Niks om in te voer nie' + RESET: Herstel + Title: 'Data modelle' UPDATEDRECORDS: 'Updated {count} records.' ModelAdmin_ImportSpec.ss: - IMPORTSPECFIELDS: 'Database columns' + IMPORTSPECFIELDS: 'Databasis kolomme' IMPORTSPECLINK: 'Show Specification for %s' - IMPORTSPECRELATIONS: Relations + IMPORTSPECRELATIONS: Verhoudings IMPORTSPECTITLE: 'Specification for %s' ModelAdmin_Tools.ss: FILTER: Filter - IMPORT: Import + IMPORT: 'Voer in' ModelSidebar.ss: - IMPORT_TAB_HEADER: Import - SEARCHLISTINGS: Search + IMPORT_TAB_HEADER: 'Voer in' + SEARCHLISTINGS: Soek MoneyField: - FIELDLABELAMOUNT: Amount - FIELDLABELCURRENCY: Currency + FIELDLABELAMOUNT: Bedrag + FIELDLABELCURRENCY: 'Geld eenheid' NullableField: IsNullLabel: 'Is Null' NumericField: VALIDATION: '''{value}'' is not a number, only numbers can be accepted for this field' Pagination: - Page: Page - View: View + Page: Bladsy + View: Wys Permission: AdminGroup: Administrateur CMS_ACCESS_CATEGORY: 'IBS Toegang' - FULLADMINRIGHTS: 'Full administrative rights' + FULLADMINRIGHTS: 'Volle administratiewe regte ' FULLADMINRIGHTS_HELP: 'Impliseer en oorskryf alle ander toegekende permissies.' - PLURALNAME: Permissions - SINGULARNAME: Permission + PLURALNAME: Toestemmings + SINGULARNAME: Toestemming PermissionCheckboxSetField: AssignedTo: 'assigned to "{title}"' FromGroup: 'inherited from group "{title}"' FromRole: 'inherited from role "{title}"' FromRoleOnGroup: 'oorgeërf van rol "%s" op groep "%s"' PermissionRole: - OnlyAdminCanApply: 'Only admin can apply' - PLURALNAME: Roles - SINGULARNAME: Role - Title: Title + OnlyAdminCanApply: 'Slegs administrateur daarvoor aansoek doen' + PLURALNAME: Rolle + SINGULARNAME: Rol + Title: Tietel PermissionRoleCode: PLURALNAME: 'Permission Role Cods' SINGULARNAME: 'Permission Role Code' @@ -474,103 +474,103 @@ af: PERMISSIONS_CATEGORY: 'Rolle en toegang permissies' UserPermissionsIntro: 'Assigning groups to this user will adjust the permissions they have. See the groups section for details of permissions on individual groups.' PhoneNumberField: - VALIDATION: 'Please enter a valid phone number' + VALIDATION: 'Tik asseblief ''n geldige telefoon nommer in' RelationComplexTableField.ss: ADD: 'Voeg by' - CSVEXPORT: 'Export to CSV' - NOTFOUND: 'No items found' + CSVEXPORT: 'Voer uit na CSV' + NOTFOUND: 'Geen items gevind nie' Security: ALREADYLOGGEDIN: 'U het nie toegang tot hierdie bladsy nie. As u n'' ander rekening het wat toegang tot hierdie bladsy het, kan u weer inteken.' - BUTTONSEND: 'Send me the password reset link' - CHANGEPASSWORDBELOW: 'You can change your password below.' - CHANGEPASSWORDHEADER: 'Change your password' - ENTERNEWPASSWORD: 'Please enter a new password.' - ERRORPASSWORDPERMISSION: 'You must be logged in in order to change your password!' - LOGGEDOUT: 'You have been logged out. If you would like to log in again, enter your credentials below.' - LOGIN: 'Log in' - NOTEPAGESECURED: 'That page is secured. Enter your credentials below and we will send you right along.' + BUTTONSEND: 'Stuur vir my die wagwoord herstel skakel' + CHANGEPASSWORDBELOW: 'Jy kan jou wagwoord onder verander' + CHANGEPASSWORDHEADER: 'Verander jou wagwoord' + ENTERNEWPASSWORD: 'Sleutel asseblief ''n nuwe wagwoord in' + ERRORPASSWORDPERMISSION: 'Jy moet ingeteken wees om jou wagwoord te verander' + LOGGEDOUT: 'Jy is uit uitgeteken. As jy weer wil inteken, moet jy ''n gebruikersnaam en wagwoord onder in tik' + LOGIN: 'Teken in' + NOTEPAGESECURED: 'Daai bladsy is beveilig. Sleutel jou informasie onder in sodat ons jou op jou pad kan stuur' NOTERESETLINKINVALID: '

The password reset link is invalid or expired.

You can request a new one here or change your password after you logged in.

' - NOTERESETPASSWORD: 'Enter your e-mail address and we will send you a link with which you can reset your password' + NOTERESETPASSWORD: 'Sleutel you epos adres in sodat ons vir jou ''n herstel skakel kan epos' PASSWORDSENTHEADER: 'Password reset link sent to ''{email}''' PASSWORDSENTTEXT: 'Thank you! A reset link has been sent to ''{email}'', provided an account exists for this email address.' SecurityAdmin: ACCESS_HELP: 'Laat toe wys, byvoeging en verandering van gebruikers, so wel as die toekenning van permissies en rolle aan hulle.' APPLY_ROLES: 'Wend rolle tot groepe toe' APPLY_ROLES_HELP: 'Vermoë om rolle toegeken aan ''n groep te verander. Benodig die "Toegang tot ''Sekuriteit'' afdeling'' permissie.' - EDITPERMISSIONS: 'Manage permissions for groups' + EDITPERMISSIONS: 'Bestuur toegangsregte vir groepe' EDITPERMISSIONS_HELP: 'Vermoë om Permissies en IP Adresse vir ''n groep te verander. Benodig die "Toegang tot ''Sekuriteit'' afdeling" permissie.' - GROUPNAME: 'Group name' - IMPORTGROUPS: 'Import groups' - IMPORTUSERS: 'Import users' - MEMBERS: Members - MENUTITLE: Security + GROUPNAME: 'Groep naam' + IMPORTGROUPS: 'Voer groepe in' + IMPORTUSERS: 'Belangrike gebruikers' + MEMBERS: Lede + MENUTITLE: Sekuriteit MemberListCaution: 'Waarskuwing: Deur lede te verwyder van hierdie lys sal hulle ook van alle groepe en die databasis verwyder' - NEWGROUP: 'New Group' - PERMISSIONS: Permissions + NEWGROUP: 'Nuwe groep' + PERMISSIONS: Toegangsregte ROLES: Rolle ROLESDESCRIPTION: ' ' TABROLES: Rolle - Users: Users + Users: Gebruikers SecurityAdmin_MemberImportForm: BtnImport: 'Voer In' FileFieldLabel: 'CSV Lêer (Laat toe uitbreidings: *.csv)' SilverStripeNavigator: - Edit: Edit + Edit: Verander SimpleImageField: - NOUPLOAD: 'No Image Uploaded' + NOUPLOAD: 'Geen foto gelaai nie' SiteTree: TABMAIN: Hoof TableField: - ISREQUIRED: 'In %s ''%s'' is required' + ISREQUIRED: 'In %s ''%s'' word benodig.' TableField.ss: ADD: 'Voeg nuwe ry by' - ADDITEM: 'Add %s' + ADDITEM: 'Voeg %s by' TableListField: - CSVEXPORT: 'Export to CSV' + CSVEXPORT: 'Voer uit na CSV lêer' PRINT: Druk - Print: Print - SELECT: 'Select:' + Print: Druk + SELECT: Kies TableListField.ss: - NOITEMSFOUND: 'No items found' + NOITEMSFOUND: 'Geen item gevind nie' SORTASC: 'Sorteer in stygende orde' SORTDESC: 'Sorteer in dalende orde' TableListField_PageControls.ss: - DISPLAYING: Displaying - OF: of - TO: to - VIEWFIRST: 'View first' - VIEWLAST: 'View last' - VIEWNEXT: 'View next' - VIEWPREVIOUS: 'View previous' + DISPLAYING: 'Wys huidiglik' + OF: van + TO: na + VIEWFIRST: 'Wys eerste' + VIEWLAST: 'Wys laaste' + VIEWNEXT: 'Wys volgende' + VIEWPREVIOUS: 'Wys vorige' TimeField: - VALIDATEFORMAT: 'Please enter a valid time format ({format})' + VALIDATEFORMAT: 'Sleutel asseblief ''n geldige tyd formaat ({format})' ToggleField: - LESS: less - MORE: more + LESS: minder + MORE: meer UploadField: - ATTACHFILE: 'Attach a file' - ATTACHFILES: 'Attach files' - AttachFile: 'Attach file(s)' - DELETE: 'Delete from files' - DELETEINFO: 'Permanently delete this file from the file store' - DOEDIT: Save - DROPFILE: 'drop a file' - DROPFILES: 'drop files' - Dimensions: Dimensions - EDIT: Edit - EDITINFO: 'Edit this file' - FIELDNOTSET: 'File information not found' - FROMCOMPUTER: 'From your computer' - FROMCOMPUTERINFO: 'Select from files' - FROMFILES: 'From files' + ATTACHFILE: 'Heg lêer aan' + ATTACHFILES: 'Heg lêer(s) aan' + AttachFile: 'Aangehegde lêer(s)' + DELETE: 'Verwyder van lêers af' + DELETEINFO: 'Wis die lêer uit die lêer stoor uit' + DOEDIT: Stoor + DROPFILE: 'Laat val ''n lêer' + DROPFILES: 'Skuif lêers hiernatoe' + Dimensions: Afmetings + EDIT: Verander + EDITINFO: 'Verander die lêer' + FIELDNOTSET: 'Die lêer informasie kan nie gevind word nie' + FROMCOMPUTER: 'Van jou rekenaar' + FROMCOMPUTERINFO: 'Kied uit lêers uit' + FROMFILES: 'Van die lêers afdeling' HOTLINKINFO: 'Info: This image will be hotlinked. Please ensure you have permissions from the original site creator to do so.' - MAXNUMBEROFFILES: 'Max number of {count} file(s) exceeded.' - MAXNUMBEROFFILESSHORT: 'Can only upload {count} files' - REMOVE: Remove - REMOVEERROR: 'Error removing file' - REMOVEINFO: 'Remove this file from here, but do not delete it from the file store' - STARTALL: 'Start all' - STARTALLINFO: 'Start all uploads' - Saved: Saved + MAXNUMBEROFFILES: 'Maksimum aantal van {count} lêer(s) oorskry ' + MAXNUMBEROFFILESSHORT: 'Kan net {count} lêer oplaai' + REMOVE: Verwyder + REMOVEERROR: 'Daar het ''n fout onstaan met die verwydering van die lêer' + REMOVEINFO: 'Verwyder die lêer van hier af maar moet dit nie uit die lêer stoor verwyder nie' + STARTALL: 'Begin alles' + STARTALLINFO: 'Begin op alles op te laai' + Saved: Gestoor Versioned: has_many_Versions: Weergawe diff --git a/lang/ast.yml b/lang/ast.yml index 15c142df6..f4cdfca14 100644 --- a/lang/ast.yml +++ b/lang/ast.yml @@ -480,7 +480,7 @@ ast: CSVEXPORT: 'Export to CSV' NOTFOUND: 'No items found' Security: - ALREADYLOGGEDIN: 'Nun tienes accesu a esta páxina. Si tienes otra cuenta que pueda entrar nesta páxina, puedes volver conectate.' + ALREADYLOGGEDIN: 'Nun tienes accesu a esta páxina. Si tienes otra cuenta que pueda entrar nesta páxina, pues volver a coneutate.' BUTTONSEND: 'Send me the password reset link' CHANGEPASSWORDBELOW: 'You can change your password below.' CHANGEPASSWORDHEADER: 'Change your password' diff --git a/lang/bg.yml b/lang/bg.yml index b3e8b5302..83f50bb73 100644 --- a/lang/bg.yml +++ b/lang/bg.yml @@ -1,7 +1,7 @@ bg: AssetAdmin: ALLOWEDEXTS: 'Allowed extensions' - NEWFOLDER: NewFolder + NEWFOLDER: НоваПапка AssetTableField: CREATED: Създаден DIM: Размери @@ -10,18 +10,18 @@ bg: LASTEDIT: 'Последна промяна' OWNER: Собственик SIZE: 'Големина на файла' - TITLE: Title + TITLE: Заглавие TYPE: 'Тип на файла' URL: URL AssetUploadField: ChooseFiles: 'Избери файлове' DRAGFILESHERE: 'Завлечете файловете тук' - DROPAREA: 'Drop Area' + DROPAREA: 'Зона за пускане' EDITALL: 'Редакция на всички' EDITANDORGANIZE: 'Редактиране и подреждане' EDITINFO: 'Edit files' FILES: Файлове - FROMCOMPUTER: 'Choose files from your computer' + FROMCOMPUTER: 'Избери файлове от компютъра' FROMCOMPUTERINFO: 'Upload from your computer' TOTAL: Общо TOUPLOAD: 'Choose files to upload...' @@ -66,12 +66,12 @@ bg: LOADING: 'Зареждане ...' REQUIREJS: 'The CMS requires that you have JavaScript enabled.' CMSMain: - ACCESS: 'Access to ''{title}'' section' + ACCESS: 'Достъп до секция ''{title}''' ACCESSALLINTERFACES: 'Достъп до всички секции на CMS' ACCESSALLINTERFACESHELP: 'Overrules more specific access settings.' SAVE: Запис CMSProfileController: - MENUTITLE: 'My Profile' + MENUTITLE: 'Моят профил' ChangePasswordEmail.ss: CHANGEPASSWORDTEXT1: 'Вие сменихте вашата парола за' CHANGEPASSWORDTEXT2: 'Вече можете да ползвате следните данни за вход:' @@ -79,10 +79,10 @@ bg: HELLO: Здравей! PASSWORD: Парола CheckboxField: - - 'False' - - 'True' + - 'не е чекнато' + - чекнато ComplexTableField: - CLOSEPOPUP: 'Close Popup' + CLOSEPOPUP: 'Затвори прозореца' SUCCESSADD2: 'Беше добавен {name}' SUCCESSEDIT: 'Съхранено %s %s %s' ComplexTableField.ss: @@ -94,9 +94,9 @@ bg: NEXT: Следващо PREVIOUS: Предишно ConfirmedPasswordField: - ATLEAST: 'Passwords must be at least {min} characters long.' - BETWEEN: 'Passwords must be {min} to {max} characters long.' - MAXIMUM: 'Passwords must be at most {max} characters long.' + ATLEAST: 'Паролата трябва да е дълга мин. {min} символа.' + BETWEEN: 'Паролата трябва да е дълга от {min} до {max} символа.' + MAXIMUM: 'Паролата трябва да е дълга макс. {max} символа.' SHOWONCLICKTITLE: 'Промяна на парола' CreditCardField: FIRST: първи @@ -138,10 +138,10 @@ bg: EmailField: VALIDATION: 'Моля, въведете имейл адрес' Email_BounceRecord: - PLURALNAME: 'Email Bounce Records' - SINGULARNAME: 'Email Bounce Record' + PLURALNAME: 'Изпращане на отпадналите записи' + SINGULARNAME: 'Изпращане на отпаднал запис' Enum: - ANY: Any + ANY: Някой File: AviType: 'AVI video file' Content: Съдържание @@ -153,38 +153,38 @@ bg: GzType: 'GZIP compressed file' HtlType: 'HTML file' HtmlType: 'HTML file' - INVALIDEXTENSION: 'Extension is not allowed (valid: {extensions})' - INVALIDEXTENSIONSHORT: 'Extension is not allowed' + INVALIDEXTENSION: 'Това разширение не е разрешено (разрешени са: {extensions})' + INVALIDEXTENSIONSHORT: 'Това разширение не е разрешено' IcoType: 'Icon image' JpgType: 'JPEG image - good for photos' JsType: 'Javascript file' Mp3Type: 'MP3 audio file' MpgType: 'MPEG video file' NOFILESIZE: 'Размер на файла е нула байта.' - NOVALIDUPLOAD: 'File is not a valid upload' + NOVALIDUPLOAD: 'Невалиден файл за качване' Name: Име PLURALNAME: Файлове PdfType: 'Adobe Acrobat PDF file' PngType: 'PNG image - good general-purpose format' SINGULARNAME: Файл - TOOLARGE: 'Filesize is too large, maximum {size} allowed' - TOOLARGESHORT: 'Filesize exceeds {size}' + TOOLARGE: 'Много голям файл, разрешено е до {size}' + TOOLARGESHORT: 'Големината на файла надхвърля {size}' TiffType: 'Tagged image format' - Title: Title + Title: Заглавие WavType: 'WAV audo file' XlsType: 'Excel spreadsheet' ZipType: 'ZIP compressed file' FileIFrameField: - ATTACH: 'Attach {type}' - ATTACHONCESAVED: '{type}s can be attached once you have saved the record for the first time.' - ATTACHONCESAVED2: 'Files can be attached once you have saved the record for the first time.' - DELETE: 'Delete {type}' + ATTACH: 'Прикачи {type}' + ATTACHONCESAVED: '{type} може да бъде прикачен след като записът се съхрани за първи път.' + ATTACHONCESAVED2: 'Файлове могат да бъдат прикачвани след като записът се съхрани за първи път.' + DELETE: 'Изтрий {type}' DISALLOWEDFILETYPE: 'Не може да бъде качен файл от този тип' FILE: Файл FROMCOMPUTER: 'От компютъра' FROMFILESTORE: 'От Файлове и Изображения' - NOSOURCE: 'Please select a source file to attach' - REPLACE: 'Replace {type}' + NOSOURCE: 'Избери файл за прикачване' + REPLACE: 'Замести {type}' FileIFrameField_iframe.ss: TITLE: 'Iframe за качване на изображение' Filesystem: @@ -204,30 +204,30 @@ bg: VALIDATIONNOTUNIQUE: 'Въведената стойност не е уникална' VALIDATIONPASSWORDSDONTMATCH: 'Паролите не съвпадат' VALIDATIONPASSWORDSNOTEMPTY: 'Паролите не може да бъдат празни' - VALIDATIONSTRONGPASSWORD: 'Passwords must have at least one digit and one alphanumeric character' + VALIDATIONSTRONGPASSWORD: 'Паролите трябва да съдържат поне една цифра и една буква.' VALIDATOR: Валидатор - VALIDCURRENCY: 'Please enter a valid currency' + VALIDCURRENCY: 'Моля, въведете коректна валута.' FormField: - NONE: нищо + NONE: никой GridAction: - DELETE_DESCRIPTION: Delete - Delete: Delete + DELETE_DESCRIPTION: Изтриване + Delete: Изтрий UnlinkRelation: Откачане GridField: Add: 'Добави {name}' Filter: Филтър FilterBy: 'Филтриране по' - Find: Find + Find: Търси LEVELUP: 'Ниво нагоре' - LinkExisting: 'Link Existing' + LinkExisting: 'Свържи към съществуващ' NewRecord: 'Нов %s' NoItemsFound: 'Няма намерени елементи' - PRINTEDAT: 'Printed at' - PRINTEDBY: 'Printed by' + PRINTEDAT: 'Отпечатано на' + PRINTEDBY: 'Отпечатано от' PlaceHolder: 'Намери {type}' PlaceHolderWithLabels: 'Намери {type} по {name}' - RelationSearch: 'Relation search' - ResetFilter: Reset + RelationSearch: 'Търсене на връзка' + ResetFilter: Изчистване GridFieldAction_Delete: DeletePermissionsFailure: 'Изтриването не е разрешено' GridFieldDetailForm: @@ -241,26 +241,26 @@ bg: GridFieldItemEditView.ss: null Group: AddRole: 'Добавяне на роля към групата' - Code: 'Group Code' + Code: 'Код на група' DefaultGroupTitleAdministrators: Администратори DefaultGroupTitleContentAuthors: 'Редактори на съдържание' Description: Описание - GroupReminder: 'If you choose a parent group, this group will take all it''s roles' + GroupReminder: 'Ако изберете родителска група, тази група ще наследи всички нейни роли' Locked: 'Заключена?' NoRoles: 'Няма намерени роли' PLURALNAME: Groups - Parent: 'Parent Group' + Parent: 'Група източник' RolesAddEditLink: 'Управление на ролите' SINGULARNAME: Group Sort: Сортиране has_many_Permissions: Разрешения - many_many_Members: Потребители + many_many_Members: Членове GroupImportForm: - Help1: '

Import one or more groups in CSV format (comma-separated values). Show advanced usage

' + Help1: '

Внасяне на една или повече групи в CSV формат (comma-separated values). Покажи начин на употреба

' Help2: '

Advanced usage

  • Allowed columns: %s
  • Existing groups are matched by their unique Code value, and updated with any new values from the imported file
  • Group hierarchies can be created by using a ParentCode column.
  • Permission codes can be assigned by the PermissionCode column. Existing permission codes are not cleared.
' - ResultCreated: 'Created {count} groups' - ResultDeleted: 'Deleted %d groups' - ResultUpdated: 'Updated %d groups' + ResultCreated: 'Бяха създадени {count} група/и' + ResultDeleted: 'Бяха изтрити %d групи' + ResultUpdated: 'Бяха обновени %d групи' Hierarchy: InfiniteLoopNotAllowed: 'Infinite loop found within the "{type}" hierarchy. Please change the parent to resolve this' HtmlEditorField: @@ -277,7 +277,7 @@ bg: CSSCLASSLEFT: 'В ляво, с текст който да се нанася около него' CSSCLASSLEFTALONE: 'В ляво, самостоятелно.' CSSCLASSRIGHT: 'В дясно, с текст който да се нанася около него' - DETAILS: Details + DETAILS: Детайли EMAIL: 'email адрес' FILE: Файл FOLDER: Папка @@ -287,7 +287,7 @@ bg: FindInFolder: 'Прегледай папка' IMAGEALT: 'Алтернативен текст (alt)' IMAGEALTTEXT: 'Алтернативен текст (alt) - показва се ако изображението не е заредено' - IMAGEALTTEXTDESC: 'Shown to screen readers or if image can not be displayed' + IMAGEALTTEXTDESC: 'Вижда се на екранните четци или ако картинката не може да бъде показана' IMAGEDIMENSIONS: Размери IMAGEHEIGHTPX: Височина IMAGETITLE: 'Описание (tooltip) - за допълнителна информация към изображението' @@ -306,48 +306,48 @@ bg: LINKTO: 'Препратка към' PAGE: Страница URL: URL - URLNOTANOEMBEDRESOURCE: 'The URL ''{url}'' could not be turned into a media resource.' + URLNOTANOEMBEDRESOURCE: 'URL адресът ''{url}'' не може да бъде превърнат в медиен ресурс.' UpdateMEDIA: 'Актуализация на медиа' Image: PLURALNAME: Files SINGULARNAME: File ImageField: - IMAGE: Image + IMAGE: Изображение Image_Cached: PLURALNAME: Files SINGULARNAME: File Image_iframe.ss: - TITLE: 'Iframe за качване на изображение' + TITLE: 'Качване на изображението Iрамка' LeftAndMain: - CANT_REORGANISE: 'You do not have permission to alter Top level pages. Your change was not saved.' + CANT_REORGANISE: 'Нямаш права да променяш страници от най-горно ниво. Твоите промени не бяха записани.' DELETED: Изтрит DropdownBatchActionsDefault: Действия - HELP: Help - PAGETYPE: 'Page type: ' + HELP: Помощ + PAGETYPE: 'Тип на страницата' PERMAGAIN: 'Вие излязохте от CMS. Ако искате да влезете отново, моля, въведете потребителско име и парола.' PERMALREADY: 'Съжалявам, но нямате достъп до тази част от CMS. Ако искате да влезете с друго потребителско име, моля, направете го по-долу' PERMDEFAULT: 'Въведете имейл адреса и паролата си, за да влезете в CMS.' - PLEASESAVE: 'Please Save Page: This page could not be upated because it hasn''t been saved yet.' + PLEASESAVE: 'Съхрани страницата: Тази страница не може да бъде обновена, защото още не е записана.' PreviewButton: Преглед - REORGANISATIONSUCCESSFUL: 'Reorganised the site tree successfully.' + REORGANISATIONSUCCESSFUL: 'Реорганизацията на дървото на сайта беше успешна.' SAVEDUP: Записано VersionUnknown: непозната LeftAndMain_Menu.ss: Hello: Здравей - LOGOUT: 'Log out' + LOGOUT: Излизане LoginAttempt: - Email: 'Email Address' + Email: 'Email адрес' IP: 'IP адрес' PLURALNAME: 'Login Attempts' SINGULARNAME: 'Login Attempt' - Status: Status + Status: Статус Member: ADDGROUP: 'Добави група' BUTTONCHANGEPASSWORD: 'Променете паролата' BUTTONLOGIN: Влез BUTTONLOGINOTHER: 'Влез като някой друг' BUTTONLOSTPASSWORD: 'Загубих си паролата' - CANTEDIT: 'You don''t have permission to do that' + CANTEDIT: 'Нямаш права за това действие' CONFIRMNEWPASSWORD: 'Потвърдете новата парола' CONFIRMPASSWORD: 'Потвърдете паролата' DATEFORMAT: 'Date format' @@ -355,14 +355,14 @@ bg: DefaultDateTime: 'по подразбиране' EMAIL: Еmail EMPTYNEWPASSWORD: 'Не е въведена нова парола' - ENTEREMAIL: 'Връзка за анулиране на парола' + ENTEREMAIL: 'Въведете email, на който ще изпратим връзка за анулиране на парола.' ERRORLOCKEDOUT: 'Вашата сметка бе изключена временно защото имаше много неуспешни опити за влизане. Моля опитайте отново след 20 минути.' ERRORNEWPASSWORD: 'Въвели сте новата парола различно, моля опитайте пак' ERRORPASSWORDNOTMATCH: 'Вашата текуща парола не съвпада, моля опитайте пак' ERRORWRONGCRED: 'Това не изглежда да е правилен email адрес или парола. Моля опитайте отново.' FIRSTNAME: Име INTERFACELANG: Език - INVALIDNEWPASSWORD: 'We couldn''t accept that password: {password}' + INVALIDNEWPASSWORD: 'Не може да бъде приета паролата: {password}' LOGGEDINAS: 'Вие сте влезли като {name}.' NEWPASSWORD: 'Нова парола' PASSWORD: Парола @@ -389,10 +389,10 @@ bg: MemberDatetimeOptionsetField: AMORPM: 'АМ (преди обед) или РМ (следобед)' 'APPLY FILTER': 'Приложи филтър' - Custom: Custom + Custom: Произволно DATEFORMATBAD: 'Невалиден формат на датата' DAYNOLEADING: 'Ден от месеца без водеща нула' - DIGITSDECFRACTIONSECOND: 'One or more digits representing a decimal fraction of a second' + DIGITSDECFRACTIONSECOND: 'Една или повече цифри, представляващи десетичната част на секундата' FOURDIGITYEAR: 'Четирицифрена година' FULLNAMEMONTH: 'Пълно наименование на месец (напр. Януари)' HOURNOLEADING: 'Час без водеща нула' @@ -408,11 +408,11 @@ bg: TWODIGITSECOND: 'Секунди с водеща нула (00 до 59)' TWODIGITYEAR: 'Двуцифрена година' MemberImportForm: - Help1: '

Import users in CSV format (comma-separated values). Show advanced usage

' + Help1: '

Внасяне на потебители в CSV формат (comma-separated values). Покажи начин на употреба

' Help2: '

Advanced usage

  • Allowed columns: %s
  • Existing users are matched by their unique Code property, and updated with any new values from the imported file.
  • Groups can be assigned by the Groups column. Groups are identified by their Code property, multiple groups can be separated by comma. Existing group memberships are not cleared.
' ResultCreated: 'Бяха добавени {count} потребители' - ResultDeleted: 'Deleted %d members' - ResultNone: 'No changes' + ResultDeleted: 'Бяха изтрити %d членове' + ResultNone: 'Нямаше промени' ResultUpdated: 'Бяха актуализирани {count} потребители' MemberPassword: PLURALNAME: 'Member Passwords' @@ -420,15 +420,15 @@ bg: MemberTableField: null ModelAdmin: DELETE: Изтрий - DELETEDRECORDS: 'Deleted {count} records.' + DELETEDRECORDS: 'Бяха изтрити {count} записа.' EMPTYBEFOREIMPORT: 'Clear Database before import' - IMPORT: 'Import from CSV' - IMPORTEDRECORDS: 'Imported {count} records.' + IMPORT: 'Внасяне от CSV' + IMPORTEDRECORDS: 'Бяха внесени {count} записа.' NOCSVFILE: 'Преглед на CSV файл за внасяне' NOIMPORT: 'Нищо за внасяне' - RESET: Reset + RESET: Нулиране Title: 'Data Models' - UPDATEDRECORDS: 'Updated {count} records.' + UPDATEDRECORDS: 'Бяха обновени {count} записа.' ModelAdmin_ImportSpec.ss: IMPORTSPECFIELDS: 'Database columns' IMPORTSPECLINK: 'Show Specification for %s' @@ -486,13 +486,13 @@ bg: CHANGEPASSWORDHEADER: 'Сменете вашата парола' ENTERNEWPASSWORD: 'Моля, въведете нова парола.' ERRORPASSWORDPERMISSION: 'Трябва да сте влезли, за да можете да промените вашата парола!' - LOGGEDOUT: 'Вие излязохте. Ако искате да влезете отново, въведете вашите данни по-долу.' + LOGGEDOUT: 'Вие излязохте. Ако искате да влезнете отново, въведете вашите данни по-долу.' LOGIN: 'Влезте в системата' - NOTEPAGESECURED: 'Тази страница е защитена. Въведете вашите данни по-долу, за да продължите.' - NOTERESETLINKINVALID: '

The password reset link is invalid or expired.

You can request a new one here or change your password after you logged in.

' - NOTERESETPASSWORD: 'Въведете вашият email адрес и ще ви изпратим линк, с който ще можете да смените паролата си' - PASSWORDSENTHEADER: 'Password reset link sent to ''{email}''' - PASSWORDSENTTEXT: 'Thank you! A reset link has been sent to ''{email}'', provided an account exists for this email address.' + NOTEPAGESECURED: 'Тази страница е защитена. Вкарайте вашите данни по-долу и ще ви препратим по-нататък.' + NOTERESETLINKINVALID: '

Връзката за нулиране на парола не е вярна или е просрочена.

Можете да заявите нова тук или да промените паролата си след като влезете.

' + NOTERESETPASSWORD: 'Въведете вашият email адрес и ще ви изпратим линк с който ще можете да смените паролата си' + PASSWORDSENTHEADER: 'Връзка за нулиране на парола беше изпратена на ''{email}''' + PASSWORDSENTTEXT: 'Благодарим ви! Връзка за нулиране на паролата беше изпратен на ''{email}'', ако съществува акаунт с този имейл адрес.' SecurityAdmin: ACCESS_HELP: 'Позволява преглед, добавяне и редактиране на потребители, както и задаване на разрешения и роли за тях.' APPLY_ROLES: 'Задаване роли на групи' @@ -503,7 +503,7 @@ bg: IMPORTGROUPS: 'Внасяне на файл с групи' IMPORTUSERS: 'Внасяне на файл с потребители' MEMBERS: Потребители - MENUTITLE: Security + MENUTITLE: Сигурност MemberListCaution: 'Внимание: изтривайки потребители от този списък, ще ги премахне от всички групи и от базата данни.' NEWGROUP: 'Нова група' PERMISSIONS: Разрешения @@ -521,7 +521,7 @@ bg: SiteTree: TABMAIN: Главно TableField: - ISREQUIRED: 'In %s ''%s'' is required' + ISREQUIRED: 'В %s е необходимо ''%s''' TableField.ss: ADD: 'Добави нов ред' ADDITEM: 'Add %s' @@ -532,8 +532,8 @@ bg: SELECT: 'Избери:' TableListField.ss: NOITEMSFOUND: 'No items found' - SORTASC: 'Sort in ascending order' - SORTDESC: 'Sort in descending order' + SORTASC: 'Сортирай възходящо' + SORTDESC: 'Сортирай низходящо' TableListField_PageControls.ss: DISPLAYING: Displaying OF: of @@ -554,22 +554,22 @@ bg: DELETE: 'Delete from files' DELETEINFO: 'Изтрий файла от сървъра' DOEDIT: Запис - DROPFILE: 'drop a file' - DROPFILES: 'drop files' + DROPFILE: 'пуснете файл' + DROPFILES: 'пускане на файлове' Dimensions: Размери EDIT: Edit EDITINFO: 'Редактирай този файл' - FIELDNOTSET: 'File information not found' + FIELDNOTSET: 'Информация за файла не беше намерена' FROMCOMPUTER: 'От компютъра' FROMCOMPUTERINFO: 'Select from files' - FROMFILES: 'From files' + FROMFILES: 'От файлове' HOTLINKINFO: 'Info: This image will be hotlinked. Please ensure you have permissions from the original site creator to do so.' MAXNUMBEROFFILES: 'Максималния брой файлове ({count}) е надхвърлен.' MAXNUMBEROFFILESSHORT: 'Максималният брой файлове за качване е {count}' REMOVE: Премахни REMOVEERROR: 'Грешка при премахване на файл' REMOVEINFO: 'Премахни файла без да го изтриваш' - STARTALL: 'Start all' + STARTALL: 'Старт на всички' STARTALLINFO: 'Start all uploads' Saved: Записано Versioned: diff --git a/lang/cs.yml b/lang/cs.yml index dfdc5157c..67ea86f8b 100644 --- a/lang/cs.yml +++ b/lang/cs.yml @@ -1,6 +1,6 @@ cs: AssetAdmin: - ALLOWEDEXTS: 'Allowed extensions' + ALLOWEDEXTS: 'Povolené extenze' NEWFOLDER: 'Nová složka' AssetTableField: CREATED: 'Poprvé nahráno' @@ -119,7 +119,7 @@ cs: MONTHS: měsíce SEC: sekunda SECS: sekundy - TIMEDIFFAGO: '{difference} před' + TIMEDIFFAGO: 'před {difference}' TIMEDIFFIN: 'v {difference}' YEAR: rok YEARS: roky @@ -149,14 +149,14 @@ cs: DmgType: 'Apple obraz disku' DocType: 'Word dokument' Filename: 'Jméno souboru' - GifType: 'GIF obrázke - vhodné pro diagramy' + GifType: 'GIF obrázek - vhodné pro diagramy' GzType: 'GZIP komprimační soubor' HtlType: 'HTML soubor' HtmlType: 'HTML soubor' INVALIDEXTENSION: 'Extenze není povolena (platné: {extensions})' INVALIDEXTENSIONSHORT: 'Extenze není povolena' - IcoType: 'Icon obrázkek' - JpgType: 'JPEG obrázke - vhodné pro fotografie' + IcoType: 'Ikona obrázek' + JpgType: 'JPEG obrázek - vhodné pro fotografie' JsType: 'Javascript soubor' Mp3Type: 'MP3 audio soubor' MpgType: 'MPEG video soubor' @@ -503,7 +503,7 @@ cs: IMPORTGROUPS: 'Importovat skupiny' IMPORTUSERS: 'Importovat uživaté' MEMBERS: Členové - MENUTITLE: Bezbečnost + MENUTITLE: Bezpečnost MemberListCaution: 'Varování: Odstranění členů z tohoto seznamu způsobí, že členové budou odtraněni ze všech skupin a databáze' NEWGROUP: 'Nová skupina' PERMISSIONS: Práva diff --git a/lang/de.yml b/lang/de.yml index eaf5cda3b..b52876873 100644 --- a/lang/de.yml +++ b/lang/de.yml @@ -7,7 +7,7 @@ de: DIM: Dimensionen FILENAME: Dateiname FOLDER: Ordner - LASTEDIT: 'Letzte Änderung' + LASTEDIT: 'Letztmals geändert' OWNER: Eigentümer SIZE: Größe TITLE: Titel @@ -73,7 +73,7 @@ de: CMSProfileController: MENUTITLE: 'Mein Profil' ChangePasswordEmail.ss: - CHANGEPASSWORDTEXT1: 'Sie haben Ihr Passwort geändert für' + CHANGEPASSWORDTEXT1: 'Sie haben ihr Passwort geändert für' CHANGEPASSWORDTEXT2: 'Sie können nun folgende Angaben benutzen um sich einzuloggen' EMAIL: E-Mail HELLO: Hi @@ -424,7 +424,7 @@ de: EMPTYBEFOREIMPORT: 'Datenbank vor Import leeren' IMPORT: 'CSV Import' IMPORTEDRECORDS: '{count} Datensätze wurden importiert.' - NOCSVFILE: 'Wählen Sie eine CSV-Datei zum Importieren' + NOCSVFILE: 'Wählen sie eine CSV-Datei zum Importieren' NOIMPORT: 'Kein Import notwendig.' RESET: Zurücksetzen Title: Datenmodelle @@ -526,7 +526,7 @@ de: ADD: 'Eine neue Zeile hinzufügen' ADDITEM: '%s hinzufügen' TableListField: - CSVEXPORT: 'Als CSV-Datei exportieren' + CSVEXPORT: 'Exportieren zu CSV' PRINT: drucken Print: Drucken SELECT: 'Auswählen:' diff --git a/lang/en.yml b/lang/en.yml index f5b439933..3c1d2561b 100644 --- a/lang/en.yml +++ b/lang/en.yml @@ -1,7 +1,6 @@ en: AssetAdmin: - ADDFILES: 'Add files' - EditOrgMenu: 'Edit & organize' + ALLOWEDEXTS: 'Allowed extensions' NEWFOLDER: NewFolder AssetTableField: CREATED: 'First uploaded' @@ -239,8 +238,6 @@ en: Deleted: 'Deleted %s %s' Save: Save Saved: 'Saved %s %s' - GridFieldEditButton.ss: - EDIT: Edit GridFieldItemEditView.ss: 'Go back': 'Go back' Group: @@ -371,7 +368,6 @@ en: NEWPASSWORD: 'New Password' PASSWORD: Password PLURALNAME: Members - PROFILESAVESUCCESS: 'Successfully saved.' REMEMBERME: 'Remember me next time?' SINGULARNAME: Member SUBJECTPASSWORDCHANGED: 'Your password has been changed' diff --git a/lang/fi.yml b/lang/fi.yml index fd2e7a41a..71ee073fb 100644 --- a/lang/fi.yml +++ b/lang/fi.yml @@ -1,6 +1,6 @@ fi: AssetAdmin: - ALLOWEDEXTS: 'Allowed extensions' + ALLOWEDEXTS: 'Sallitut laajennukset' NEWFOLDER: 'Uusi kansio' AssetTableField: CREATED: 'Ensimmäisen kerran ladattu palvelimelle' @@ -347,7 +347,7 @@ fi: BUTTONLOGIN: 'Kirjaudu sisään' BUTTONLOGINOTHER: 'Kirjaudu jonain muuna' BUTTONLOSTPASSWORD: 'Kadotin salasanani' - CANTEDIT: 'You don''t have permission to do that' + CANTEDIT: 'Sinulla ei ole oikeuksia tähän toimintoon.' CONFIRMNEWPASSWORD: 'Syötä uusi salasana uudelleen' CONFIRMPASSWORD: 'Syötä salasana uudelleen' DATEFORMAT: Päivämäärämuoto @@ -472,7 +472,7 @@ fi: SINGULARNAME: 'Käyttöoikeiden roolin koodi' Permissions: PERMISSIONS_CATEGORY: 'Roolit ja käyttöoikeudet' - UserPermissionsIntro: 'Assigning groups to this user will adjust the permissions they have. See the groups section for details of permissions on individual groups.' + UserPermissionsIntro: 'Määriteltäessä käyttäjälle ryhmä, hänen käyttöoikeutensa mukautuvat ryhmälle tehtyjen asetusten mukaisesti. Katso tarkemmat ryhmäkohtaiset käyttöoikeusasetukset Ryhmät-välilehdeltä.' PhoneNumberField: VALIDATION: 'Kirjoita pätevä puhelinnumero' RelationComplexTableField.ss: diff --git a/lang/fr.yml b/lang/fr.yml index c39aa29c0..0ff29d77d 100644 --- a/lang/fr.yml +++ b/lang/fr.yml @@ -74,7 +74,7 @@ fr: MENUTITLE: 'Mon profil' ChangePasswordEmail.ss: CHANGEPASSWORDTEXT1: 'Vous avez modifié votre mot de passe pour' - CHANGEPASSWORDTEXT2: 'Vous pouvez maintenant utiliser les identifiants suivants pour vous connecter :' + CHANGEPASSWORDTEXT2: 'Vous pouvez maintenant utiliser les détails suivants pour vous connecter :' EMAIL: Email HELLO: Salut PASSWORD: 'Mot de passe' @@ -253,7 +253,7 @@ fr: RolesAddEditLink: 'Ajouter/éditer les rôles' SINGULARNAME: Groupe Sort: 'Ordre de tri' - has_many_Permissions: Autorisations + has_many_Permissions: Permissions many_many_Members: Membres GroupImportForm: Help1: '

Importer un ou plusieurs groupe(s) au format CSV (comma-separated values). Montrer l''usage avancé

' @@ -323,11 +323,11 @@ fr: DELETED: Supprimé. DropdownBatchActionsDefault: Actions HELP: Aide - PAGETYPE: 'Type de page :' + PAGETYPE: 'Type de page :' PERMAGAIN: 'Vous avez été déconnecté du CMS. Si vous voulez vous reconnecter, entrez un nom d''utilisateur et un mot de passe ci-dessous.' PERMALREADY: 'Désolé, mais vous ne pouvez pas accéder à cette partie du CMS. Si vous voulez changer d''identité, faites le ci-dessous' PERMDEFAULT: 'Saisissez votre adresse de courriel et votre mot de passe pour accéder au CMS.' - PLEASESAVE: 'Enregistrez la page s’il vous plaît : elle ne pouvait pas être mise à jour car elle n’avait pas encore été sauvegardée.' + PLEASESAVE: 'Enregistez la page s''il vous plaît : Cette page ne pouvait pas être actualisée, car elle n''a pas encore été enregistrée.' PreviewButton: Aperçu REORGANISATIONSUCCESSFUL: 'L’arbre du site a été bien réorganisé.' SAVEDUP: Enregistré. @@ -454,7 +454,7 @@ fr: AdminGroup: Administrateur CMS_ACCESS_CATEGORY: 'Accès au CMS' FULLADMINRIGHTS: 'Droits d''administration complets' - FULLADMINRIGHTS_HELP: 'Implique et prévaut sur toutes les autres autorisations assignées.' + FULLADMINRIGHTS_HELP: 'Implique et écrase toute les autres permissions assignées.' PLURALNAME: Autorisations SINGULARNAME: Autorisation PermissionCheckboxSetField: @@ -494,26 +494,26 @@ fr: PASSWORDSENTHEADER: 'Lien de réinitialisation de mot de passe envoyé à « {email} »' PASSWORDSENTTEXT: 'Merci ! Un lien de réinitialisation vient d’être envoyé à « {email} », à condition que cette adresse existe.' SecurityAdmin: - ACCESS_HELP: 'Permet de consulter, d’ajouter et d’éditer les utilisateurs, aussi bien que de leur assigner des autorisations et des rôles.' + ACCESS_HELP: 'Permettre la visualisation, l''addition et l''édition des utilisateurs, aussi bien que leur assigner des permissions et des rôles.' APPLY_ROLES: 'Appliquer des rôles aux groupes' - APPLY_ROLES_HELP: 'Possibilité d''éditer les rôle assignés à un groupe. Nécessite l’autorisation « Accès à la section “Utilisateurs” ».' - EDITPERMISSIONS: 'Gérer les autorisations des groupes' - EDITPERMISSIONS_HELP: 'Possibilité d''éditer les autorisations et les adresses IP pour un groupe. Nécessite l’autorisation « Accès à la section “Securité” ».' + APPLY_ROLES_HELP: 'Possibilité d''éditer les rôles assignés à un groupe. Nécessite "Access to ''Security'' section".' + EDITPERMISSIONS: 'Gérer les permissions des groupes' + EDITPERMISSIONS_HELP: 'Possibilité d''éditer les permissions et les l''adresses IP pour un groupe. Nécessite "Access to ''Security'' section".' GROUPNAME: 'Nom du group' IMPORTGROUPS: 'Importer groupes' IMPORTUSERS: 'Importer utilisateurs' MEMBERS: Membres MENUTITLE: Sécurité - MemberListCaution: 'Attention : en supprimant des membres de cette liste vous les enlèverez de tous les groupes ainsi que de la base de données' - NEWGROUP: 'Nouveau groupe' - PERMISSIONS: Autorisations + MemberListCaution: 'Attention : Enlever des membres de cette liste va les enlever de tous les groupes et de la base de donnée' + NEWGROUP: 'Nouveau Groupe' + PERMISSIONS: Permissions ROLES: Rôles - ROLESDESCRIPTION: 'Les rôles sont des regroupements logiques d’autorisations qui peuvent être assignés à des groupes.
Ils peuvent être hérités de groupes parents, si nécessaire.' + ROLESDESCRIPTION: 'Cette section vous permet d''ajouter des rôles à ce groupe. Les rôles sont des regroupements logiques d''autorisations, qui peuvent être modifiés dans l''onglet Rôles' TABROLES: Rôles Users: Utilisateurs SecurityAdmin_MemberImportForm: BtnImport: Importer - FileFieldLabel: 'Fichier CSV (extension autorisée : *.csv)' + FileFieldLabel: 'Fichier CSV (Extension permise: *.csv)' SilverStripeNavigator: Edit: 'Tout modifier' SimpleImageField: @@ -529,7 +529,7 @@ fr: CSVEXPORT: 'Exporter vers un fichier CSV' PRINT: Imprimer Print: Imprimer - SELECT: 'Sélectionner :' + SELECT: 'Sélectionner:' TableListField.ss: NOITEMSFOUND: 'Aucun élément n’a été trouvé' SORTASC: 'Classer en ordre croissant' diff --git a/lang/it.yml b/lang/it.yml index fb827f710..7448d91f4 100644 --- a/lang/it.yml +++ b/lang/it.yml @@ -3,15 +3,15 @@ it: ALLOWEDEXTS: 'Allowed extensions' NEWFOLDER: NuovaCartella AssetTableField: - CREATED: 'Inizialmente caricato' + CREATED: 'Primo inserito' DIM: Dimensioni FILENAME: 'Nome del file' FOLDER: Cartella - LASTEDIT: 'Ultima modifica' + LASTEDIT: 'Ultimo modificato' OWNER: Proprietario SIZE: Dimensione TITLE: Titolo - TYPE: 'Tipo di file' + TYPE: Tipo URL: URL AssetUploadField: ChooseFiles: 'Scegli file' @@ -67,14 +67,14 @@ it: REQUIREJS: 'Il CMS richiede JavaScript abilitato.' CMSMain: ACCESS: 'Accesso alla sezione ''{title}''' - ACCESSALLINTERFACES: 'Accesso a tutte le sezioni del CMS' + ACCESSALLINTERFACES: 'Accesso a tutte le interfaccia CMS' ACCESSALLINTERFACESHELP: 'Annulla le impostazioni di accesso più specifiche.' SAVE: Salva CMSProfileController: MENUTITLE: 'Il mio Profilo' ChangePasswordEmail.ss: CHANGEPASSWORDTEXT1: 'Hai cambiato la password per' - CHANGEPASSWORDTEXT2: 'Ora puoi utilizzare le seguenti credenziali per accedere:' + CHANGEPASSWORDTEXT2: 'Puoi ora utilizzare le seguenti credenziali per accedere:' EMAIL: Email HELLO: Ciao PASSWORD: Password @@ -86,10 +86,10 @@ it: SUCCESSADD2: 'Aggiunto {name}' SUCCESSEDIT: 'Salvato %s %s %s' ComplexTableField.ss: - ADDITEM: 'Inserisci %s' + ADDITEM: 'Aggiungi %s' NOITEMSFOUND: 'Nessun elemento trovato' - SORTASC: 'Ordina in modo ascendente' - SORTDESC: 'Ordina in modo discendente' + SORTASC: 'Ordina in modo crescente' + SORTDESC: 'Ordina in modo decrescente' ComplexTableField_popup.ss: NEXT: Prossimo PREVIOUS: Precedente @@ -97,7 +97,7 @@ it: ATLEAST: 'La password deve essere lunga almeno {min} caratteri.' BETWEEN: 'La password deve essere lunga da {min} a {max} caratteri.' MAXIMUM: 'La password deve essere lunga almeno {max} caratteri.' - SHOWONCLICKTITLE: 'Cambia password' + SHOWONCLICKTITLE: 'Cambia la password' CreditCardField: FIRST: primo FOURTH: quarto @@ -106,8 +106,8 @@ it: CurrencyField: CURRENCYSYMBOL: $ DataObject: - PLURALNAME: 'Data Objects' - SINGULARNAME: 'Data Object' + PLURALNAME: 'Oggetti dati' + SINGULARNAME: 'Oggetto dati' Date: DAY: giorno DAYS: giorni @@ -250,10 +250,10 @@ it: NoRoles: 'Nessun ruolo trovato' PLURALNAME: Gruppi Parent: 'Gruppo padre' - RolesAddEditLink: 'Gestisci ruoli' + RolesAddEditLink: 'Aggiungi/modifica ruoli' SINGULARNAME: Gruppo Sort: 'Tipo ordinamento' - has_many_Permissions: Permessi + has_many_Permissions: Autorizzazioni many_many_Members: Membri GroupImportForm: Help1: '

Importa gruppi in formato CSV (valori separati da virgole). Mostra utilizzo avanzato

' @@ -345,7 +345,7 @@ it: ADDGROUP: 'Aggiungi gruppo' BUTTONCHANGEPASSWORD: 'Cambia password' BUTTONLOGIN: Accedi - BUTTONLOGINOTHER: 'Autenticati come qualcun altro' + BUTTONLOGINOTHER: 'Autenticato come qualcun altro' BUTTONLOSTPASSWORD: 'Ho perso la mia password' CANTEDIT: 'You don''t have permission to do that' CONFIRMNEWPASSWORD: 'Conferma nuova password' @@ -355,25 +355,25 @@ it: DefaultDateTime: predefinito EMAIL: Email EMPTYNEWPASSWORD: 'La nuova password non può essere vuota, riprova' - ENTEREMAIL: 'Inserisci un indirizzo e-mail per ricevere il link di azzeramento della password' + ENTEREMAIL: 'Indica un indirizzo e-mail per ricevere il collegamento di azzeramento della password' ERRORLOCKEDOUT: 'Il tuo account è stato temporaneamente disabilitato perchè ci sono stati troppi tentativi di accesso errati. Riprova tra 20 minuti.' ERRORNEWPASSWORD: 'Hai inserito la tua nuova password in modo differente, prova di nuovo' ERRORPASSWORDNOTMATCH: 'La tua password attuale non corrisponde, per favore prova ancora' - ERRORWRONGCRED: 'E-mail o password non sembrano essere corretti. Per favore, prova di nuovo.' + ERRORWRONGCRED: 'Non sembra esserci l''indirizzo e-mail corretto o la password. Per favore, prova di nuovo.' FIRSTNAME: Nome INTERFACELANG: 'Lingua dell''interfaccia' INVALIDNEWPASSWORD: 'Non possiamo accettare questa password: {password}' LOGGEDINAS: 'Sei collegato come {name}.' NEWPASSWORD: 'Nuova password' PASSWORD: Password - PLURALNAME: Utenti + PLURALNAME: Membri REMEMBERME: 'Ricordati di me la prossima volta?' - SINGULARNAME: Utente + SINGULARNAME: Membro SUBJECTPASSWORDCHANGED: 'La tua password è stata cambiata' - SUBJECTPASSWORDRESET: 'Link per azzerare la tua password' + SUBJECTPASSWORDRESET: 'Indirizzo per reimpostare la tua password' SURNAME: Cognome TIMEFORMAT: 'Formato dell''ora' - VALIDATIONMEMBEREXISTS: 'Esiste già un utente con l''e-mail %s' + VALIDATIONMEMBEREXISTS: 'Esiste già un membro con questa e-mail' ValidationIdentifierFailed: 'Non posso sovrascrivere l''utente esistente #{id} con identificatore identico ({name} = {value}))' WELCOMEBACK: 'Bentornato, {firstname}' YOUROLDPASSWORD: 'La tua vecchia password' @@ -419,12 +419,12 @@ it: SINGULARNAME: 'Password utente' MemberTableField: null ModelAdmin: - DELETE: Elimina + DELETE: Cancella DELETEDRECORDS: 'Eliminati {count} record.' EMPTYBEFOREIMPORT: 'Cancella database prima dell''import' IMPORT: 'Importa da CSV' IMPORTEDRECORDS: 'Importati {count} record.' - NOCSVFILE: 'Scegli un file CSV da importare' + NOCSVFILE: 'Cerca un file CSV da importare' NOIMPORT: 'Nulla da importare.' RESET: Azzera Title: 'Modelli di dati' @@ -441,7 +441,7 @@ it: IMPORT_TAB_HEADER: Importa SEARCHLISTINGS: Cerca MoneyField: - FIELDLABELAMOUNT: Importo + FIELDLABELAMOUNT: Totale FIELDLABELCURRENCY: Valuta NullableField: IsNullLabel: 'è nullo.' @@ -461,7 +461,7 @@ it: AssignedTo: 'assegnato a "{title}"' FromGroup: 'ereditato dal gruppo "{title}"' FromRole: 'ereditato dal ruolo "{title}"' - FromRoleOnGroup: 'ereditato dal ruolo "%s" nel gruppo "%s"' + FromRoleOnGroup: 'eredita dal ruolo "%s" sul gruppo "%s"' PermissionRole: OnlyAdminCanApply: 'Solo l''amministratore può applicare' PLURALNAME: Ruoli @@ -481,16 +481,16 @@ it: NOTFOUND: 'Nessun elemento trovato' Security: ALREADYLOGGEDIN: 'Non hai accesso a questa pagina. Se hai un altro account che può accederci, puoi autenticarti qui sotto.' - BUTTONSEND: 'Inviami il link per azzerare la password' - CHANGEPASSWORDBELOW: 'Puoi cambiare la tua password qui sotto.' + BUTTONSEND: 'Inviami il link per reimpostare la password' + CHANGEPASSWORDBELOW: 'Puoi cambiare la tua password qui di seguito.' CHANGEPASSWORDHEADER: 'Cambia la tua password' ENTERNEWPASSWORD: 'Per favore inserisci una nuova password.' ERRORPASSWORDPERMISSION: 'Devi essere autenticato per poter cambiare la tua password!' - LOGGEDOUT: 'Sei stato disconnesso. Se vuoi autenticarti nuovamente, inserisci qui sotto le tue credenziali.' + LOGGEDOUT: 'Sei stato sloggato. Se vuoi autenticarti nuovamente, inserisci qui sotto le tue credenziali.' LOGIN: Entra - NOTEPAGESECURED: 'La pagina è protetta. Inserisci le credenziali qui sotto per poter andare avanti.' + NOTEPAGESECURED: 'La pagina è sicura. Inserisci le credenziali qui di seguito per poter andare avanti.' NOTERESETLINKINVALID: '

Il link per azzerare la password non è valido o è scaduto.

Puoi richiederne uno nuovo qui o cambiare la tua password dopo che ti sei connesso.

' - NOTERESETPASSWORD: 'Inserisci il tuo indirizzo e-mail e ti verrà inviato un link per poter azzerare la tua password.' + NOTERESETPASSWORD: 'Inserisci il tuo indirizzo e-mail e ti verrà inviato un link per poter reimpostare la tua password.' PASSWORDSENTHEADER: 'Link per azzeramento della password inviato a ''{email}''' PASSWORDSENTTEXT: 'Grazie! Un link di azzeramento è stato inviato a ''{email}'', fornito un account esistente per questo indirizzo e-mail.' SecurityAdmin: diff --git a/lang/ja_JP.yml b/lang/ja_JP.yml index d2c6102a3..5cad90b9c 100644 --- a/lang/ja_JP.yml +++ b/lang/ja_JP.yml @@ -86,7 +86,7 @@ ja_JP: SUCCESSADD2: '{name}を追加しました' SUCCESSEDIT: '更新日時 %s %s %s' ComplexTableField.ss: - ADDITEM: '%sを追加する' + ADDITEM: '%sを追加' NOITEMSFOUND: 項目が見つかりませんでした SORTASC: 昇順 SORTDESC: ソート(下順) diff --git a/lang/mi_NZ.yml b/lang/mi_NZ.yml index 9e3a035ff..2dd2e714e 100644 --- a/lang/mi_NZ.yml +++ b/lang/mi_NZ.yml @@ -4,14 +4,14 @@ mi_NZ: NEWFOLDER: KōpakiHōu AssetTableField: CREATED: 'Tukuatu tuatahi' - DIM: 'Ngā Rahinga' + DIM: Nuinga FILENAME: 'Ingoa Kōnae' FOLDER: Kōpaki LASTEDIT: 'Hurihanga tōmuri' OWNER: Kaiūmanga SIZE: Nuinga - TITLE: Taitara - TYPE: 'Momo kōnae' + TITLE: 'Ingoa ' + TYPE: 'Tūmomo ' URL: PRO AssetUploadField: ChooseFiles: 'Kōwhiri kōnae' @@ -69,7 +69,7 @@ mi_NZ: ACCESS: 'Uru ki te wāhanga ''{title}''' ACCESSALLINTERFACES: 'Uru ki ngā wāhanga CMS katoa' ACCESSALLINTERFACESHELP: 'Ka takahi i ngā tautuhinga uru tauwhāiti ake' - SAVE: Tiaki + SAVE: tiakina CMSProfileController: MENUTITLE: 'My Profile' ChangePasswordEmail.ss: @@ -505,7 +505,7 @@ mi_NZ: MEMBERS: 'Ngā Mema' MENUTITLE: Haumarutanga MemberListCaution: 'Whakatūpato: Mā te tango mema i tēnei rārangi, ka tangohia i ngā rōpū katoa me te pātengi raraunga' - NEWGROUP: 'Rōpū Hōu' + NEWGROUP: 'Roopu hou' PERMISSIONS: 'Ngā Whakaaetanga' ROLES: 'Ngā Tūnga' ROLESDESCRIPTION: 'Ko ngā tūnga he huinga o ngā whakaaetanga i tautuhia i mua, ā, ka taea te tautapa i ēnei ki ngā rōpū.
I tukuna iho i ngā rōpū matua ki te hiahiatia.' diff --git a/lang/nl.yml b/lang/nl.yml index 0bdf29a93..016bc4097 100644 --- a/lang/nl.yml +++ b/lang/nl.yml @@ -17,15 +17,15 @@ nl: ChooseFiles: 'Selecteer bestanden' DRAGFILESHERE: 'Sleep bestanden hiernaar toe' DROPAREA: 'Drop Area' - EDITALL: 'Edit all' + EDITALL: 'Alle bewerken' EDITANDORGANIZE: 'Bewerk en beheer' EDITINFO: 'Edit files' - FILES: Files + FILES: Bestanden FROMCOMPUTER: 'Choose files from your computer' FROMCOMPUTERINFO: 'Upload from your computer' - TOTAL: Total + TOTAL: Totaal TOUPLOAD: 'Choose files to upload...' - UPLOADINPROGRESS: 'Please wait… upload in progress' + UPLOADINPROGRESS: 'Even geduld... bezig met uploaden' UPLOADOR: OF BBCodeParser: ALIGNEMENT: Uitlijning @@ -63,7 +63,7 @@ nl: ANY: Elke 1: Ja CMSLoadingScreen.ss: - LOADING: Loading... + LOADING: 'Bezig met laden...' REQUIREJS: 'The CMS requires that you have JavaScript enabled.' CMSMain: ACCESS: 'Toegang tot het ''{title}'' gedeelte' @@ -119,7 +119,7 @@ nl: MONTHS: maanden SEC: seconde SECS: seconden - TIMEDIFFAGO: '{difference} ago' + TIMEDIFFAGO: '{difference} geleden' TIMEDIFFIN: 'in {difference}' YEAR: jaar YEARS: jaren @@ -338,8 +338,8 @@ nl: LoginAttempt: Email: 'Email adres ' IP: 'IP Adres' - PLURALNAME: 'Login Attempts' - SINGULARNAME: 'Login Attempt' + PLURALNAME: 'Pogingen om in te loggen' + SINGULARNAME: 'Poging om in te loggen' Status: Status Member: ADDGROUP: 'Add group' @@ -393,7 +393,7 @@ nl: DATEFORMATBAD: 'Datum is niet correct opgegeven' DAYNOLEADING: 'Dag van de maand zonder voorloop-nul' DIGITSDECFRACTIONSECOND: 'One or more digits representing a decimal fraction of a second' - FOURDIGITYEAR: 'Four-digit year' + FOURDIGITYEAR: 'jaar (yyyy)' FULLNAMEMONTH: 'Full name of month (e.g. June)' HOURNOLEADING: 'Hour without leading zero' MINUTENOLEADING: 'Minute without leading zero' @@ -446,7 +446,7 @@ nl: NullableField: IsNullLabel: 'is nul' NumericField: - VALIDATION: '''{value}'' is not a number, only numbers can be accepted for this field' + VALIDATION: '''{value}'' is geen getal. Dit velt accepteert alleen getallen.' Pagination: Page: Page View: View @@ -458,7 +458,7 @@ nl: PLURALNAME: Permissions SINGULARNAME: Permission PermissionCheckboxSetField: - AssignedTo: 'assigned to "{title}"' + AssignedTo: 'toegewezen aan "{title}"' FromGroup: 'inherited from group "{title}"' FromRole: 'inherited from role "{title}"' FromRoleOnGroup: 'geërfd van rol "%s" in groep "%s"' @@ -466,7 +466,7 @@ nl: OnlyAdminCanApply: 'Only admin can apply' PLURALNAME: Roles SINGULARNAME: Role - Title: Title + Title: Titel PermissionRoleCode: PLURALNAME: 'Permission Role Cods' SINGULARNAME: 'Permission Role Code' @@ -528,7 +528,7 @@ nl: TableListField: CSVEXPORT: 'Exporteer naar CSV' PRINT: Afdrukken - Print: Print + Print: Afdrukken SELECT: 'Selecteer:' TableListField.ss: NOITEMSFOUND: 'No items found' diff --git a/lang/ro.yml b/lang/ro.yml index 6c72973bc..61cac0920 100644 --- a/lang/ro.yml +++ b/lang/ro.yml @@ -380,7 +380,7 @@ ro: belongs_many_many_Groups: Grupuri db_LastVisited: 'Data ultimei vizite' db_Locale: 'Interface Locale' - db_LockedOutUntil: 'Blocat pana la' + db_LockedOutUntil: 'Blocat pana cand' db_NumVisit: 'Numarul de vizite' db_Password: Parola db_PasswordExpiry: 'Data de Expirare a Parolei' diff --git a/lang/sk.yml b/lang/sk.yml index 31ec9ff75..29eed7414 100644 --- a/lang/sk.yml +++ b/lang/sk.yml @@ -1,7 +1,7 @@ sk: AssetAdmin: - ALLOWEDEXTS: 'Allowed extensions' - NEWFOLDER: 'Nový priečinok' + ALLOWEDEXTS: 'Povolené extenzie' + NEWFOLDER: 'Nový Adresár' AssetTableField: CREATED: 'Prvýkrát nahrané' DIM: Rozmery @@ -155,7 +155,7 @@ sk: HtmlType: 'HTML súbor' INVALIDEXTENSION: 'Extenzia nie je povolená (platné: {extensions})' INVALIDEXTENSIONSHORT: 'Extenzia nie je povolená' - IcoType: 'Icon obrázok' + IcoType: 'Ikona obrázok' JpgType: 'JPEG obrázok - vhodné pre fotografie' JsType: 'Javascript súbor' Mp3Type: 'MP3 audio súbor' @@ -240,21 +240,21 @@ sk: Saved: 'Uložené %s %s' GridFieldItemEditView.ss: null Group: - AddRole: 'Pridať úlohu pre túto skupinu' + AddRole: 'Pridať novú úlohu pre túto skupinu' Code: 'Kód skupiny' DefaultGroupTitleAdministrators: Administratori DefaultGroupTitleContentAuthors: 'Autori obsahu' Description: Popis GroupReminder: 'Ak vyberiete nadriadenú skupinu, bude táto skupina mať všetky úlohy' Locked: 'Zamknuté?' - NoRoles: 'Nenašli sa úlohy' + NoRoles: 'Nenašli sa žiadne úlohy' PLURALNAME: Skupiny Parent: 'Nadradená skupina' - RolesAddEditLink: 'Spravovať úlohy' + RolesAddEditLink: 'Pridať/upraviť úlohy' SINGULARNAME: Skupina - Sort: 'Poradie zoradenia' + Sort: 'Zoradiť podľa' has_many_Permissions: Právomoci - many_many_Members: Členovia + many_many_Members: Uživatelia GroupImportForm: Help1: 'Importovať jednu alebo viac skupín v CSV formáte (čiarkov oddelené hodnoty). Zobraziť pokročilé použitie' Help2: "
\\n

Pokročilé použitie

\\n
    \\n
  • Povolené stĺpce: %s
  • \\n
  • Existujúce skupiny sú porovnávané ich unikátnou vlastnostou Code, a aktualizované s novými hodnotami z\\nimportovaného súboru.
  • \\n
  • Hierarchia skupín môže byť tvorená použitím stĺpce ParentCode.
  • \\n
  • Kódy oprávnení môžu byť priradené stĺpcom PermissionCode. Existujúce oprávnenia nie sú smazáné.
  • \\n
\\n
" @@ -366,9 +366,9 @@ sk: LOGGEDINAS: 'Ste prihlásený/á ako {name}.' NEWPASSWORD: 'Nové heslo' PASSWORD: Heslo - PLURALNAME: Členovia + PLURALNAME: Uživatelia REMEMBERME: 'Pamätať si ma nabudúce?' - SINGULARNAME: Člen + SINGULARNAME: Uživatel SUBJECTPASSWORDCHANGED: 'Vaše heslo bolo zmenené' SUBJECTPASSWORDRESET: 'Odkaz na resetovanie hesla' SURNAME: Priezvisko @@ -419,7 +419,7 @@ sk: SINGULARNAME: 'Heslo člena' MemberTableField: null ModelAdmin: - DELETE: Zmazať + DELETE: Vymazať DELETEDRECORDS: 'Zmazaných {count} záznamov.' EMPTYBEFOREIMPORT: 'Vyčistiť databázu pred importovaním' IMPORT: 'Importovať z CSV' @@ -503,7 +503,7 @@ sk: IMPORTGROUPS: 'Importovať skupiny' IMPORTUSERS: 'Importovať požívateľov' MEMBERS: Členovia - MENUTITLE: Zabezpečenie + MENUTITLE: Bezpečnosť MemberListCaution: 'Upozornenie: Odstánenie členov z tohto zoznamu ich odstáni zo všetkých skupín a databázy.' NEWGROUP: 'Nová skupina' PERMISSIONS: Právomoci @@ -532,8 +532,8 @@ sk: SELECT: 'Vyberte:' TableListField.ss: NOITEMSFOUND: 'Žiadne položky' - SORTASC: 'Triedit v vzostupnom poradí' - SORTDESC: 'Triediť v zostupnom poradí' + SORTASC: 'Zoradiť vzostupne' + SORTDESC: 'Zoradiť zostupne' TableListField_PageControls.ss: DISPLAYING: Zobrazujem OF: z From 375c33e0cf5d40529d3a8fb5b54d8989b888af84 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Mon, 17 Dec 2012 13:00:18 +0100 Subject: [PATCH 18/73] Wider sidebar to accommodate "add" and "edit" buttons --- admin/css/screen.css | 2 +- admin/scss/_style.scss | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/admin/css/screen.css b/admin/css/screen.css index 4fd318fc3..1a18cc5df 100644 --- a/admin/css/screen.css +++ b/admin/css/screen.css @@ -492,7 +492,7 @@ p.message { margin-bottom: 12px; } .cms-content-tools { background: #eceff1; width: 200px; overflow-y: auto; overflow-x: hidden; z-index: 70; border-right: 1px solid #c0c0c2; -webkit-box-shadow: rgba(248, 248, 248, 0.9) -1px 0 0 inset, 0 0 1px rgba(201, 205, 206, 0.8); -moz-box-shadow: rgba(248, 248, 248, 0.9) -1px 0 0 inset, 0 0 1px rgba(201, 205, 206, 0.8); box-shadow: rgba(248, 248, 248, 0.9) -1px 0 0 inset, 0 0 1px rgba(201, 205, 206, 0.8); float: left; position: relative; } .cms-content-tools.filter { padding: 0 !important; } .cms-content-tools .cms-panel-header { clear: both; margin: 0 0 7px; line-height: 24px; border-bottom: 1px solid #d0d3d5; -webkit-box-shadow: 0 1px 0 rgba(248, 248, 248, 0.9); -moz-box-shadow: 0 1px 0 rgba(248, 248, 248, 0.9); -o-box-shadow: 0 1px 0 rgba(248, 248, 248, 0.9); box-shadow: 0 1px 0 rgba(248, 248, 248, 0.9); } -.cms-content-tools .cms-panel-content { width: 176px; padding: 8px 8px 0; overflow: auto; height: 100%; } +.cms-content-tools .cms-panel-content { width: 184px; padding: 8px 8px 0; overflow: auto; height: 100%; } .cms-content-tools .cms-panel-content .Actions .ss-ui-action-constructive { margin-right: 5px; } .cms-content-tools .cms-content-header { background-color: #748d9d; background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjUwJSIgeTE9IjAlIiB4Mj0iNTAlIiB5Mj0iMTAwJSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2IwYmVjNyIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzc0OGQ5ZCIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=='); background-size: 100%; background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #b0bec7), color-stop(100%, #748d9d)); background-image: -webkit-linear-gradient(#b0bec7, #748d9d); background-image: -moz-linear-gradient(#b0bec7, #748d9d); background-image: -o-linear-gradient(#b0bec7, #748d9d); background-image: linear-gradient(#b0bec7, #748d9d); } .cms-content-tools .cms-content-header h2 { text-shadow: #5c7382 -1px -1px 0; width: 176px; color: white; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; -o-text-overflow: ellipsis; } diff --git a/admin/scss/_style.scss b/admin/scss/_style.scss index dc36c0447..ffe0b4ad4 100644 --- a/admin/scss/_style.scss +++ b/admin/scss/_style.scss @@ -702,7 +702,7 @@ p.message { } .cms-panel-content { - width: ($grid-x * 22); + width: ($grid-x * 23); padding: $grid-x $grid-x 0; overflow: auto; height:100%; From c1bd1432d1a05008cda7cd36a433274b4348c876 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Mon, 17 Dec 2012 14:21:13 +0100 Subject: [PATCH 19/73] Tab spacing (regression from 2d075671) --- admin/css/screen.css | 2 +- admin/scss/_style.scss | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/admin/css/screen.css b/admin/css/screen.css index 1a18cc5df..9c9db5c3c 100644 --- a/admin/css/screen.css +++ b/admin/css/screen.css @@ -409,7 +409,7 @@ body.cms { overflow: hidden; } .ui-tabs.ss-tabset-tabshidden .ui-tabs-panel { border-top: none; } /** Primary styles which sit on top of screen, with different tab colors. TODO Only use one "primary" selector and fix HTMLEditorField TabSet addExtraClass() */ -.ui-tabs.cms-tabset-primary .ui-tabs-nav, .ui-tabs .ui-tabs-nav.cms-tabset-nav-primary, .ui-tabs .cms-content-header-tabs .ui-tabs-nav { border-left: 1px solid #b3b3b3; } +.ui-tabs.cms-tabset-primary .ui-tabs-nav, .ui-tabs .ui-tabs-nav.cms-tabset-nav-primary, .ui-tabs .cms-content-header-tabs .ui-tabs-nav { border-left: 1px solid #b3b3b3; float: none; } .ui-tabs.cms-tabset-primary .ui-tabs-nav li, .ui-tabs .ui-tabs-nav.cms-tabset-nav-primary li, .ui-tabs .cms-content-header-tabs .ui-tabs-nav li { margin-right: 0; margin-top: 0; } .ui-tabs.cms-tabset-primary .ui-tabs-nav li a, .ui-tabs .ui-tabs-nav.cms-tabset-nav-primary li a, .ui-tabs .cms-content-header-tabs .ui-tabs-nav li a { margin: 0; line-height: 39px; } .ui-tabs.cms-tabset-primary .ui-tabs-nav .ui-corner-all, .ui-tabs.cms-tabset-primary .ui-tabs-nav .ui-corner-top, .ui-tabs.cms-tabset-primary .ui-tabs-nav .ui-corner-right, .ui-tabs.cms-tabset-primary .ui-tabs-nav .ui-corner-tr, .ui-tabs.cms-tabset-primary .ui-tabs-nav .ui-corner-tl, .ui-tabs .ui-tabs-nav.cms-tabset-nav-primary .ui-corner-all, .ui-tabs .ui-tabs-nav.cms-tabset-nav-primary .ui-corner-top, .ui-tabs .ui-tabs-nav.cms-tabset-nav-primary .ui-corner-right, .ui-tabs .ui-tabs-nav.cms-tabset-nav-primary .ui-corner-tr, .ui-tabs .ui-tabs-nav.cms-tabset-nav-primary .ui-corner-tl, .ui-tabs .cms-content-header-tabs .ui-tabs-nav .ui-corner-all, .ui-tabs .cms-content-header-tabs .ui-tabs-nav .ui-corner-top, .ui-tabs .cms-content-header-tabs .ui-tabs-nav .ui-corner-right, .ui-tabs .cms-content-header-tabs .ui-tabs-nav .ui-corner-tr, .ui-tabs .cms-content-header-tabs .ui-tabs-nav .ui-corner-tl { border-radius: 0; } diff --git a/admin/scss/_style.scss b/admin/scss/_style.scss index ffe0b4ad4..0cdc4c8a5 100644 --- a/admin/scss/_style.scss +++ b/admin/scss/_style.scss @@ -302,7 +302,8 @@ body.cms { .ui-tabs .ui-tabs-nav.cms-tabset-nav-primary, .ui-tabs .cms-content-header-tabs .ui-tabs-nav { border-left: 1px solid darken($color-tab, 15%); - + float: none; // parent container is already right floated + li { margin-right: 0; // tabs are directly adjacent margin-top: 0; From 407a19cdb64ed63007c3ac23ebe150ab45a6bb4e Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Mon, 17 Dec 2012 14:27:31 +0100 Subject: [PATCH 20/73] Beta changelog links --- docs/en/changelogs/index.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/changelogs/index.md b/docs/en/changelogs/index.md index 034d4d1e5..78a80e545 100644 --- a/docs/en/changelogs/index.md +++ b/docs/en/changelogs/index.md @@ -9,6 +9,8 @@ For information on how to upgrade to newer versions consult the [upgrading](/ins ## Stable Releases + * [3.1.0](3.1.0) - Unreleased + * [3.0.2](3.0.2) - 17 September 2012 * [3.0.1](3.0.1) - 31 July 2012 * [3.0.0](3.0.0) - 28 June 2012 @@ -65,6 +67,8 @@ For information on how to upgrade to newer versions consult the [upgrading](/ins ## Alpha/beta/release candidate ## + * [3.1.0-beta1](beta/3.1.0-beta1) - 17 December 2012 + * [3.0.3-rc1](rc/3.0.3-rc1) - 6 November 2012 * [3.0.2-rc2](rc/3.0.2-rc2) - 12 September 2012 * [3.0.2-rc1](rc/3.0.2-rc1) - 5 September 2012 From 6028cf1b625ae268c7c3e08b5f5afb265a32c598 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Mon, 17 Dec 2012 15:13:43 +0100 Subject: [PATCH 21/73] Fixed panel spacing regressions from 544d2eb6 Specifically, the change removed the "add page" panel padding, because it moved padding from .cms-panel-padded into commonly contained elements, like .ui-tabs-panel. Apart from breaking layouts, it makes the class meaningless, since its only padded depending on which elements it contains. In order to rectify some introduced inconsistencies, much too complex were required, e.g. .ui-tabs .cms-edit-form, .ui-tabs .cms-content-fields {...}. --- admin/css/screen.css | 26 +++++++--------- admin/scss/_style.scss | 62 ++++++++++++++++---------------------- css/AssetUploadField.css | 2 +- scss/AssetUploadField.scss | 1 - 4 files changed, 38 insertions(+), 53 deletions(-) diff --git a/admin/css/screen.css b/admin/css/screen.css index 9c9db5c3c..b43726bb8 100644 --- a/admin/css/screen.css +++ b/admin/css/screen.css @@ -371,10 +371,10 @@ body.cms { overflow: hidden; } /** -------------------------------------------- Tabs -------------------------------------------- */ .ui-tabs { padding: 0; background: none; } .ui-tabs .ui-tabs { position: static; } -.ui-tabs .ui-tabs-panel { padding: 8px 0; background: transparent; border: 0; } +.ui-tabs .ui-tabs-panel { padding: 16px; background: transparent; border: 0; } .ui-tabs .ui-tabs-panel.cms-edit-form { padding: 0; } .ui-tabs .ui-widget-header { border: 0; background: none; } -.ui-tabs .ui-tabs-nav { float: right; margin: 0 0 -1px 0; padding: 0 12px 0 0; border-bottom: none; } +.ui-tabs .ui-tabs-nav { float: right; margin: 16px 0 -1px 0; padding: 0 12px 0 0; border-bottom: none; } .ui-tabs .ui-tabs-nav ~ .ui-tabs-panel { border-top: 1px solid #c0c0c2; clear: both; } .ui-tabs .ui-tabs-nav li { top: 0; float: left; border-bottom: 0 !important; } .ui-tabs .ui-tabs-nav li a { display: -moz-inline-stack; display: inline-block; vertical-align: middle; *vertical-align: auto; zoom: 1; *display: inline; float: none; font-weight: bold; color: #444444; line-height: 32px; padding: 0 16px 0; } @@ -396,20 +396,13 @@ body.cms { overflow: hidden; } .ui-tabs .ui-tabs-nav li.cms-tabset-icon.gallery.ui-state-active a { background: url('../images/sprites-64x64-s88957ee578.png') 0 -54px no-repeat; } .ui-tabs .ui-tabs-nav li.cms-tabset-icon.edit.ui-state-active a { background: url('../images/sprites-64x64-s88957ee578.png') 0 -404px no-repeat; } .ui-tabs .ui-tabs-nav li.cms-tabset-icon.search.ui-state-active a { background: url('../images/sprites-64x64-s88957ee578.png') 0 -104px no-repeat; } -.ui-tabs .cms-edit-form, .ui-tabs .cms-content-fields { /*not sure if .cms-content-fields effects other areas*/ } -.ui-tabs .cms-edit-form .cms-panel-padded, .ui-tabs .cms-content-fields .cms-panel-padded { /* Has padded area inside it */ padding: 0; margin: 0; } -.ui-tabs .cms-edit-form .ui-tabs-panel, .ui-tabs .cms-edit-form .ss-gridfield, .ui-tabs .cms-content-fields .ui-tabs-panel, .ui-tabs .cms-content-fields .ss-gridfield { margin: 12px; padding: 0 0 12px; } -.ui-tabs .cms-edit-form .ui-tabs-panel .ss-gridfield, .ui-tabs .cms-edit-form .ss-gridfield .ss-gridfield, .ui-tabs .cms-content-fields .ui-tabs-panel .ss-gridfield, .ui-tabs .cms-content-fields .ss-gridfield .ss-gridfield { /* Files area & inside second level tabs */ padding: 0; /* should be zero ideally */ margin: 0 0 12px; } -.ui-tabs .cms-edit-form .ui-tabs-nav, .ui-tabs .cms-content-fields .ui-tabs-nav { margin: 10px 12px 0; padding: 0 8px 0 0; /* second set of tabs */ } -.ui-tabs .cms-edit-form #tree_actions .ui-tabs-nav, .ui-tabs .cms-content-fields #tree_actions .ui-tabs-nav { margin: 0; } -.ui-tabs .cms-panel-padded h3 { margin-left: 12px; /* reports headers, probably too specific */ } -.ui-tabs .cms-panel-padded .ui-tabs-panel { margin: 0; padding: 12px 12px 12px; } +.ui-tabs .cms-panel-padded .ui-tabs-panel { padding: 0; } .ui-tabs .cms-panel-padded .ui-tabs-panel .ui-tabs-panel { padding: 8px 0 0 0; } -.ui-tabs .ui-tabs .ui-tabs-panel { /* second level tabs */ padding-top: 8px; } +.ui-tabs .cms-panel-padded .Actions { padding: 0; } .ui-tabs.ss-tabset-tabshidden .ui-tabs-panel { border-top: none; } /** Primary styles which sit on top of screen, with different tab colors. TODO Only use one "primary" selector and fix HTMLEditorField TabSet addExtraClass() */ -.ui-tabs.cms-tabset-primary .ui-tabs-nav, .ui-tabs .ui-tabs-nav.cms-tabset-nav-primary, .ui-tabs .cms-content-header-tabs .ui-tabs-nav { border-left: 1px solid #b3b3b3; float: none; } +.ui-tabs.cms-tabset-primary .ui-tabs-nav, .ui-tabs .ui-tabs-nav.cms-tabset-nav-primary, .ui-tabs .cms-content-header-tabs .ui-tabs-nav { margin-top: 0; border-left: 1px solid #b3b3b3; float: none; } .ui-tabs.cms-tabset-primary .ui-tabs-nav li, .ui-tabs .ui-tabs-nav.cms-tabset-nav-primary li, .ui-tabs .cms-content-header-tabs .ui-tabs-nav li { margin-right: 0; margin-top: 0; } .ui-tabs.cms-tabset-primary .ui-tabs-nav li a, .ui-tabs .ui-tabs-nav.cms-tabset-nav-primary li a, .ui-tabs .cms-content-header-tabs .ui-tabs-nav li a { margin: 0; line-height: 39px; } .ui-tabs.cms-tabset-primary .ui-tabs-nav .ui-corner-all, .ui-tabs.cms-tabset-primary .ui-tabs-nav .ui-corner-top, .ui-tabs.cms-tabset-primary .ui-tabs-nav .ui-corner-right, .ui-tabs.cms-tabset-primary .ui-tabs-nav .ui-corner-tr, .ui-tabs.cms-tabset-primary .ui-tabs-nav .ui-corner-tl, .ui-tabs .ui-tabs-nav.cms-tabset-nav-primary .ui-corner-all, .ui-tabs .ui-tabs-nav.cms-tabset-nav-primary .ui-corner-top, .ui-tabs .ui-tabs-nav.cms-tabset-nav-primary .ui-corner-right, .ui-tabs .ui-tabs-nav.cms-tabset-nav-primary .ui-corner-tr, .ui-tabs .ui-tabs-nav.cms-tabset-nav-primary .ui-corner-tl, .ui-tabs .cms-content-header-tabs .ui-tabs-nav .ui-corner-all, .ui-tabs .cms-content-header-tabs .ui-tabs-nav .ui-corner-top, .ui-tabs .cms-content-header-tabs .ui-tabs-nav .ui-corner-right, .ui-tabs .cms-content-header-tabs .ui-tabs-nav .ui-corner-tr, .ui-tabs .cms-content-header-tabs .ui-tabs-nav .ui-corner-tl { border-radius: 0; } @@ -442,7 +435,8 @@ body.cms { overflow: hidden; } .message.good { background-color: #eaf6e4; border-color: #72c34b; } .message p { margin: 0; } -p.message { margin-bottom: 12px; } +.cms-edit-form .message { margin: 16px; } +.cms-edit-form .ui-tabs-panel .message { margin: 0 0 16px 0; } /** -------------------------------------------- Page icons -------------------------------------------- */ .page-icon, a .jstree-pageicon { display: block; width: 16px; height: 16px; background: transparent url(../images/sitetree_ss_pageclass_icons_default.png) no-repeat; } @@ -492,7 +486,7 @@ p.message { margin-bottom: 12px; } .cms-content-tools { background: #eceff1; width: 200px; overflow-y: auto; overflow-x: hidden; z-index: 70; border-right: 1px solid #c0c0c2; -webkit-box-shadow: rgba(248, 248, 248, 0.9) -1px 0 0 inset, 0 0 1px rgba(201, 205, 206, 0.8); -moz-box-shadow: rgba(248, 248, 248, 0.9) -1px 0 0 inset, 0 0 1px rgba(201, 205, 206, 0.8); box-shadow: rgba(248, 248, 248, 0.9) -1px 0 0 inset, 0 0 1px rgba(201, 205, 206, 0.8); float: left; position: relative; } .cms-content-tools.filter { padding: 0 !important; } .cms-content-tools .cms-panel-header { clear: both; margin: 0 0 7px; line-height: 24px; border-bottom: 1px solid #d0d3d5; -webkit-box-shadow: 0 1px 0 rgba(248, 248, 248, 0.9); -moz-box-shadow: 0 1px 0 rgba(248, 248, 248, 0.9); -o-box-shadow: 0 1px 0 rgba(248, 248, 248, 0.9); box-shadow: 0 1px 0 rgba(248, 248, 248, 0.9); } -.cms-content-tools .cms-panel-content { width: 184px; padding: 8px 8px 0; overflow: auto; height: 100%; } +.cms-content-tools .cms-panel-content { width: 184px; padding: 16px 8px 0; overflow: auto; height: 100%; } .cms-content-tools .cms-panel-content .Actions .ss-ui-action-constructive { margin-right: 5px; } .cms-content-tools .cms-content-header { background-color: #748d9d; background-image: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4gPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGRlZnM+PGxpbmVhckdyYWRpZW50IGlkPSJncmFkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjUwJSIgeTE9IjAlIiB4Mj0iNTAlIiB5Mj0iMTAwJSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iI2IwYmVjNyIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzc0OGQ5ZCIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjAiIHk9IjAiIHdpZHRoPSIxMDAlIiBoZWlnaHQ9IjEwMCUiIGZpbGw9InVybCgjZ3JhZCkiIC8+PC9zdmc+IA=='); background-size: 100%; background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #b0bec7), color-stop(100%, #748d9d)); background-image: -webkit-linear-gradient(#b0bec7, #748d9d); background-image: -moz-linear-gradient(#b0bec7, #748d9d); background-image: -o-linear-gradient(#b0bec7, #748d9d); background-image: linear-gradient(#b0bec7, #748d9d); } .cms-content-tools .cms-content-header h2 { text-shadow: #5c7382 -1px -1px 0; width: 176px; color: white; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; -o-text-overflow: ellipsis; } @@ -538,7 +532,7 @@ p.message { margin-bottom: 12px; } /** -------------------------------------------- Member Profile -------------------------------------------- */ form.member-profile-form { padding: 0 16px 0 0; } form.member-profile-form #Root_Permissions { clear: both; border-top: 1px solid #a6a6a6; } -form.member-profile-form #Root_Main { clear: both; border-top: 1px solid #a6a6a6; padding-top: 16px; } +form.member-profile-form #Root_Main { clear: both; border-top: 1px solid #a6a6a6; } form.member-profile-form #Root_Main .cms-help-toggle { text-indent: -9999em; display: inline-block; width: 20px; background: url(../images/question.png) no-repeat 0px 0px; } form.member-profile-form #FavouritePageID { margin-top: 8px; } form.member-profile-form #CsvFile .middleColumn { background: none !important; } @@ -595,6 +589,8 @@ form.member-profile-form #Permissions .optionset li { float: none; width: auto; .cms-panel .collapsed-flyout { display: block !important; left: 41px; margin-top: -40px; position: fixed; width: 191px; } .cms-panel .collapsed-flyout li a span { display: block !important; } +.cms .cms-panel-padded { padding: 16px 16px; margin: 0; } + /** ------------------------------------------------------------------ * Dialog * diff --git a/admin/scss/_style.scss b/admin/scss/_style.scss index 0cdc4c8a5..2b2482229 100644 --- a/admin/scss/_style.scss +++ b/admin/scss/_style.scss @@ -159,7 +159,7 @@ body.cms { } .ui-tabs-panel { - padding: $grid-x 0; + padding: $grid-x*2; background: transparent; // default it's white border: 0; // suppress default borders &.cms-edit-form { @@ -174,7 +174,7 @@ body.cms { .ui-tabs-nav { float: right; - margin: 0 0 -1px 0; + margin: $grid-x*2 0 -1px 0; padding: 0 $grid-x*1.5 0 0; border-bottom: none; @@ -250,43 +250,17 @@ body.cms { } } - .cms-edit-form, .cms-content-fields { /*not sure if .cms-content-fields effects other areas*/ - .cms-panel-padded { /* Has padded area inside it */ - padding: 0; - margin: 0; - } - .ui-tabs-panel, .ss-gridfield { - margin: 12px; - padding: 0 0 12px; - .ss-gridfield { /* Files area & inside second level tabs */ - padding: 0; /* should be zero ideally */ - margin: 0 0 12px; - } - } - .ui-tabs-nav { - margin: 10px 12px 0; - padding: 0 8px 0 0; /* second set of tabs */ - } - #tree_actions .ui-tabs-nav{ - margin: 0; - } - } - .cms-panel-padded { - h3 { - margin-left: 12px; /* reports headers, probably too specific */ - } .ui-tabs-panel { - margin: 0; - padding: 12px 12px 12px; + padding: 0; // Avoid double padding with parent .ui-tabs-panel { padding: $grid-x 0 0 0; } } - } - .ui-tabs .ui-tabs-panel { /* second level tabs */ - padding-top: 8px; + .Actions { + padding: 0; // Avoid double padding with parent + } } &.ss-tabset-tabshidden .ui-tabs-panel { @@ -301,6 +275,7 @@ body.cms { .ui-tabs.cms-tabset-primary .ui-tabs-nav, .ui-tabs .ui-tabs-nav.cms-tabset-nav-primary, .ui-tabs .cms-content-header-tabs .ui-tabs-nav { + margin-top: 0; border-left: 1px solid darken($color-tab, 15%); float: none; // parent container is already right floated @@ -483,8 +458,17 @@ body.cms { margin: 0; } } -p.message { - margin-bottom: $grid-y*1.5; + + +.cms-edit-form { + .message { + margin: $grid-x*2; // TODO Remove double padding when adjacent to a padded tabs panel + } + .ui-tabs-panel { + .message { + margin: 0 0 $grid-x*2 0; // gets padding from tab panel + } + } } /** -------------------------------------------- @@ -704,7 +688,7 @@ p.message { .cms-panel-content { width: ($grid-x * 23); - padding: $grid-x $grid-x 0; + padding: $grid-x*2 $grid-x 0; // smaller left/right padding to use space efficiently overflow: auto; height:100%; @@ -924,7 +908,6 @@ form.member-profile-form { #Root_Main { clear:both; border-top: 1px solid darken($color-tab, 20%); - padding-top:$grid-y*2; .cms-help-toggle { text-indent: -9999em; display: inline-block; @@ -1210,6 +1193,13 @@ form.member-profile-form { } } +.cms { + .cms-panel-padded { + padding: $grid-y*2 $grid-x*2; + margin:0; + } +} + /** ------------------------------------------------------------------ * Dialog * diff --git a/css/AssetUploadField.css b/css/AssetUploadField.css index ad090f63c..9b997cff3 100644 --- a/css/AssetUploadField.css +++ b/css/AssetUploadField.css @@ -12,7 +12,7 @@ Used in side panels and action tabs */ .ss-uploadfield-view-allowed-extensions { padding-top: 20px; clear: both; max-width: 750px; display: block; } -#AssetUploadField { border-bottom: 0; -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; padding: 12px; } +#AssetUploadField { border-bottom: 0; -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; } .backlink { padding-left: 12px; } diff --git a/scss/AssetUploadField.scss b/scss/AssetUploadField.scss index e3b0b2ef0..a96b24c6a 100644 --- a/scss/AssetUploadField.scss +++ b/scss/AssetUploadField.scss @@ -17,7 +17,6 @@ #AssetUploadField { border-bottom: 0; @include box-shadow(none); - padding: 12px; } .backlink { padding-left: 12px; From 546d202f3a7d1ac5139f5b9908c67be3d7c427e9 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Mon, 17 Dec 2012 15:33:12 +0100 Subject: [PATCH 22/73] Don't complain about pre-replaced YAML fixture relations --- dev/FixtureBlueprint.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dev/FixtureBlueprint.php b/dev/FixtureBlueprint.php index 0b01458d6..c3cc97c4e 100644 --- a/dev/FixtureBlueprint.php +++ b/dev/FixtureBlueprint.php @@ -129,8 +129,9 @@ class FixtureBlueprint { $parsedItems = array(); $items = preg_split('/ *, */',trim($fieldVal)); foreach($items as $item) { - // Check for correct format: =>. - if(!preg_match('/^=>[^\.]+\.[^\.]+/', $item)) { + // Check for correct format: =>.. + // Ignore if the item has already been replaced with a numeric DB identifier + if(!is_numeric($item) && !preg_match('/^=>[^\.]+\.[^\.]+/', $item)) { throw new InvalidArgumentException(sprintf( 'Invalid format for relation "%s" on class "%s" ("%s")', $fieldName, From 7950584b3acaed68394d84735994b7201ef6cef6 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Mon, 17 Dec 2012 15:46:09 +0100 Subject: [PATCH 23/73] SimpleXML string casting in tests for older PHPUnit --- tests/api/XMLDataFormatterTest.php | 6 +++--- tests/forms/HtmlEditorFieldTest.php | 8 ++++---- tests/forms/SelectionGroupTest.php | 12 ++++++------ 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/api/XMLDataFormatterTest.php b/tests/api/XMLDataFormatterTest.php index 414cce108..49388a2e0 100644 --- a/tests/api/XMLDataFormatterTest.php +++ b/tests/api/XMLDataFormatterTest.php @@ -50,16 +50,16 @@ class XMLDataFormatterTest extends SapphireTest { $page->Content = 'This is some test content [test_shortcode]test[/test_shortcode]'; $xml = new SimpleXMLElement('' . $formatter->convertDataObjectWithoutHeader($page)); - $this->assertEquals('This is some test content test', $xml->Content); + $this->assertEquals('This is some test content test', (string)$xml->Content); $page->Content = '[test_shortcode,id=-1]'; $xml = new SimpleXMLElement('' . $formatter->convertDataObjectWithoutHeader($page)); - $this->assertEmpty('', $xml->Content); + $this->assertEmpty('', (string)$xml->Content); $page->Content = '[bad_code,id=1]'; $xml = new SimpleXMLElement('' . $formatter->convertDataObjectWithoutHeader($page)); - $this->assertContains('[bad_code,id=1]', $xml->Content); + $this->assertContains('[bad_code,id=1]', (string)$xml->Content); } /** diff --git a/tests/forms/HtmlEditorFieldTest.php b/tests/forms/HtmlEditorFieldTest.php index cb11563ea..9d55226d3 100644 --- a/tests/forms/HtmlEditorFieldTest.php +++ b/tests/forms/HtmlEditorFieldTest.php @@ -46,16 +46,16 @@ class HtmlEditorFieldTest extends FunctionalTest { $parser = new CSSContentParser($obj->Content); $xml = $parser->getByXpath('//img'); - $this->assertEquals('', $xml[0]['alt'], 'Alt tags are added by default.'); - $this->assertEquals('', $xml[0]['title'], 'Title tags are added by default.'); + $this->assertEquals('', (string)$xml[0]['alt'], 'Alt tags are added by default.'); + $this->assertEquals('', (string)$xml[0]['title'], 'Title tags are added by default.'); $editor->setValue('foo'); $editor->saveInto($obj); $parser = new CSSContentParser($obj->Content); $xml = $parser->getByXpath('//img'); - $this->assertEquals('foo', $xml[0]['alt'], 'Alt tags are preserved.'); - $this->assertEquals('bar', $xml[0]['title'], 'Title tags are preserved.'); + $this->assertEquals('foo', (string)$xml[0]['alt'], 'Alt tags are preserved.'); + $this->assertEquals('bar', (string)$xml[0]['title'], 'Title tags are preserved.'); } public function testMultiLineSaving() { diff --git a/tests/forms/SelectionGroupTest.php b/tests/forms/SelectionGroupTest.php index e418639c6..924a54627 100644 --- a/tests/forms/SelectionGroupTest.php +++ b/tests/forms/SelectionGroupTest.php @@ -23,8 +23,8 @@ class SelectionGroupTest extends SapphireTest { $this->assertEquals('one', (string)$listElOne->input[0]['value']); $this->assertEquals('two', (string)$listElTwo->input[0]['value']); - $this->assertEquals('one title', $listElOne->label[0]); - $this->assertEquals('two title', $listElTwo->label[0]); + $this->assertEquals('one title', (string)$listElOne->label[0]); + $this->assertEquals('two title', (string)$listElTwo->label[0]); $this->assertContains('one view', (string)$listElOne->div); $this->assertContains('two view', (string)$listElTwo->div); @@ -44,8 +44,8 @@ class SelectionGroupTest extends SapphireTest { $this->assertEquals('one', (string)$listElOne->input[0]['value']); $this->assertEquals('two', (string)$listElTwo->input[0]['value']); - $this->assertEquals('one', $listElOne->label[0]); - $this->assertEquals('two', $listElTwo->label[0]); + $this->assertEquals('one', (string)$listElOne->label[0]); + $this->assertEquals('two', (string)$listElTwo->label[0]); } function testLegacyItemsFieldHolderWithTitle() { @@ -62,8 +62,8 @@ class SelectionGroupTest extends SapphireTest { $this->assertEquals('one', (string)$listElOne->input[0]['value']); $this->assertEquals('two', (string)$listElTwo->input[0]['value']); - $this->assertEquals('one title', $listElOne->label[0]); - $this->assertEquals('two title', $listElTwo->label[0]); + $this->assertEquals('one title', (string)$listElOne->label[0]); + $this->assertEquals('two title', (string)$listElTwo->label[0]); } } \ No newline at end of file From 8f239d63731e6a621aef784166e0ecbb382e5bd0 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Mon, 17 Dec 2012 15:52:01 +0100 Subject: [PATCH 24/73] SimpleXML string casting in tests for older PHPUnit --- tests/api/XMLDataFormatterTest.php | 8 ++++---- tests/forms/HtmlEditorFieldTest.php | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/api/XMLDataFormatterTest.php b/tests/api/XMLDataFormatterTest.php index 414cce108..cca690fec 100644 --- a/tests/api/XMLDataFormatterTest.php +++ b/tests/api/XMLDataFormatterTest.php @@ -39,7 +39,7 @@ class XMLDataFormatterTest extends SapphireTest { $this->assertEquals( 'mysite.com is a link in this HTML content.' . ' ', - (string) $xml->Content + (string)$xml->Content ); } @@ -50,16 +50,16 @@ class XMLDataFormatterTest extends SapphireTest { $page->Content = 'This is some test content [test_shortcode]test[/test_shortcode]'; $xml = new SimpleXMLElement('' . $formatter->convertDataObjectWithoutHeader($page)); - $this->assertEquals('This is some test content test', $xml->Content); + $this->assertEquals('This is some test content test', (string)$xml->Content); $page->Content = '[test_shortcode,id=-1]'; $xml = new SimpleXMLElement('' . $formatter->convertDataObjectWithoutHeader($page)); - $this->assertEmpty('', $xml->Content); + $this->assertEmpty('', (string)$xml->Content); $page->Content = '[bad_code,id=1]'; $xml = new SimpleXMLElement('' . $formatter->convertDataObjectWithoutHeader($page)); - $this->assertContains('[bad_code,id=1]', $xml->Content); + $this->assertContains('[bad_code,id=1]', (string)$xml->Content); } /** diff --git a/tests/forms/HtmlEditorFieldTest.php b/tests/forms/HtmlEditorFieldTest.php index cb11563ea..9d55226d3 100644 --- a/tests/forms/HtmlEditorFieldTest.php +++ b/tests/forms/HtmlEditorFieldTest.php @@ -46,16 +46,16 @@ class HtmlEditorFieldTest extends FunctionalTest { $parser = new CSSContentParser($obj->Content); $xml = $parser->getByXpath('//img'); - $this->assertEquals('', $xml[0]['alt'], 'Alt tags are added by default.'); - $this->assertEquals('', $xml[0]['title'], 'Title tags are added by default.'); + $this->assertEquals('', (string)$xml[0]['alt'], 'Alt tags are added by default.'); + $this->assertEquals('', (string)$xml[0]['title'], 'Title tags are added by default.'); $editor->setValue('foo'); $editor->saveInto($obj); $parser = new CSSContentParser($obj->Content); $xml = $parser->getByXpath('//img'); - $this->assertEquals('foo', $xml[0]['alt'], 'Alt tags are preserved.'); - $this->assertEquals('bar', $xml[0]['title'], 'Title tags are preserved.'); + $this->assertEquals('foo', (string)$xml[0]['alt'], 'Alt tags are preserved.'); + $this->assertEquals('bar', (string)$xml[0]['title'], 'Title tags are preserved.'); } public function testMultiLineSaving() { From 0d37cd3e69efd590f18901a426bd0b47a671929f Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Mon, 17 Dec 2012 16:40:33 +0100 Subject: [PATCH 25/73] Updated changelog --- docs/en/changelogs/beta/3.1.0-beta1.md | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/docs/en/changelogs/beta/3.1.0-beta1.md b/docs/en/changelogs/beta/3.1.0-beta1.md index 29ca133b3..9e3e13042 100644 --- a/docs/en/changelogs/beta/3.1.0-beta1.md +++ b/docs/en/changelogs/beta/3.1.0-beta1.md @@ -30,6 +30,8 @@ See [3.1.0 release notes](/changelogs/3.1.0) ### API Changes + * 2012-12-17 [bbc8e06](https://github.com/silverstripe/sapphire/commit/bbc8e06) Show GridFieldEditButton even without edit permissions (for readonly forms) (Ingo Schommer) + * 2012-12-17 [1848d7e](https://github.com/silverstripe/sapphire/commit/1848d7e) Check model permissions in GridField (Ingo Schommer) * 2012-12-14 [644cc79](https://github.com/silverstripe/sapphire/commit/644cc79) Removed methods previously deprecated in 3.0 (Ingo Schommer) * 2012-12-13 [6f9d01f](https://github.com/silverstripe/sapphire/commit/6f9d01f) FormField->setDescription() visible in default template (Ingo Schommer) * 2012-12-13 [559abec](https://github.com/silverstripe/sapphire/commit/559abec) Copying instance props on FormField readonly/disabled transformations (Ingo Schommer) @@ -37,8 +39,6 @@ See [3.1.0 release notes](/changelogs/3.1.0) * 2012-12-12 [27113f8](https://github.com/silverstripe/sapphire/commit/27113f8) Make DataList and ArrayList immutable (Hamish Friedlander) * 2012-12-10 [e6e47cb](https://github.com/silverstripe/sapphire/commit/e6e47cb) DB-specific comparisators in SearchFilter and DataList (Ingo Schommer) * 2012-12-11 [4d6d823](https://github.com/silverstripe/sapphire/commit/4d6d823) Allow ignoring persistent tab state through entwine property. (Mateusz Uzdowski) - * 2012-12-10 [efa9ff9](https://github.com/silverstripe/sapphire/commit/efa9ff9) Queries added by DataList::addInnerJoin() and DataList::leftJoin() come after the base joins, not before. (stojg) - * 2012-12-06 [c6b1d4a](https://github.com/silverstripe/sapphire/commit/c6b1d4a) Storing alternative DB name in cookie rather than session (Ingo Schommer) * 2012-12-04 [4fa2b0f](https://github.com/silverstripe/sapphire/commit/4fa2b0f) Support disabling/enabling of previews. (Mateusz Uzdowski) * 2012-12-03 [5fed5b9](https://github.com/silverstripe/sapphire/commit/5fed5b9) Moved email bounce handling to new 'emailbouncehandler' module (Ingo Schommer) * 2012-12-03 [fb076c0](https://github.com/silverstripe/sapphire/commit/fb076c0) Deprecated global email methods, moved to Mailer class (Ingo Schommer) @@ -100,21 +100,22 @@ See [3.1.0 release notes](/changelogs/3.1.0) ### Bugfixes + * 2012-12-17 [6028cf1](https://github.com/silverstripe/sapphire/commit/6028cf1) ed panel spacing regressions from 544d2eb6 (Ingo Schommer) + * 2012-12-17 [cc536f6](https://github.com/silverstripe/silverstripe-cms/commit/cc536f6) ed "last edited" display in CMS actions (Ingo Schommer) + * 2012-12-17 [a823c38](https://github.com/silverstripe/sapphire/commit/a823c38) ed JS syntax error (Ingo Schommer) * 2012-12-16 [bf5590d](https://github.com/silverstripe/sapphire/commit/bf5590d) Fix side-by-side initial icon display issue in IE8. (Mateusz Uzdowski) * 2012-12-16 [8455686](https://github.com/silverstripe/sapphire/commit/8455686) Fix the re-layouting not being triggered in IE8. (Mateusz Uzdowski) + * 2012-12-15 [22eeaa4](https://github.com/silverstripe/sapphire/commit/22eeaa4) Members should not be allowed to delete themselves (fixes #8121) (Ingo Schommer) * 2012-12-15 [b365714](https://github.com/silverstripe/sapphire/commit/b365714) Remove "delete" button from "My Profile" (fixes #8121) (Ingo Schommer) * 2012-12-15 [c2d31e5](https://github.com/silverstripe/silverstripe-cms/commit/c2d31e5) Hiding group selections in "Settings" (Ingo Schommer) * 2012-12-14 [d2c1d53](https://github.com/silverstripe/sapphire/commit/d2c1d53) ed UploadField->setDescription() handlgin (Ingo Schommer) * 2012-12-14 [74d6379](https://github.com/silverstripe/silverstripe-cms/commit/74d6379) ed regression in SiteTree->getCMSActions() (Ingo Schommer) - * 2012-12-14 [f41f307](https://github.com/silverstripe/sapphire/commit/f41f307) ed spacing (Ingo Schommer) * 2012-12-13 [a355e1d](https://github.com/silverstripe/sapphire/commit/a355e1d) Set visibility on login form methods to public. (Justin Martin) - * 2012-12-13 [d42c004](https://github.com/silverstripe/silverstripe-cms/commit/d42c004) Fixed pagination functionality on root assets folder (Niklas Forsdahl) * 2012-12-13 [006790b](https://github.com/silverstripe/sapphire/commit/006790b) ed IE7 GridField "add row" alignment issue (Ingo Schommer) * 2012-12-13 [0ba51c1](https://github.com/silverstripe/sapphire/commit/0ba51c1) to allow buttons to align inline (fixes #8099) (Paul Clarke) * 2012-12-13 [bdc3e91](https://github.com/silverstripe/sapphire/commit/bdc3e91) ed wrong floating on GridField certain buttons (Ingo Schommer) * 2012-12-13 [bd59f84](https://github.com/silverstripe/sapphire/commit/bd59f84) Make sure you can only remove items from a DataList that are actually in it (Hamish Friedlander) * 2012-12-13 [9979b11](https://github.com/silverstripe/sapphire/commit/9979b11) Make sure ArrayList#limit uses clone so for subclasses it returns instances of same subclass (Hamish Friedlander) - * 2012-12-12 [639cc02](https://github.com/silverstripe/sapphire/commit/639cc02) Fix insert media form inserting images from other UploadFields (fixes #8051) (Loz Calver) * 2012-12-12 [546762e](https://github.com/silverstripe/silverstripe-cms/commit/546762e) use of DataList#innerJoin expecting it to be mutable (Hamish Friedlander) * 2012-12-12 [c0a1226](https://github.com/silverstripe/sapphire/commit/c0a1226) fix and code clean up (Paul Clarke) * 2012-12-12 [5d93f8d](https://github.com/silverstripe/sapphire/commit/5d93f8d) fix preview note "Website preview" (Paul Clarke) @@ -122,7 +123,6 @@ See [3.1.0 release notes](/changelogs/3.1.0) * 2012-12-11 [9803459](https://github.com/silverstripe/sapphire/commit/9803459) ed SelectionGroupTest (Ingo Schommer) * 2012-12-10 [084acc0](https://github.com/silverstripe/silverstripe-cms/commit/084acc0) ed Behat tests for preview feature (Ingo Schommer) * 2012-12-10 [0fd6d14](https://github.com/silverstripe/sapphire/commit/0fd6d14) ed Behat steps for preview feature (Ingo Schommer) - * 2012-12-07 [4f63f91](https://github.com/silverstripe/sapphire/commit/4f63f91) Fixed issue with convertServiceProperty (Marcus Nyeholt) * 2012-12-04 [4d106aa](https://github.com/silverstripe/sapphire/commit/4d106aa) Fixed unintentional ParentID reset in "add page" form (Ingo Schommer) * 2012-12-04 [b8c656b](https://github.com/silverstripe/sapphire/commit/b8c656b) ed cms extension docs to remove zzz_admin workaround (Ingo Schommer) * 2012-12-04 [65002f6](https://github.com/silverstripe/sapphire/commit/65002f6) GD::greyscale did not correctly preserve alpha component of images Added test cases to test greyscale operation across various image formats Replaced various magic numbers with IMAGETYPE_XXX definitions (Damian Mooyman) @@ -183,6 +183,15 @@ See [3.1.0 release notes](/changelogs/3.1.0) ### Other + * 2012-12-17 [7950584](https://github.com/silverstripe/sapphire/commit/7950584) SimpleXML string casting in tests for older PHPUnit (Ingo Schommer) + * 2012-12-17 [546d202](https://github.com/silverstripe/sapphire/commit/546d202) Don't complain about pre-replaced YAML fixture relations (Ingo Schommer) + * 2012-12-17 [407a19c](https://github.com/silverstripe/sapphire/commit/407a19c) Beta changelog links (Ingo Schommer) + * 2012-12-17 [c1bd143](https://github.com/silverstripe/sapphire/commit/c1bd143) Tab spacing (regression from 2d075671) (Ingo Schommer) + * 2012-12-17 [375c33e](https://github.com/silverstripe/sapphire/commit/375c33e) Wider sidebar to accommodate "add" and "edit" buttons (Ingo Schommer) + * 2012-12-17 [58d316e](https://github.com/silverstripe/silverstripe-cms/commit/58d316e) Moving "edit tree" button next to "add new" (fixes #8119) (Ingo Schommer) + * 2012-12-17 [9cfa7b7](https://github.com/silverstripe/sapphire/commit/9cfa7b7) Wider side panel to fit "add" and "edit" button (Ingo Schommer) + * 2012-12-17 [17908b6](https://github.com/silverstripe/sapphire/commit/17908b6) Revert CMS button style (regression from fe08236) (Ingo Schommer) + * 2012-12-17 [3da41ef](https://github.com/silverstripe/sapphire/commit/3da41ef) Permission docs (Ingo Schommer) * 2012-12-15 [5b2cc19](https://github.com/silverstripe/silverstripe-cms/commit/5b2cc19) Added placeholder text to group listboxes (Ingo Schommer) * 2012-12-14 [e6bf199](https://github.com/silverstripe/sapphire/commit/e6bf199) Less far-future date assertions, seems to throw off some PHP installs (Ingo Schommer) * 2012-12-14 [4f5b3fa](https://github.com/silverstripe/sapphire/commit/4f5b3fa) Readd SQlite to travis builds, having it fail harms TDD (Ingo Schommer) From 77212c064768b03634c7f9e583fca90b9b9651d1 Mon Sep 17 00:00:00 2001 From: uniun Date: Mon, 17 Dec 2012 11:41:07 +0200 Subject: [PATCH 26/73] CMS Titles does not support UTF-8 Title in CMS is set using header X-Title. But UTF-8 characters can't be used in HTTP headers. So the title should be encoded just before sending X-Title header and decoded before setting HTML document title (fixes #7942). --- admin/code/LeftAndMain.php | 2 +- admin/javascript/LeftAndMain.js | 2 +- docs/en/reference/cms-architecture.md | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/admin/code/LeftAndMain.php b/admin/code/LeftAndMain.php index 27c2e6128..82fc5a56b 100644 --- a/admin/code/LeftAndMain.php +++ b/admin/code/LeftAndMain.php @@ -357,7 +357,7 @@ class LeftAndMain extends Controller implements PermissionProvider { $response = parent::handleRequest($request, $model); $title = $this->Title(); if(!$response->getHeader('X-Controller')) $response->addHeader('X-Controller', $this->class); - if(!$response->getHeader('X-Title')) $response->addHeader('X-Title', $title); + if(!$response->getHeader('X-Title')) $response->addHeader('X-Title', urlencode($title)); return $response; } diff --git a/admin/javascript/LeftAndMain.js b/admin/javascript/LeftAndMain.js index d90f991d0..0417bc151 100644 --- a/admin/javascript/LeftAndMain.js +++ b/admin/javascript/LeftAndMain.js @@ -462,7 +462,7 @@ jQuery.noConflict(); // Update title var title = xhr.getResponseHeader('X-Title'); - if(title) document.title = title; + if(title) document.title = decodeURIComponent(title.replace(/\+/g, ' ')); var newFragments = {}, newContentEls; // If content type is text/json (ignoring charset and other parameters) diff --git a/docs/en/reference/cms-architecture.md b/docs/en/reference/cms-architecture.md index eaf67207e..9caeca734 100644 --- a/docs/en/reference/cms-architecture.md +++ b/docs/en/reference/cms-architecture.md @@ -311,6 +311,7 @@ without affecting the response body. Built-in headers are: + * `X-Title`: Set window title (requires URL encoding) * `X-Controller`: PHP class name matching a menu entry, which is marked active * `X-ControllerURL`: Alternative URL to record in the HTML5 browser history * `X-Status`: Extended status information, used for an information popover. From 806637629040b555e0dfc110a1c53c3031e6f1d0 Mon Sep 17 00:00:00 2001 From: Loz Calver Date: Thu, 13 Dec 2012 14:25:56 +0000 Subject: [PATCH 27/73] ENHANCEMENT: LeftAndMain breadcrumbs to use MenuTitle Breadcrumbs in the CMS currently only use title, when MenuTitle is probably more appropriate (if it is set). --- admin/code/LeftAndMain.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/admin/code/LeftAndMain.php b/admin/code/LeftAndMain.php index 82fc5a56b..bcaf4f3e8 100644 --- a/admin/code/LeftAndMain.php +++ b/admin/code/LeftAndMain.php @@ -645,13 +645,13 @@ class LeftAndMain extends Controller implements PermissionProvider { $ancestors->push($record); foreach($ancestors as $ancestor) { $items->push(new ArrayData(array( - 'Title' => $ancestor->Title, + 'Title' => ($ancestor->MenuTitle) ? $ancestor->MenuTitle : $ancestor->Title, 'Link' => ($unlinked) ? false : Controller::join_links($this->Link('show'), $ancestor->ID) ))); } } else { $items->push(new ArrayData(array( - 'Title' => $record->Title, + 'Title' => ($record->MenuTitle) ? $record->MenuTitle : $record->Title, 'Link' => ($unlinked) ? false : Controller::join_links($this->Link('show'), $record->ID) ))); } From 0ee7bbf75cef2e3d2b49744e417d03c276d406af Mon Sep 17 00:00:00 2001 From: Justin Martin Date: Thu, 13 Dec 2012 09:56:26 -0800 Subject: [PATCH 28/73] BUG: Removed !important attribute of #Remember margin --- css/Security_login.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/css/Security_login.css b/css/Security_login.css index 92c56085e..8a3ba03c9 100644 --- a/css/Security_login.css +++ b/css/Security_login.css @@ -1,4 +1,4 @@ -#Remember { margin: 0.5em 0 0.5em 11em !important; } +#Remember { margin: 0.5em 0 0.5em 11em; } p#Remember label { display: inline-block; margin: 0; } From b01b91ffc376b7a047f9a7c910593c13ce63bc4c Mon Sep 17 00:00:00 2001 From: Damian Mooyman Date: Tue, 18 Dec 2012 10:11:30 +1300 Subject: [PATCH 29/73] BUG When selecting stage_unique from Versioned the augmentSQL function would permanantly alter the DataQuery while doing a recursive augmentSQL. This fix correctly maintains the correct Versioned.mode so that subsequent calls to this function exhibit the same expected behaviour. --- model/Versioned.php | 1 + 1 file changed, 1 insertion(+) diff --git a/model/Versioned.php b/model/Versioned.php index 7fab016e5..61c33dc1e 100644 --- a/model/Versioned.php +++ b/model/Versioned.php @@ -203,6 +203,7 @@ class Versioned extends DataExtension { // below) $dataQuery->setQueryParam('Versioned.mode', 'stage'); $this->augmentSQL($query, $dataQuery); + $dataQuery->setQueryParam('Versioned.mode', 'stage_unique'); // Now exclude any ID from any other stage. Note that we double rename to avoid the regular stage rename // renaming all subquery references to be Versioned.stage From 8779e9be5b3142bd6ee3d323415c6ee19680823c Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Mon, 17 Dec 2012 23:02:04 +0100 Subject: [PATCH 30/73] BUG Fixed changetracking for radio and checkbox field types Also removing the 'changed' class from the form once no further fields are marked as changed. That's important now that we're surfacing the state much more visibly through the alternative "save" button styles in the CMS. --- .../lib/jquery.changetracker.js | 32 ++++++++++++++++--- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/admin/javascript/jquery-changetracker/lib/jquery.changetracker.js b/admin/javascript/jquery-changetracker/lib/jquery.changetracker.js index 0aa5d18f4..854668b40 100644 --- a/admin/javascript/jquery-changetracker/lib/jquery.changetracker.js +++ b/admin/javascript/jquery-changetracker/lib/jquery.changetracker.js @@ -57,20 +57,42 @@ var onchange = function(e) { var $field = $(e.target); - var origVal = $field.data('changetracker.origVal'); - if(origVal === null || e.target.value != origVal) { - // TODO Also add class to radiobutton/checkbox siblings + var origVal = $field.data('changetracker.origVal'), newVal; + + // Determine value based on field type + if($field.is(':checkbox')) { + newVal = $field.is(':checked') ? 1 : 0; + } else { + newVal = $field.val(); + } + + // Determine changed state based on value comparisons + if(origVal === null || newVal != origVal) { $field.addClass(options.changedCssClass); self.addClass(options.changedCssClass); + } else { + $field.removeClass(options.changedCssClass); + // Unset changed state on all radio buttons of the same name + if($field.is(':radio')) { + self.find(':radio[name=' + $field.attr('name') + ']').removeClass(options.changedCssClass); + } + // Only unset form state if no other fields are changed as well + if(!self.getFields().filter('.' + options.changedCssClass).length) { + self.removeClass(options.changedCssClass); + } } }; // setup original values - var fields = this.getFields(); + var fields = this.getFields(), origVal; fields.filter(':radio,:checkbox').bind('click.changetracker', onchange); fields.not(':radio,:checkbox').bind('change.changetracker', onchange); fields.each(function() { - var origVal = $(this).is(':radio,:checkbox') ? self.find(':input[name=' + $(this).attr('name') + ']:checked').val() : $(this).val(); + if($(this).is(':radio,:checkbox')) { + origVal = self.find(':input[name=' + $(this).attr('name') + ']:checked').val(); + } else { + origVal = $(this).val(); + } $(this).data('changetracker.origVal', origVal); }); From 51c6a87fc7080d3d4e53a758882cd92e989e3c1d Mon Sep 17 00:00:00 2001 From: Paul Clarke Date: Thu, 13 Dec 2012 11:09:27 +1300 Subject: [PATCH 31/73] Fix for ie8 styles for preview switch and modes --- admin/css/ie7.css | 7 ++++--- admin/css/ie8.css | 7 ++++--- admin/scss/_ieShared.scss | 12 ++++++++---- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/admin/css/ie7.css b/admin/css/ie7.css index bc068612e..afffeb927 100644 --- a/admin/css/ie7.css +++ b/admin/css/ie7.css @@ -42,12 +42,13 @@ .filter-buttons button.ss-gridfield-button-filter { background-position: -18px 4px !important; } /* Alternative styles for the switch in old IE */ -fieldset.switch-states { padding: 0; } -fieldset.switch-states .switch { padding: 0 10px 0 0; } +fieldset.switch-states { padding-right: 5px; } +fieldset.switch-states .switch { padding: 0; width: 132%; left: -32px; } fieldset.switch-states .switch label { overflow: visible; text-overflow: visible; white-space: normal; padding: 0; } fieldset.switch-states .switch label.active { color: #fff; background-color: #2b9c32; } -fieldset.switch-states .switch label span { display: inline; padding: 0 10px; padding-right: 15px; overflow: visible; text-overflow: visible; white-space: wrap; } +fieldset.switch-states .switch label span { display: inline; padding: 0 8px; overflow: visible; text-overflow: visible; white-space: wrap; } fieldset.switch-states .switch .slide-button { display: none; } +fieldset.switch-states .switch input.state-name { margin-left: -20px; } /* Hide size controls in IE - they won't work as intended */ .cms-content-controls .preview-size-selector { display: none; } diff --git a/admin/css/ie8.css b/admin/css/ie8.css index dfdd196a4..569c11ab2 100644 --- a/admin/css/ie8.css +++ b/admin/css/ie8.css @@ -42,12 +42,13 @@ .filter-buttons button.ss-gridfield-button-filter { background-position: -18px 4px !important; } /* Alternative styles for the switch in old IE */ -fieldset.switch-states { padding: 0; } -fieldset.switch-states .switch { padding: 0 10px 0 0; } +fieldset.switch-states { padding-right: 5px; } +fieldset.switch-states .switch { padding: 0; width: 132%; left: -32px; } fieldset.switch-states .switch label { overflow: visible; text-overflow: visible; white-space: normal; padding: 0; } fieldset.switch-states .switch label.active { color: #fff; background-color: #2b9c32; } -fieldset.switch-states .switch label span { display: inline; padding: 0 10px; padding-right: 15px; overflow: visible; text-overflow: visible; white-space: wrap; } +fieldset.switch-states .switch label span { display: inline; padding: 0 8px; overflow: visible; text-overflow: visible; white-space: wrap; } fieldset.switch-states .switch .slide-button { display: none; } +fieldset.switch-states .switch input.state-name { margin-left: -20px; } /* Hide size controls in IE - they won't work as intended */ .cms-content-controls .preview-size-selector { display: none; } diff --git a/admin/scss/_ieShared.scss b/admin/scss/_ieShared.scss index 2c989544f..342344de9 100644 --- a/admin/scss/_ieShared.scss +++ b/admin/scss/_ieShared.scss @@ -142,9 +142,11 @@ /* Alternative styles for the switch in old IE */ fieldset.switch-states{ - padding:0; + padding-right: 5px; .switch{ - padding:0 10px 0 0; + padding: 0; + width: 100%+32; + left: -32px; label{ overflow:visible; text-overflow:visible; @@ -156,8 +158,7 @@ fieldset.switch-states{ } span{ display:inline; - padding:0 10px; - padding-right:15px; + padding:0 8px; overflow:visible; text-overflow:visible; white-space:wrap; @@ -166,6 +167,9 @@ fieldset.switch-states{ .slide-button{ display:none; } + input.state-name { + margin-left: -20px; + } } } /* Hide size controls in IE - they won't work as intended */ From af6eccea967d1574deb4d5f9c265a062b29b9ea4 Mon Sep 17 00:00:00 2001 From: Matt Lewis Date: Wed, 12 Dec 2012 11:00:52 +0000 Subject: [PATCH 32/73] Fixing typo in Requirements allowing access to files requested with query strings --- view/Requirements.php | 272 +++++++++++++++++++++--------------------- 1 file changed, 136 insertions(+), 136 deletions(-) diff --git a/view/Requirements.php b/view/Requirements.php index 8cbc5a322..98472920d 100644 --- a/view/Requirements.php +++ b/view/Requirements.php @@ -3,12 +3,12 @@ /** * Requirements tracker, for javascript and css. * @todo Document the requirements tracker, and discuss it with the others. - * + * * @package framework * @subpackage view */ class Requirements { - + /** * Enable combining of css/javascript files. * @param boolean $enable @@ -34,38 +34,38 @@ class Requirements { } /** - * Set whether we want to suffix requirements with the time / + * Set whether we want to suffix requirements with the time / * location on to the requirements - * + * * @param bool */ public static function set_suffix_requirements($var) { self::backend()->set_suffix_requirements($var); } - + /** * Return whether we want to suffix requirements - * + * * @return bool */ public static function get_suffix_requirements() { return self::backend()->get_suffix_requirements(); } - + /** * Instance of requirements for storage * * @var Requirements */ private static $backend = null; - + public static function backend() { if(!self::$backend) { self::$backend = new Requirements_Backend(); } return self::$backend; } - + /** * Setter method for changing the Requirements backend * @@ -74,20 +74,20 @@ class Requirements { public static function set_backend(Requirements_Backend $backend) { self::$backend = $backend; } - + /** * Register the given javascript file as required. - * + * * See {@link Requirements_Backend::javascript()} for more info - * + * */ public static function javascript($file) { self::backend()->javascript($file); } - + /** * Add the javascript code to the header of the page - * + * * See {@link Requirements_Backend::customScript()} for more info * @param script The script content * @param uniquenessID Use this to ensure that pieces of code only get added once. @@ -98,50 +98,50 @@ class Requirements { /** * Include custom CSS styling to the header of the page. - * + * * See {@link Requirements_Backend::customCSS()} - * + * * @param string $script CSS selectors as a string (without \n"; } - - foreach(array_diff_key($this->customHeadTags,$this->blocked) as $customHeadTag) { - $requirements .= "$customHeadTag\n"; + + foreach(array_diff_key($this->customHeadTags,$this->blocked) as $customHeadTag) { + $requirements .= "$customHeadTag\n"; } - + if($this->write_js_to_body) { // Remove all newlines from code to preserve layout $jsRequirements = preg_replace('/>\n*/', '>', $jsRequirements); - + // We put script tags into the body, for performance. - // If your template already has script tags in the body, then we put our script + // If your template already has script tags in the body, then we put our script // tags just before those. Otherwise, we put it at the bottom. $p2 = stripos($content, ']*>)/i", $jsRequirements . "\\1", $content); } - - // Put CSS at the bottom of the head + + // Put CSS at the bottom of the head $content = preg_replace("/(<\/head>)/i", $requirements . "\\1", $content); } else { $content = preg_replace("/(<\/head>)/i", $requirements . "\\1", $content); $content = preg_replace("/(<\/head>)/i", $jsRequirements . "\\1", $content); } - } - + } + return $content; } @@ -723,20 +723,20 @@ class Requirements_Backend { * Attach requirements inclusion to X-Include-JS and X-Include-CSS headers on the HTTP response */ public function include_in_response(SS_HTTPResponse $response) { - $this->process_combined_files(); + $this->process_combined_files(); $jsRequirements = array(); $cssRequirements = array(); - foreach(array_diff_key($this->javascript, $this->blocked) as $file => $dummy) { + foreach(array_diff_key($this->javascript, $this->blocked) as $file => $dummy) { $path = $this->path_for_file($file); if($path) { $jsRequirements[] = str_replace(',', '%2C', $path); } } - + $response->addHeader('X-Include-JS', implode(',', $jsRequirements)); - foreach(array_diff_key($this->css,$this->blocked) as $file => $params) { + foreach(array_diff_key($this->css,$this->blocked) as $file => $params) { $path = $this->path_for_file($file); if($path) { $path = str_replace(',', '%2C', $path); @@ -746,11 +746,11 @@ class Requirements_Backend { $response->addHeader('X-Include-CSS', implode(',', $cssRequirements)); } - + /** * Add i18n files from the given javascript directory. SilverStripe expects that the given directory * will contain a number of java script files named by language: en_US.js, de_DE.js, etc. - * + * * @param String The javascript lang directory, relative to the site root, e.g., 'framework/javascript/lang' * @param Boolean Return all relative file paths rather than including them in requirements * @param Boolean Only include language files, not the base libraries @@ -764,10 +764,10 @@ class Requirements_Backend { if(!$langOnly) $files[] = FRAMEWORK_DIR . '/javascript/i18n.js'; if(substr($langDir,-1) != '/') $langDir .= '/'; - + $files[] = $langDir . i18n::default_locale() . '.js'; $files[] = $langDir . i18n::get_locale() . '.js'; - + // Stub i18n implementation for when i18n is disabled. } else { if(!$langOnly) $files[] = FRAMEWORK_DIR . '/javascript/i18nx.js'; @@ -778,13 +778,13 @@ class Requirements_Backend { } else { foreach($files as $file) $this->javascript($file); } - } - + } + /** * Finds the path for specified file. * * @param string $fileOrUrl - * @return string|boolean + * @return string|boolean */ protected function path_for_file($fileOrUrl) { if(preg_match('{^//|http[s]?}', $fileOrUrl)) { @@ -794,7 +794,7 @@ class Requirements_Backend { $mtimesuffix = ""; $suffix = ''; if(strpos($fileOrUrl, '?') !== false) { - $suffix = '&' . substr($fileOrUrl, strpos($fileOrUrl, '?')+1); + $suffix = '?' . substr($fileOrUrl, strpos($fileOrUrl, '?')+1); $fileOrUrl = substr($fileOrUrl, 0, strpos($fileOrUrl, '?')); } if($this->suffix_requirements) { @@ -805,22 +805,22 @@ class Requirements_Backend { return false; } } - + /** * Concatenate several css or javascript files into a single dynamically generated * file (stored in {@link Director::baseFolder()}). This increases performance * by fewer HTTP requests. - * + * * The combined file is regenerated * based on every file modification time. Optionally a rebuild can be triggered * by appending ?flush=1 to the URL. * If all files to be combined are javascript, we use the external JSMin library * to minify the javascript. This can be controlled by {@link $combine_js_with_jsmin}. - * + * * All combined files will have a comment on the start of each concatenated file * denoting their original position. For easier debugging, we recommend to only * minify javascript if not in development mode ({@link Director::isDev()}). - * + * * CAUTION: You're responsible for ensuring that the load order for combined files * is retained - otherwise combining javascript files can lead to functional errors * in the javascript logic, and combining css can lead to wrong styling inheritance. @@ -828,7 +828,7 @@ class Requirements_Backend { * in more than one combine_files() call. * Best practice is to include every javascript file in exactly *one* combine_files() * directive to avoid the issues mentioned above - this is enforced by this function. - * + * * CAUTION: Combining CSS Files discards any "media" information. * * Example for combined JavaScript: @@ -854,10 +854,10 @@ class Requirements_Backend { * * * @see http://code.google.com/p/jsmin-php/ - * + * * @todo Should we enforce unique inclusion of files, or leave it to the developer? Can auto-detection cause * breaks? - * + * * @param string $combinedFileName Filename of the combined file (will be stored in {@link Director::baseFolder()} * by default) * @param array $files Array of filenames relative to the webroot @@ -913,7 +913,7 @@ class Requirements_Backend { } $this->combine_files[$combinedFileName] = $files; } - + /** * Returns all combined files. * @return array @@ -921,15 +921,15 @@ class Requirements_Backend { public function get_combine_files() { return $this->combine_files; } - + /** - * Deletes all dynamically generated combined files from the filesystem. - * + * Deletes all dynamically generated combined files from the filesystem. + * * @param string $combinedFileName If left blank, all combined files are deleted. */ public function delete_combined_files($combinedFileName = null) { $combinedFiles = ($combinedFileName) ? array($combinedFileName => null) : $this->combine_files; - $combinedFolder = ($this->getCombinedFilesFolder()) ? + $combinedFolder = ($this->getCombinedFilesFolder()) ? (Director::baseFolder() . '/' . $this->combinedFilesFolder) : Director::baseFolder(); foreach($combinedFiles as $combinedFile => $sourceItems) { $filePath = $combinedFolder . '/' . $combinedFile; @@ -938,7 +938,7 @@ class Requirements_Backend { } } } - + public function clear_combined_files() { $this->combine_files = array(); } @@ -952,7 +952,7 @@ class Requirements_Backend { // SapphireTest isn't running :-) if(class_exists('SapphireTest', false)) $runningTest = SapphireTest::is_running_test(); else $runningTest = false; - + if((Director::isDev() && !$runningTest && !isset($_REQUEST['combine'])) || !$this->combined_files_enabled) { return; } @@ -961,12 +961,12 @@ class Requirements_Backend { $combinerCheck = array(); foreach($this->combine_files as $combinedFile => $sourceItems) { foreach($sourceItems as $sourceItem) { - if(isset($combinerCheck[$sourceItem]) && $combinerCheck[$sourceItem] != $combinedFile){ + if(isset($combinerCheck[$sourceItem]) && $combinerCheck[$sourceItem] != $combinedFile){ user_error("Requirements_Backend::process_combined_files - file '$sourceItem' appears in two " . "combined files:" . " '{$combinerCheck[$sourceItem]}' and '$combinedFile'", E_USER_WARNING); } $combinerCheck[$sourceItem] = $combinedFile; - + } } @@ -985,7 +985,7 @@ class Requirements_Backend { $newJSRequirements[$file] = true; } } - + foreach($this->css as $file => $params) { if(isset($combinerCheck[$file])) { $newCSSRequirements[$combinedFilesFolder . $combinerCheck[$file]] = true; @@ -1041,7 +1041,7 @@ class Requirements_Backend { $isJS = stripos($file, '.js'); if($isJS && $this->combine_js_with_jsmin) { require_once('thirdparty/jsmin/jsmin.php'); - + increase_time_limit_to(); $fileContent = JSMin::minify($fileContent); } @@ -1074,13 +1074,13 @@ class Requirements_Backend { public function get_custom_scripts() { $requirements = ""; - + if($this->customScript) { foreach($this->customScript as $script) { $requirements .= "$script\n"; } } - + return $requirements; } @@ -1102,7 +1102,7 @@ class Requirements_Backend { $this->css($module.$css); } } - + public function debug() { Debug::show($this->javascript); Debug::show($this->css); @@ -1111,5 +1111,5 @@ class Requirements_Backend { Debug::show($this->customHeadTags); Debug::show($this->combine_files); } - + } From 618a3d0314e75d8c419055469aff92b888f7395e Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Tue, 18 Dec 2012 00:58:09 +0100 Subject: [PATCH 33/73] Requirements acces to files with query strings (fixes #7735) Originally authored by florian.thoma, tests added by Ingo Schommer. Also removed query params from file paths before calling mtime() on it. See https://github.com/silverstripe/sapphire/pull/1023 --- tests/forms/RequirementsTest.php | 28 ++++++++++++++++++++++++++++ view/Requirements.php | 15 ++++++++++----- 2 files changed, 38 insertions(+), 5 deletions(-) diff --git a/tests/forms/RequirementsTest.php b/tests/forms/RequirementsTest.php index 9c53e0ec9..af54ce2a7 100644 --- a/tests/forms/RequirementsTest.php +++ b/tests/forms/RequirementsTest.php @@ -325,6 +325,34 @@ class RequirementsTest extends SapphireTest { $this->assertContains('', $html); } + public function testSuffix() { + $template = '
My header

Body

'; + $basePath = $this->getCurrentRelativePath(); + $basePath = 'framework' . substr($basePath, strlen(FRAMEWORK_DIR)); + + $backend = new Requirements_Backend; + + $backend->javascript($basePath .'/RequirementsTest_a.js'); + $backend->javascript($basePath .'/RequirementsTest_b.js?foo=bar&bla=blubb'); + $backend->css($basePath .'/RequirementsTest_a.css'); + $backend->css($basePath .'/RequirementsTest_b.css?foo=bar&bla=blubb'); + + $backend->set_suffix_requirements(true); + $html = $backend->includeInHTML(false, $template); + $this->assertRegexp('/RequirementsTest_a\.js\?m=[\d]*/', $html); + $this->assertRegexp('/RequirementsTest_b\.js\?m=[\d]*&foo=bar&bla=blubb/', $html); + $this->assertRegexp('/RequirementsTest_a\.css\?m=[\d]*/', $html); + $this->assertRegexp('/RequirementsTest_b\.css\?m=[\d]*&foo=bar&bla=blubb/', $html); + + $backend->set_suffix_requirements(false); + $html = $backend->includeInHTML(false, $template); + $this->assertNotContains('RequirementsTest_a.js=', $html); + $this->assertNotRegexp('/RequirementsTest_a\.js\?m=[\d]*/', $html); + $this->assertNotRegexp('/RequirementsTest_b\.js\?m=[\d]*&foo=bar&bla=blubb/', $html); + $this->assertNotRegexp('/RequirementsTest_a\.css\?m=[\d]*/', $html); + $this->assertNotRegexp('/RequirementsTest_b\.css\?m=[\d]*&foo=bar&bla=blubb/', $html); + } + public function assertFileIncluded($backend, $type, $files) { $type = strtolower($type); switch (strtolower($type)) { diff --git a/view/Requirements.php b/view/Requirements.php index 98472920d..253ba239c 100644 --- a/view/Requirements.php +++ b/view/Requirements.php @@ -790,15 +790,20 @@ class Requirements_Backend { if(preg_match('{^//|http[s]?}', $fileOrUrl)) { return $fileOrUrl; } elseif(Director::fileExists($fileOrUrl)) { + $filePath = preg_replace('/\?.*/', '', Director::baseFolder() . '/' . $fileOrUrl); $prefix = Director::baseURL(); $mtimesuffix = ""; $suffix = ''; - if(strpos($fileOrUrl, '?') !== false) { - $suffix = '?' . substr($fileOrUrl, strpos($fileOrUrl, '?')+1); - $fileOrUrl = substr($fileOrUrl, 0, strpos($fileOrUrl, '?')); - } if($this->suffix_requirements) { - $mtimesuffix = "?m=" . filemtime(Director::baseFolder() . '/' . $fileOrUrl); + $mtimesuffix = "?m=" . filemtime($filePath); + $suffix = '&'; + } + if(strpos($fileOrUrl, '?') !== false) { + if (strlen($suffix) == 0) { + $suffix = '?'; + } + $suffix .= substr($fileOrUrl, strpos($fileOrUrl, '?')+1); + $fileOrUrl = substr($fileOrUrl, 0, strpos($fileOrUrl, '?')); } return "{$prefix}{$fileOrUrl}{$mtimesuffix}{$suffix}"; } else { From 94be5c6d8749ed969e9d1ebda69237f9282e943a Mon Sep 17 00:00:00 2001 From: Simon Welsh Date: Tue, 18 Dec 2012 15:00:45 +1300 Subject: [PATCH 34/73] FIX Handle namespaced classes in Object::parse_class_spec() --- core/Object.php | 7 +++++++ tests/core/ObjectTest.php | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/core/Object.php b/core/Object.php index 3fafb7035..8c3ac83c6 100755 --- a/core/Object.php +++ b/core/Object.php @@ -164,12 +164,19 @@ abstract class Object { // Keep track of the current bucket that we're putting data into $bucket = &$args; $bucketStack = array(); + $had_ns = false; foreach($tokens as $token) { $tName = is_array($token) ? $token[0] : $token; // Get the class naem if($class == null && is_array($token) && $token[0] == T_STRING) { $class = $token[1]; + } elseif(is_array($token) && $token[0] == T_NS_SEPARATOR) { + $class .= $token[1]; + $had_ns = true; + } elseif ($had_ns && is_array($token) && $token[0] == T_STRING) { + $class .= $token[1]; + $had_ns = false; // Get arguments } else if(is_array($token)) { switch($token[0]) { diff --git a/tests/core/ObjectTest.php b/tests/core/ObjectTest.php index da73064b3..784f50fcd 100644 --- a/tests/core/ObjectTest.php +++ b/tests/core/ObjectTest.php @@ -361,6 +361,16 @@ class ObjectTest extends SapphireTest { Object::parse_class_spec( "Enum(array('Accepted', 'Pending', 'Declined', array('UnsubmittedA','UnsubmittedB')), 'Unsubmitted')") ); + // Namespaced class + $this->assertEquals( + array('Test\MyClass', array()), + Object::parse_class_spec('Test\MyClass') + ); + // Fully qualified namespaced class + $this->assertEquals( + array('\Test\MyClass', array()), + Object::parse_class_spec('\Test\MyClass') + ); } } From d5a1c3d99a4218e15ec2bb35d9f031152f7958e8 Mon Sep 17 00:00:00 2001 From: Mateusz Uzdowski Date: Tue, 18 Dec 2012 15:43:05 +1300 Subject: [PATCH 35/73] BUG SS has problems handling + in URLs. Filter them out. + has a special meaning in the URLs so overall it's a good idea to strip them out. Otherwise they would need to appear in their ugly url encoded form "%2B". Refer: http://open.silverstripe.org/ticket/7929 --- model/URLSegmentFilter.php | 6 +++--- tests/model/URLSegmentFilterTest.php | 10 +++++++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/model/URLSegmentFilter.php b/model/URLSegmentFilter.php index 983d6a0cb..870622677 100644 --- a/model/URLSegmentFilter.php +++ b/model/URLSegmentFilter.php @@ -29,7 +29,7 @@ class URLSegmentFilter extends Object { '/&/u' => '-and-', '/\s/u' => '-', // remove whitespace '/_/u' => '-', // underscores to dashes - '/[^A-Za-z0-9+.-]+/u' => '', // remove non-ASCII chars, only allow alphanumeric plus dash and dot + '/[^A-Za-z0-9.-]+/u' => '', // remove non-ASCII chars, only allow alphanumeric, dashes and dots. '/[\-]{2,}/u' => '-', // remove duplicate dashes '/^[\.\-_]/u' => '', // Remove all leading dots, dashes or underscores ); @@ -66,8 +66,8 @@ class URLSegmentFilter extends Object { $replacements = $this->getReplacements(); // Unset automated removal of non-ASCII characters, and don't try to transliterate - if($this->getAllowMultibyte() && isset($replacements['/[^A-Za-z0-9+.-]+/u'])) { - unset($replacements['/[^A-Za-z0-9+.-]+/u']); + if($this->getAllowMultibyte() && isset($replacements['/[^A-Za-z0-9.-]+/u'])) { + unset($replacements['/[^A-Za-z0-9.-]+/u']); } foreach($replacements as $regex => $replace) { diff --git a/tests/model/URLSegmentFilterTest.php b/tests/model/URLSegmentFilterTest.php index 38adedef2..c5567be31 100644 --- a/tests/model/URLSegmentFilterTest.php +++ b/tests/model/URLSegmentFilterTest.php @@ -22,7 +22,15 @@ class URLSegmentFilterTest extends SapphireTest { $f->filter('Brötchen') ); } - + + public function testReplacesCommonNonAsciiCharacters() { + $f = new URLSegmentFilter(); + $this->assertEquals( + urlencode('aa1-.'), + $f->filter('Aa1~!@#$%^*()_+`-=;\':"[]\{}|,./<>?') + ); + } + public function testRetainsNonAsciiUrlsWithAllowMultiByteOption() { $f = new URLSegmentFilter(); $f->setAllowMultibyte(true); From f72a024af586b5ddc1d2a67cd273d8ae32756e0a Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Tue, 18 Dec 2012 10:40:00 +0100 Subject: [PATCH 36/73] Updated changelog notes --- docs/en/changelogs/3.1.0.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/en/changelogs/3.1.0.md b/docs/en/changelogs/3.1.0.md index 09b76fd9b..2e28f3063 100644 --- a/docs/en/changelogs/3.1.0.md +++ b/docs/en/changelogs/3.1.0.md @@ -104,7 +104,8 @@ through the CMS controllers, providing a simple level of security. * `TableListField`, `ComplexTableField`, `TableField`, `HasOneComplexTableField`, `HasManyComplexTableField` and `ManyManyComplexTableField` have been removed from the core and placed into a module called "legacytablefields" located at https://github.com/silverstripe-labs/legacytablefields * `prototype.js` and `behaviour.js` have been removed from the core, they are no longer used. If you have custom code relying on these two libraries, please update your code to include the files yourself * `Object::has_extension()` and `Object::add_extension()` deprecated in favour of using late static binding, please use `{class}::has_extension()` and `{class}::add_extension()` instead, where {class} is the class name of your DataObject class. - * Removed `SiteTree.MetaTitle` and `SiteTree.MetaKeywords` since they are irrelevant in terms of SEO ([1](http://www.seomoz.org/learn-seo/title-tag), [2](http://www.mattcutts.com/blog/keywords-meta-tag-in-web-search/)) and general page informancy + * Removed `SiteTree.MetaKeywords` since they are irrelevant in terms of SEO ([seomoz article](http://www.mattcutts.com/blog/keywords-meta-tag-in-web-search/)) and general page informancy + * Removed `SiteTree.MetaTitle` as a means to customize the window title, use `SiteTree.Title` instead * Deprecated `Profiler` class, use third-party solutions like [xhprof](https://github.com/facebook/xhprof/) * Removed defunct or unnecessary debug GET parameters: `debug_profile`, `debug_memory`, `profile_trace`, `debug_javascript`, `debug_behaviour` From 9b3aebd310ee8729236e0e9d093309a29221828b Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Tue, 18 Dec 2012 15:02:23 +0100 Subject: [PATCH 37/73] Allow HTML in FormField->setDescription() --- admin/javascript/LeftAndMain.FieldHelp.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/javascript/LeftAndMain.FieldHelp.js b/admin/javascript/LeftAndMain.FieldHelp.js index a773cd437..af15d6458 100644 --- a/admin/javascript/LeftAndMain.FieldHelp.js +++ b/admin/javascript/LeftAndMain.FieldHelp.js @@ -13,7 +13,7 @@ if(title && title.length && field.has('.help').length == 0) { var span = $("", { "class": "help", - "text": title + "html": title }); field.append(span); From 07fb7563273fa82bd93eb25570571c0a298198e5 Mon Sep 17 00:00:00 2001 From: unclecheese Date: Tue, 18 Dec 2012 09:41:54 -0500 Subject: [PATCH 38/73] Fix edge case in which uninitialized buttons are being destroyed. In certain cases, the button may not yet be initialized or may no longer have button properties at the time of removal from the DOM. Without this check, an uncaught exception is thrown. --- admin/javascript/LeftAndMain.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/admin/javascript/LeftAndMain.js b/admin/javascript/LeftAndMain.js index d5b9fe708..30db823ce 100644 --- a/admin/javascript/LeftAndMain.js +++ b/admin/javascript/LeftAndMain.js @@ -575,7 +575,7 @@ jQuery.noConflict(); this._super(); }, onremove: function() { - this.button('destroy'); + if(this.data('button')) this.button('destroy'); this._super(); } }); From 2e1a5081fabf709720c4893587ed03724935ccf7 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Wed, 19 Dec 2012 16:05:37 +0100 Subject: [PATCH 39/73] API Remove dev/tests/startsession etc, use new "testsession" module Removed commands: startsession, endsession, sessionloadyml, setdb, emptydb. See https://github.com/silverstripe-labs/silverstripe-testsession --- dev/DevelopmentAdmin.php | 13 --- dev/TestRunner.php | 206 --------------------------------------- model/DB.php | 2 +- 3 files changed, 1 insertion(+), 220 deletions(-) diff --git a/dev/DevelopmentAdmin.php b/dev/DevelopmentAdmin.php index ac76a27fa..dd458bed3 100644 --- a/dev/DevelopmentAdmin.php +++ b/dev/DevelopmentAdmin.php @@ -79,9 +79,6 @@ class DevelopmentAdmin extends Controller { "build" => "Build/rebuild this environment. Call this whenever you have updated your project sources", "tests" => "See a list of unit tests to run", "tests/all" => "Run all tests", - "tests/startsession" => "Start a test session in your browser" - . " (gives you a temporary database with default content)", - "tests/endsession" => "Ends a test session", "jstests" => "See a list of JavaScript tests to run", "jstests/all" => "Run all JavaScript tests", "tasks" => "See a list of build tasks to run" @@ -191,16 +188,6 @@ Config::inst()->update('Security', 'token', '$token'); TXT; } - public function reset() { - $link = BASE_URL.'/dev/tests/startsession'; - - return "

The dev/reset feature has been removed. If you are trying to test your site " . - "with a clean datababase, we recommend that you use " . - "dev/test/startsession ". - "instead.

"; - - } - public function errors() { $this->redirect("Debug_"); } diff --git a/dev/TestRunner.php b/dev/TestRunner.php index f09fb9714..cf9395d5e 100644 --- a/dev/TestRunner.php +++ b/dev/TestRunner.php @@ -29,12 +29,7 @@ class TestRunner extends Controller { 'coverage/module/$ModuleName' => 'coverageModule', 'coverage/$TestCase!' => 'coverageOnly', 'coverage' => 'coverageAll', - 'sessionloadyml' => 'sessionloadyml', - 'startsession' => 'startsession', - 'endsession' => 'endsession', - 'setdb' => 'setdb', 'cleanupdb' => 'cleanupdb', - 'emptydb' => 'emptydb', 'module/$ModuleName' => 'module', 'all' => 'all', 'build' => 'build', @@ -48,9 +43,6 @@ class TestRunner extends Controller { 'coverageAll', 'coverageModule', 'coverageOnly', - 'startsession', - 'endsession', - 'setdb', 'cleanupdb', 'module', 'all', @@ -341,204 +333,6 @@ class TestRunner extends Controller { if(Director::is_cli() && ($results->failureCount() + $results->errorCount()) > 0) exit(2); } - /** - * Start a test session. - * Usage: visit dev/tests/startsession?fixture=(fixturefile). A test database will be constructed, and your - * browser session will be amended to use this database. This can only be run on dev and test sites. - * - * See {@link setdb()} for an alternative approach which just sets a database - * name, and is used for more advanced use cases like interacting with test databases - * directly during functional tests. - * - * Requires PHP's mycrypt extension in order to set the database name - * as an encrypted cookie. - */ - public function startsession() { - if(!Director::isLive()) { - if(SapphireTest::using_temp_db()) { - $endLink = Director::baseURL() . "dev/tests/endsession"; - return "

You're in the middle of a test session;" - . " click here to end it.

"; - - } else if(!isset($_GET['fixture'])) { - $me = Director::baseURL() . "dev/tests/startsession"; - return << -

Enter a fixture file name to start a new test session. Don't forget to visit dev/tests/endsession when - you're done!

-

Fixture file (leave blank to start with default set-up):

- -

- -HTML; - } else { - $fixtureFile = $_GET['fixture']; - - if($fixtureFile) { - // Validate fixture file - $realFile = realpath(BASE_PATH.'/'.$fixtureFile); - $baseDir = realpath(Director::baseFolder()); - if(!$realFile || !file_exists($realFile)) { - return "

Fixture file doesn't exist

"; - } else if(substr($realFile,0,strlen($baseDir)) != $baseDir) { - return "

Fixture file must be inside $baseDir

"; - } else if(substr($realFile,-4) != '.yml') { - return "

Fixture file must be a .yml file

"; - } else if(!preg_match('/^([^\/.][^\/]+)\/tests\//', $fixtureFile)) { - return "

Fixture file must be inside the tests subfolder of one of your modules.

"; - } - } - - $dbname = SapphireTest::create_temp_db(); - - DB::set_alternative_database_name($dbname); - - // Fixture - if($fixtureFile) { - $fixture = Injector::inst()->create('YamlFixture', $fixtureFile); - $fixture->saveIntoDatabase(); - - // If no fixture, then use defaults - } else { - $dataClasses = ClassInfo::subclassesFor('DataObject'); - array_shift($dataClasses); - foreach($dataClasses as $dataClass) singleton($dataClass)->requireDefaultRecords(); - } - - return "

Started testing session with fixture '$fixtureFile'. - Time to start testing; where would you like to start?

- "; - } - - } else { - return "

startession can only be used on dev and test sites

"; - } - } - - /** - * Set an alternative database name in the current browser session as a cookie. - * Useful for functional testing libraries like behat to create a "clean slate". - * Does not actually create the database, that's usually handled - * by {@link SapphireTest::create_temp_db()}. - * - * The database names are limited to a specific naming convention as a security measure: - * The "tmpdb" prefix and a random sequence of seven digits. - * This avoids the user gaining access to other production databases - * available on the same connection. - * - * See {@link startsession()} for a different approach which actually creates - * the DB and loads a fixture file instead. - * - * Requires PHP's mycrypt extension in order to set the database name - * as an encrypted cookie. - */ - public function setdb() { - if(Director::isLive()) { - return $this->httpError(403, "dev/tests/setdb can only be used on dev and test sites"); - } - if(!isset($_GET['database'])) { - return $this->httpError(400, "dev/tests/setdb must be used with a 'database' parameter"); - } - - $name = $_GET['database']; - $prefix = defined('SS_DATABASE_PREFIX') ? SS_DATABASE_PREFIX : 'ss_'; - $pattern = strtolower(sprintf('#^%stmpdb\d{7}#', $prefix)); - if($name && !preg_match($pattern, $name)) { - return $this->httpError(400, "Invalid database name format"); - } - - DB::set_alternative_database_name($name); - - if($name) { - return "

Set database session to '$name'.

"; - } else { - return "

Unset database session.

"; - } - - } - - public function emptydb() { - if(SapphireTest::using_temp_db()) { - SapphireTest::empty_temp_db(); - - if(isset($_GET['fixture']) && ($fixtureFile = $_GET['fixture'])) { - $fixture = Injector::inst()->create('YamlFixture', $fixtureFile); - $fixture->saveIntoDatabase(); - return "

Re-test the test database with fixture '$fixtureFile'. Time to start testing; where would" - . " you like to start?

"; - - } else { - return "

Re-test the test database. Time to start testing; where would you like to start?

"; - } - - } else { - return "

dev/tests/emptydb can only be used with a temporary database. Perhaps you should use" - . " dev/tests/startsession first?

"; - } - } - - public function endsession() { - SapphireTest::kill_temp_db(); - DB::set_alternative_database_name(null); - - return "

Test session ended.

- "; - } - - public function sessionloadyml() { - // Load incremental YAML fixtures - // TODO: We will probably have to filter out the admin member here, - // as it is supplied by Bare.yml - if(Director::isLive()) { - return "

sessionloadyml can only be used on dev and test sites

"; - } - if (!SapphireTest::using_temp_db()) { - return "

Please load /dev/tests/startsession first

"; - } - - $fixtureFile = isset($_GET['fixture']) ? $_GET['fixture'] : null; - if (empty($fixtureFile)) { - $me = Director::baseURL() . "/dev/tests/sessionloadyml"; - return << -

Enter a fixture file name to load a new YAML fixture into the session.

-

Fixture file

- -

- -HTML; - } - // Validate fixture file - $realFile = realpath(BASE_PATH.'/'.$fixtureFile); - $baseDir = realpath(Director::baseFolder()); - if(!$realFile || !file_exists($realFile)) { - return "

Fixture file doesn't exist

"; - } else if(substr($realFile,0,strlen($baseDir)) != $baseDir) { - return "

Fixture file must be inside $baseDir

"; - } else if(substr($realFile,-4) != '.yml') { - return "

Fixture file must be a .yml file

"; - } else if(!preg_match('/^([^\/.][^\/]+)\/tests\//', $fixtureFile)) { - return "

Fixture file must be inside the tests subfolder of one of your modules.

"; - } - - // Fixture - $fixture = Injector::inst()->create('YamlFixture', $fixtureFile); - $fixture->saveIntoDatabase(); - - return "

Loaded fixture '$fixtureFile' into session

"; - } - public function setUp() { // The first DB test will sort out the DB, we don't have to SSViewer::flush_template_cache(); diff --git a/model/DB.php b/model/DB.php index d9c1a3dac..b4eb45ac6 100644 --- a/model/DB.php +++ b/model/DB.php @@ -153,7 +153,7 @@ class DB { * rest of the options, see the specific class. */ public static function connect($databaseConfig) { - // This is used by TestRunner::startsession() to test up a test session using an alt + // This is used by the "testsession" module to test up a test session using an alternative name if($name = self::get_alternative_database_name()) { $databaseConfig['database'] = $name; } From 561e629c164a8869808b754ca4d8ef0735a47763 Mon Sep 17 00:00:00 2001 From: Kirk Mayo Date: Wed, 19 Dec 2012 14:40:22 +1300 Subject: [PATCH 40/73] NEW Show the allowed extensions as a toggle tip as per trac 7993 NEW Added a behat test for showing extension trac 7993 --- css/AssetUploadField.css | 5 ++--- javascript/AssetUploadField.js | 13 +++++++++++++ lang/en.yml | 1 + scss/AssetUploadField.scss | 9 +++++++-- templates/AssetUploadField.ss | 6 ++++-- tests/behat/features/manage-files.feature | 7 ++++++- 6 files changed, 33 insertions(+), 8 deletions(-) diff --git a/css/AssetUploadField.css b/css/AssetUploadField.css index 9b997cff3..4881de652 100644 --- a/css/AssetUploadField.css +++ b/css/AssetUploadField.css @@ -11,6 +11,7 @@ Used in side panels and action tabs */ .ss-uploadfield-view-allowed-extensions { padding-top: 20px; clear: both; max-width: 750px; display: block; } +.ss-uploadfield-view-allowed-extensions .toggle { font-style: normal; font-size: 11px; } #AssetUploadField { border-bottom: 0; -webkit-box-shadow: none; -moz-box-shadow: none; box-shadow: none; } @@ -68,9 +69,7 @@ body.cms.ss-uploadfield-edit-iframe .fieldholder-small label, .composite.ss-asse .ss-assetuploadfield .ss-uploadfield-addfile .ss-uploadfield-item-info { float: left; margin: 34px 0 0; } .ss-insert-media .ss-assetuploadfield .ss-uploadfield-addfile .ss-uploadfield-item-info { margin: 15px 0px 0 20px; } .ss-assetuploadfield .ss-uploadfield-addfile .ss-uploadfield-item-info label { font-size: 16px; line-height: 30px; padding: 5px 16px; } -.ss-assetuploadfield .ss-uploadfield-addfile .ss-uploadfield-fromcomputer { /*position: relative; -overflow: hidden; -display: block;*/ } +.ss-assetuploadfield .ss-uploadfield-addfile .ss-uploadfield-fromcomputer { /*position: relative; */ overflow: hidden; display: block; } .ss-assetuploadfield .ss-uploadfield-addfile .ss-uploadfield-item-uploador { float: left; font-weight: bold; font-size: 22px; padding: 0 20px; line-height: 70px; margin-top: 16px; display: none; } .ss-insert-media .ss-assetuploadfield .ss-uploadfield-addfile .ss-uploadfield-item-uploador { font-size: 18px; margin-top: 0; } .ss-assetuploadfield .ss-uploadfield-addfile .ss-uploadfield-dropzone { margin-top: 9px; -webkit-border-radius: 13px; -moz-border-radius: 13px; -ms-border-radius: 13px; -o-border-radius: 13px; border-radius: 13px; -webkit-box-shadow: rgba(128, 128, 128, 0.4) 0 0 4px 0 inset, 0 1px 0 #fafafa; -moz-box-shadow: rgba(128, 128, 128, 0.4) 0 0 4px 0 inset, 0 1px 0 #fafafa; box-shadow: rgba(128, 128, 128, 0.4) 0 0 4px 0 inset, 0 1px 0 #fafafa; border: 2px dashed gray; background: #d4dbe0; display: none; height: 82px; width: 360px; float: left; } diff --git a/javascript/AssetUploadField.js b/javascript/AssetUploadField.js index 93dddde1f..a63c3a130 100644 --- a/javascript/AssetUploadField.js +++ b/javascript/AssetUploadField.js @@ -16,4 +16,17 @@ this.find('.ss-uploadfield-editandorganize').show(); } }); + $('.ss-uploadfield-view-allowed-extensions').entwine({ + onmatch: function() { + this.find('.description .toggle-content').hide(); + this._super(); + } + }); + + $('.ss-uploadfield-view-allowed-extensions .toggle').entwine({ + onclick: function(e) { + jQuery(this).closest('.description').find('.toggle-content').toggle(); + return false; + } + }); }(jQuery)); diff --git a/lang/en.yml b/lang/en.yml index 4ff7b99a4..d2512ee63 100644 --- a/lang/en.yml +++ b/lang/en.yml @@ -1,6 +1,7 @@ en: AssetAdmin: ALLOWEDEXTS: 'Allowed extensions' + SHOWALLOWEDEXTS: 'Show allowed extensions' NEWFOLDER: NewFolder AssetTableField: CREATED: 'First uploaded' diff --git a/scss/AssetUploadField.scss b/scss/AssetUploadField.scss index a96b24c6a..dedb5b80b 100644 --- a/scss/AssetUploadField.scss +++ b/scss/AssetUploadField.scss @@ -12,6 +12,11 @@ clear:both; max-width:750px; display:block; + + .toggle { + font-style: normal; + font-size: $font-base-size; + } } #AssetUploadField { @@ -273,9 +278,9 @@ body.cms.ss-uploadfield-edit-iframe, .composite.ss-assetuploadfield .details fie } } .ss-uploadfield-fromcomputer { - /*position: relative; + /*position: relative; */ overflow: hidden; - display: block;*/ + display: block; } .ss-uploadfield-item-uploador { float: left; diff --git a/templates/AssetUploadField.ss b/templates/AssetUploadField.ss index 4a596696c..9abddc6b9 100644 --- a/templates/AssetUploadField.ss +++ b/templates/AssetUploadField.ss @@ -28,9 +28,11 @@ + - <% _t('AssetAdmin.ALLOWEDEXTS', 'Allowed extensions') %> - $Extensions + <% _t('AssetAdmin.SHOWALLOWEDEXTS', 'Show allowed extensions') %> +

$Extensions

+
diff --git a/tests/behat/features/manage-files.feature b/tests/behat/features/manage-files.feature index a0c09985d..23996cebd 100644 --- a/tests/behat/features/manage-files.feature +++ b/tests/behat/features/manage-files.feature @@ -81,4 +81,9 @@ Feature: Manage files # /show/0 is to ensure that we are on top level folder And I go to "/admin/assets/show/0" And I click on "folder2" in the "Files" table - And the "folder2" table should contain "file1" \ No newline at end of file + And the "folder2" table should contain "file1" + + Scenario: I can see allowed extensions help + When I go to "/admin/assets/add" + And I follow "Show allowed extensions" + Then I should see "png," \ No newline at end of file From 86940aa6849003ebef3154b372a0a9d631061621 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Wed, 19 Dec 2012 17:30:28 +0100 Subject: [PATCH 41/73] Made hyphen escaping clearer in FileNameFilter and URLSegmentFilter Does not actually change behaviour, but ensures that the hyphen is not interpreted as a range identifier should it be placed between two characters which PCRE regards as "rangeable". --- filesystem/FileNameFilter.php | 2 +- model/URLSegmentFilter.php | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/filesystem/FileNameFilter.php b/filesystem/FileNameFilter.php index d1a000f12..ef2357abc 100644 --- a/filesystem/FileNameFilter.php +++ b/filesystem/FileNameFilter.php @@ -39,7 +39,7 @@ class FileNameFilter extends Object { static $default_replacements = array( '/\s/' => '-', // remove whitespace '/_/' => '-', // underscores to dashes - '/[^A-Za-z0-9+.-]+/' => '', // remove non-ASCII chars, only allow alphanumeric plus dash and dot + '/[^A-Za-z0-9+.\-]+/' => '', // remove non-ASCII chars, only allow alphanumeric plus dash and dot '/[\-]{2,}/' => '-', // remove duplicate dashes '/^[\.\-_]+/' => '', // Remove all leading dots, dashes or underscores ); diff --git a/model/URLSegmentFilter.php b/model/URLSegmentFilter.php index 983d6a0cb..77240e282 100644 --- a/model/URLSegmentFilter.php +++ b/model/URLSegmentFilter.php @@ -29,7 +29,7 @@ class URLSegmentFilter extends Object { '/&/u' => '-and-', '/\s/u' => '-', // remove whitespace '/_/u' => '-', // underscores to dashes - '/[^A-Za-z0-9+.-]+/u' => '', // remove non-ASCII chars, only allow alphanumeric plus dash and dot + '/[^A-Za-z0-9+.\-]+/u' => '', // remove non-ASCII chars, only allow alphanumeric plus dash and dot '/[\-]{2,}/u' => '-', // remove duplicate dashes '/^[\.\-_]/u' => '', // Remove all leading dots, dashes or underscores ); @@ -66,8 +66,8 @@ class URLSegmentFilter extends Object { $replacements = $this->getReplacements(); // Unset automated removal of non-ASCII characters, and don't try to transliterate - if($this->getAllowMultibyte() && isset($replacements['/[^A-Za-z0-9+.-]+/u'])) { - unset($replacements['/[^A-Za-z0-9+.-]+/u']); + if($this->getAllowMultibyte() && isset($replacements['/[^A-Za-z0-9+.\-]+/u'])) { + unset($replacements['/[^A-Za-z0-9+.\-]+/u']); } foreach($replacements as $regex => $replace) { From c56a80d6ce5294a5339fb45d62bccf45cc5dcdc3 Mon Sep 17 00:00:00 2001 From: Simon Welsh Date: Thu, 20 Dec 2012 13:40:42 +1300 Subject: [PATCH 42/73] Use preg_replace_callback over preg_replace with e modifier --- control/HTTP.php | 25 +++++++++++++++---------- core/Convert.php | 9 ++++++--- email/Mailer.php | 4 +++- 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/control/HTTP.php b/control/HTTP.php index 71a4d6362..6621a7246 100644 --- a/control/HTTP.php +++ b/control/HTTP.php @@ -60,20 +60,25 @@ class HTTP { if(!is_numeric($tag)) $tagPrefix = "$tag "; else $tagPrefix = ""; - $regExps[] = "/(<{$tagPrefix}[^>]*$attrib *= *\")([^\"]*)(\")/ie"; - $regExps[] = "/(<{$tagPrefix}[^>]*$attrib *= *')([^']*)(')/ie"; - $regExps[] = "/(<{$tagPrefix}[^>]*$attrib *= *)([^\"' ]*)( )/ie"; + $regExps[] = "/(<{$tagPrefix}[^>]*$attrib *= *\")([^\"]*)(\")/i"; + $regExps[] = "/(<{$tagPrefix}[^>]*$attrib *= *')([^']*)(')/i"; + $regExps[] = "/(<{$tagPrefix}[^>]*$attrib *= *)([^\"' ]*)( )/i"; } - $regExps[] = '/(background-image:[^;]*url *\()([^)]+)(\))/ie'; - $regExps[] = '/(background:[^;]*url *\()([^)]+)(\))/ie'; - $regExps[] = '/(list-style-image:[^;]*url *\()([^)]+)(\))/ie'; - $regExps[] = '/(list-style:[^;]*url *\()([^)]+)(\))/ie'; + $regExps[] = '/(background-image:[^;]*url *\()([^)]+)(\))/i'; + $regExps[] = '/(background:[^;]*url *\()([^)]+)(\))/i'; + $regExps[] = '/(list-style-image:[^;]*url *\()([^)]+)(\))/i'; + $regExps[] = '/(list-style:[^;]*url *\()([^)]+)(\))/i'; // Make - $code = 'stripslashes("$1") . (' . str_replace('$URL', 'stripslashes("$2")', $code) . ') . stripslashes("$3")'; - + $callback = function($matches) use($code) { + return + stripslashes($matches[1]) . + str_replace('$URL', stripslashes($matches[2]), $code) . + stripslashes($matches[3]); + }; + foreach($regExps as $regExp) { - $content = preg_replace($regExp, $code, $content); + $content = preg_replace_callback($regExp, $callback, $content); } return $content; diff --git a/core/Convert.php b/core/Convert.php index 3df0b37b7..94c6234c0 100644 --- a/core/Convert.php +++ b/core/Convert.php @@ -244,9 +244,12 @@ class Convert { // Expand hyperlinks if(!$preserveLinks && !$config['PreserveLinks']) { - $data = preg_replace('/]*href\s*=\s*"([^"]*)">(.*?)<\/a>/ie', "Convert::html2raw('\\2').'[\\1]'", - $data); - $data = preg_replace('/]*href\s*=\s*([^ ]*)>(.*?)<\/a>/ie', "Convert::html2raw('\\2').'[\\1]'", $data); + $data = preg_replace_callback('/]*href\s*=\s*"([^"]*)">(.*?)<\/a>/i', function($matches) { + return Convert::html2raw($matches[2]) . "[$matches[1]]"; + }, $data); + $data = preg_replace_callback('/]*href\s*=\s*([^ ]*)>(.*?)<\/a>/i', function($matches) { + return Convert::html2raw($matches[2]) . "[$matches[1]]"; + }, $data); } // Replace images with their alt tags diff --git a/email/Mailer.php b/email/Mailer.php index 6d97d5db5..8fd8ed93e 100644 --- a/email/Mailer.php +++ b/email/Mailer.php @@ -368,7 +368,9 @@ function encodeFileForEmail($file, $destFileName = false, $disposition = NULL, $ function QuotedPrintable_encode($quotprint) { $quotprint = (string)str_replace('\r\n',chr(13).chr(10),$quotprint); $quotprint = (string)str_replace('\n', chr(13).chr(10),$quotprint); - $quotprint = (string)preg_replace("~([\x01-\x1F\x3D\x7F-\xFF])~e", "sprintf('=%02X', ord('\\1'))", $quotprint); + $quotprint = (string)preg_replace_callback("~([\x01-\x1F\x3D\x7F-\xFF])~e", function($matches) { + return sprintf('=%02X', ord($matches[1])); + }, $quotprint); //$quotprint = (string)str_replace('\=0D=0A',"=0D=0A",$quotprint); $quotprint = (string)str_replace('=0D=0A',"\n",$quotprint); $quotprint = (string)str_replace('=0A=0D',"\n",$quotprint); From 1a4eaaaf04808c48ab980622d0bd3492f562daf3 Mon Sep 17 00:00:00 2001 From: Simon Elvery Date: Thu, 6 Dec 2012 09:42:24 +1000 Subject: [PATCH 43/73] BUGFIX Ensure has length before using string index access. --- dev/LogErrorFileFormatter.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev/LogErrorFileFormatter.php b/dev/LogErrorFileFormatter.php index 30d1ad256..9b4f82f9b 100644 --- a/dev/LogErrorFileFormatter.php +++ b/dev/LogErrorFileFormatter.php @@ -30,7 +30,7 @@ class SS_LogErrorFileFormatter implements Zend_Log_Formatter_Interface { $urlSuffix = ''; $relfile = Director::makeRelative($errfile); - if($relfile[0] == '/') $relfile = substr($relfile, 1); + if(strlen($relfile) && $relfile[0] == '/') $relfile = substr($relfile, 1); if(isset($_SERVER['HTTP_HOST']) && $_SERVER['HTTP_HOST'] && isset($_SERVER['REQUEST_URI'])) { $urlSuffix = " (http://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI])"; } From e20f15df55a24c74ba94fb96304152a4c0d0ae92 Mon Sep 17 00:00:00 2001 From: Simon Welsh Date: Thu, 20 Dec 2012 15:35:40 +1300 Subject: [PATCH 44/73] Remove /e option due to preg_replace_callback use --- email/Mailer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/email/Mailer.php b/email/Mailer.php index 8fd8ed93e..8f1fbf265 100644 --- a/email/Mailer.php +++ b/email/Mailer.php @@ -368,7 +368,7 @@ function encodeFileForEmail($file, $destFileName = false, $disposition = NULL, $ function QuotedPrintable_encode($quotprint) { $quotprint = (string)str_replace('\r\n',chr(13).chr(10),$quotprint); $quotprint = (string)str_replace('\n', chr(13).chr(10),$quotprint); - $quotprint = (string)preg_replace_callback("~([\x01-\x1F\x3D\x7F-\xFF])~e", function($matches) { + $quotprint = (string)preg_replace_callback("~([\x01-\x1F\x3D\x7F-\xFF])~", function($matches) { return sprintf('=%02X', ord($matches[1])); }, $quotprint); //$quotprint = (string)str_replace('\=0D=0A',"=0D=0A",$quotprint); From aa3b35846968f2b540f5df17e6b70acb86a8b16e Mon Sep 17 00:00:00 2001 From: Sean Harvey Date: Thu, 20 Dec 2012 15:52:46 +1300 Subject: [PATCH 45/73] Adding test for SortColumn to SQLQueryTest Mostly for the benefit of MSSQLDatabase which is having problems with subselects and alias functions. --- model/SQLQuery.php | 1 + tests/model/SQLQueryTest.php | 26 ++++++++++++++++++++++++++ tests/model/SQLQueryTest.yml | 4 +++- 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/model/SQLQuery.php b/model/SQLQuery.php index d7729d7a9..4503b5624 100644 --- a/model/SQLQuery.php +++ b/model/SQLQuery.php @@ -566,6 +566,7 @@ class SQLQuery { if($this->orderby) { $i = 0; foreach($this->orderby as $clause => $dir) { + // public function calls and multi-word columns like "CASE WHEN ..." if(strpos($clause, '(') !== false || strpos($clause, " ") !== false ) { // remove the old orderby diff --git a/tests/model/SQLQueryTest.php b/tests/model/SQLQueryTest.php index f59c2d519..d3e64b827 100755 --- a/tests/model/SQLQueryTest.php +++ b/tests/model/SQLQueryTest.php @@ -368,12 +368,38 @@ class SQLQueryTest extends SapphireTest { } } + /** + * Test that "_SortColumn0" is added for an aggregate in the ORDER BY + * clause, in combination with a LIMIT and GROUP BY clause. + * For some databases, like MSSQL, this is a complicated scenario + * because a subselect needs to be done to query paginated data. + */ + public function testOrderByContainingAggregateAndLimitOffset() { + $query = new SQLQuery(); + $query->setSelect(array('"Name"', '"Meta"')); + $query->setFrom('"SQLQueryTest_DO"'); + $query->setOrderBy(array('MAX(Date)')); + $query->setGroupBy(array('"Name"', '"Meta"')); + $query->setLimit('1', '1'); + + $records = array(); + foreach($query->execute() as $record) { + $records[] = $record; + } + + $this->assertCount(1, $records); + + $this->assertEquals('Object 2', $records[0]['Name']); + $this->assertEquals('2012-05-01 09:00:00', $records['0']['_SortColumn0']); + } + } class SQLQueryTest_DO extends DataObject implements TestOnly { static $db = array( "Name" => "Varchar", "Meta" => "Varchar", + "Date" => "SS_Datetime" ); } diff --git a/tests/model/SQLQueryTest.yml b/tests/model/SQLQueryTest.yml index 725b7dee4..9d88cd25b 100644 --- a/tests/model/SQLQueryTest.yml +++ b/tests/model/SQLQueryTest.yml @@ -2,6 +2,8 @@ SQLQueryTest_DO: test1: Name: 'Object 1' Meta: 'Details 1' + Date: 2012-01-01 10:00:00 test2: Name: 'Object 2' - Meta: 'Details 2' \ No newline at end of file + Meta: 'Details 2' + Date: 2012-05-01 09:00:00 From d487a424565bd26406f9f747ea9bc578b4a524a4 Mon Sep 17 00:00:00 2001 From: "Nathan J. Brauer" Date: Wed, 19 Dec 2012 17:52:44 -0800 Subject: [PATCH 46/73] API Default to Upload::$uploads_dir in UploadField --- forms/FileField.php | 8 ++++---- forms/UploadField.php | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/forms/FileField.php b/forms/FileField.php index 95ffc1d98..f8a9d6b8c 100644 --- a/forms/FileField.php +++ b/forms/FileField.php @@ -64,11 +64,11 @@ class FileField extends FormField { /** * Partial filesystem path relative to /assets directory. - * Defaults to 'Uploads'. + * Defaults to Upload::$uploads_folder. * * @var string */ - protected $folderName = 'Uploads'; + protected $folderName = false; /** * Create a new file field. @@ -111,7 +111,7 @@ class FileField extends FormField { $file = new $fileClass(); } - $this->upload->loadIntoFile($_FILES[$this->name], $file, $this->folderName); + $this->upload->loadIntoFile($_FILES[$this->name], $file, $this->getFolderName()); if($this->upload->isError()) return false; $file = $this->upload->getFile(); @@ -160,7 +160,7 @@ class FileField extends FormField { * @return string */ public function getFolderName() { - return $this->folderName; + return ($this->folderName !== false) ? $this->folderName : Upload::$uploads_folder; } public function validate($validator) { diff --git a/forms/UploadField.php b/forms/UploadField.php index 033d2f956..272e9ce5b 100644 --- a/forms/UploadField.php +++ b/forms/UploadField.php @@ -431,7 +431,7 @@ class UploadField extends FileField { * @return UploadField_ItemHandler */ public function handleSelect(SS_HTTPRequest $request) { - return UploadField_SelectHandler::create($this, $this->folderName); + return UploadField_SelectHandler::create($this, $this->getFolderName()); } /** @@ -500,7 +500,7 @@ class UploadField extends FileField { // Get the uploaded file into a new file object. try { - $this->upload->loadIntoFile($tmpfile, $fileObject, $this->folderName); + $this->upload->loadIntoFile($tmpfile, $fileObject, $this->getFolderName()); } catch (Exception $e) { // we shouldn't get an error here, but just in case $return['error'] = $e->getMessage(); From 9ffd25225ea5c076130a02abf13d108f09bbcdb5 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Mon, 17 Dec 2012 15:33:12 +0100 Subject: [PATCH 47/73] Don't complain about pre-replaced YAML fixture relations --- dev/FixtureBlueprint.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dev/FixtureBlueprint.php b/dev/FixtureBlueprint.php index 0b01458d6..c3cc97c4e 100644 --- a/dev/FixtureBlueprint.php +++ b/dev/FixtureBlueprint.php @@ -129,8 +129,9 @@ class FixtureBlueprint { $parsedItems = array(); $items = preg_split('/ *, */',trim($fieldVal)); foreach($items as $item) { - // Check for correct format: =>. - if(!preg_match('/^=>[^\.]+\.[^\.]+/', $item)) { + // Check for correct format: =>.. + // Ignore if the item has already been replaced with a numeric DB identifier + if(!is_numeric($item) && !preg_match('/^=>[^\.]+\.[^\.]+/', $item)) { throw new InvalidArgumentException(sprintf( 'Invalid format for relation "%s" on class "%s" ("%s")', $fieldName, From d918c267827166d466a34ad92e8e2f1b3b57db88 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Thu, 20 Dec 2012 12:46:35 +0100 Subject: [PATCH 48/73] Allow recursive includes in i18nTextCollector (fixes #8133) --- i18n/i18nTextCollector.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/i18n/i18nTextCollector.php b/i18n/i18nTextCollector.php index 40da3f8e6..abb9e064b 100644 --- a/i18n/i18nTextCollector.php +++ b/i18n/i18nTextCollector.php @@ -289,7 +289,7 @@ class i18nTextCollector extends Object { * * @todo Why the type juggling for $this->collectFromTemplate()? It always returns an array. */ - public function collectFromTemplate($content, $fileName, $module) { + public function collectFromTemplate($content, $fileName, $module, &$parsedFiles = array()) { $entities = array(); // Search for included templates @@ -299,11 +299,12 @@ class i18nTextCollector extends Object { $includeFileName = "{$includeName}.ss"; $filePath = SSViewer::getTemplateFileByType($includeName, 'Includes'); if(!$filePath) $filePath = SSViewer::getTemplateFileByType($includeName, 'main'); - if($filePath) { + if($filePath && !in_array($filePath, $parsedFiles)) { + $parsedFiles[] = $filePath; $includeContent = file_get_contents($filePath); $entities = array_merge( $entities, - (array)$this->collectFromTemplate($includeContent, $module, $includeFileName) + (array)$this->collectFromTemplate($includeContent, $module, $includeFileName, $parsedFiles) ); } // @todo Will get massively confused if you include the includer -> infinite loop From 7a6ce01567fdb0168fc2776c646a544f0074320f Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Thu, 20 Dec 2012 20:16:53 +0100 Subject: [PATCH 49/73] BUG Skip pagination on UnsavedRelationList in GFPaginator --- forms/gridfield/GridFieldPaginator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/forms/gridfield/GridFieldPaginator.php b/forms/gridfield/GridFieldPaginator.php index 76f0cf4e4..c79e1f838 100755 --- a/forms/gridfield/GridFieldPaginator.php +++ b/forms/gridfield/GridFieldPaginator.php @@ -130,7 +130,7 @@ class GridFieldPaginator implements GridField_HTMLProvider, GridField_DataManipu // Update item count prior to filter. GridFieldPageCount will rely on this value $this->totalItems = $dataList->count(); - if(!($dataList instanceof SS_Limitable)) { + if(!($dataList instanceof SS_Limitable) || ($dataList instanceof UnsavedRelationList)) { return $dataList; } From 661a4a2492196bd237bbe7a6497a8e5fec145833 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Fri, 21 Dec 2012 11:18:51 +0100 Subject: [PATCH 50/73] Removed direct sprintf() usage from _t() calls Parameterized strings are easier to understand, and more fail-proof, don't fatal out when not enough sprintf() args --- forms/RequiredFields.php | 11 +++++++++-- forms/gridfield/GridFieldDetailForm.php | 14 ++++++++++---- lang/en.yml | 8 +++++--- 3 files changed, 24 insertions(+), 9 deletions(-) diff --git a/forms/RequiredFields.php b/forms/RequiredFields.php index 536140d9c..2dba8c619 100644 --- a/forms/RequiredFields.php +++ b/forms/RequiredFields.php @@ -85,8 +85,15 @@ class RequiredFields extends Validator { } if($formField && $error) { - $errorMessage = sprintf(_t('Form.FIELDISREQUIRED', '%s is required'), - strip_tags('"' . ($formField->Title() ? $formField->Title() : $fieldName) . '"')); + $errorMessage = _t( + 'Form.FIELDISREQUIRED', + '{name} is required', + array( + 'name' => strip_tags( + '"' . ($formField->Title() ? $formField->Title() : $fieldName) . '"' + ) + ) + ); if($msg = $formField->getCustomValidationMessage()) { $errorMessage = $msg; diff --git a/forms/gridfield/GridFieldDetailForm.php b/forms/gridfield/GridFieldDetailForm.php index 0f1c37fe5..74457bb82 100644 --- a/forms/gridfield/GridFieldDetailForm.php +++ b/forms/gridfield/GridFieldDetailForm.php @@ -412,10 +412,16 @@ class GridFieldDetailForm_ItemRequest extends RequestHandler { // TODO Save this item into the given relationship - $message = sprintf( - _t('GridFieldDetailForm.Saved', 'Saved %s %s'), - $this->record->singular_name(), - '"' . htmlspecialchars($this->record->Title, ENT_QUOTES) . '"' + $link = '"' + . htmlspecialchars($this->record->Title, ENT_QUOTES) + . '"'; + $message = _t( + 'GridFieldDetailForm.Saved', + 'Saved {name} {link}', + array( + 'name' => $this->record->singular_name(), + 'link' => $link + ) ); $form->sessionMessage($message, 'good'); diff --git a/lang/en.yml b/lang/en.yml index 3c1d2561b..0d4989c06 100644 --- a/lang/en.yml +++ b/lang/en.yml @@ -1,6 +1,5 @@ en: AssetAdmin: - ALLOWEDEXTS: 'Allowed extensions' NEWFOLDER: NewFolder AssetTableField: CREATED: 'First uploaded' @@ -198,7 +197,7 @@ en: TEXT2: 'password reset link' TEXT3: for Form: - FIELDISREQUIRED: '%s is required' + FIELDISREQUIRED: '{name} is required' SubmitBtnLabel: Go VALIDATIONCREDITNUMBER: 'Please ensure you have entered the {number} credit card number correctly' VALIDATIONNOTUNIQUE: 'The value entered is not unique' @@ -237,7 +236,9 @@ en: DeletePermissionsFailure: 'No delete permissions' Deleted: 'Deleted %s %s' Save: Save - Saved: 'Saved %s %s' + Saved: 'Saved {name} {link}' + GridFieldEditButton.ss: + EDIT: Edit GridFieldItemEditView.ss: 'Go back': 'Go back' Group: @@ -368,6 +369,7 @@ en: NEWPASSWORD: 'New Password' PASSWORD: Password PLURALNAME: Members + PROFILESAVESUCCESS: 'Successfully saved.' REMEMBERME: 'Remember me next time?' SINGULARNAME: Member SUBJECTPASSWORDCHANGED: 'Your password has been changed' From f0f83b26a8c901f78a4e6ae9b7ff9641613cc61c Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Fri, 21 Dec 2012 11:46:30 +0100 Subject: [PATCH 51/73] BUG Graceful handling of sprintf with too few params in i18n::_t() Originally discovered as a problem with the 'GridFieldDetailForm.Saved' in nl.yml --- i18n/i18n.php | 8 +++++++- tests/i18n/i18nTest.php | 9 +++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/i18n/i18n.php b/i18n/i18n.php index 98f1c6904..f714cf46b 100644 --- a/i18n/i18n.php +++ b/i18n/i18n.php @@ -1536,7 +1536,13 @@ class i18n extends Object implements TemplateGlobalProvider { // Legacy mode: If no injection placeholders are found, // replace sprintf placeholders in fixed order. // Fail silently in case the translation is outdated - $replaced = @vsprintf($returnValue, array_values($injectionArray)); + preg_match_all('/%[s,d]/', $returnValue, $returnValueArgs); + if($returnValueArgs) foreach($returnValueArgs[0] as $i => $returnValueArg) { + if($i >= count($injectionArray)) { + $injectionArray[] = ''; + } + } + $replaced = vsprintf($returnValue, array_values($injectionArray)); if($replaced) $returnValue = $replaced; } else if(!ArrayLib::is_associative($injectionArray)) { // Legacy mode: If injection placeholders are found, diff --git a/tests/i18n/i18nTest.php b/tests/i18n/i18nTest.php index 391e5a72d..07dbb7162 100644 --- a/tests/i18n/i18nTest.php +++ b/tests/i18n/i18nTest.php @@ -300,6 +300,15 @@ class i18nTest extends SapphireTest { $translated, "Testing sprintf placeholders with named injections" ); + $translated = i18n::_t( + 'i18nTestModule.INJECTIONSLEGACY', // has %s placeholders + array("Cat", "meow"/*, "meow" */) // remove third arg + ); + $this->assertContains( + "TRANS Hello Cat meow. But it is late, ", + $translated, "Testing sprintf placeholders with unnamed injections and too few args" + ); + $translated = i18n::_t( 'i18nTestModule.INJECTIONS', // has {name} placeholders array("Cat", "meow", "meow") From 3fd176914297da424a9812557697a25e3bf9d28a Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Fri, 21 Dec 2012 14:26:51 +0100 Subject: [PATCH 52/73] Added docs about which branch to choose --- docs/en/installation/composer.md | 7 +++--- docs/en/misc/contributing/code.md | 36 ++++++++++++++++++------------- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/docs/en/installation/composer.md b/docs/en/installation/composer.md index c738cc8c6..ed2c947de 100644 --- a/docs/en/installation/composer.md +++ b/docs/en/installation/composer.md @@ -212,7 +212,7 @@ Both the version and the alias are specified as Composer versions, not branch na This is not the only way to set things up in Composer. For more information on this topic, read the ["Aliases" chapter of the Composer documentation](http://getcomposer.org/doc/articles/aliases.md). -## Setting up an environment for contributing to SilverStripe +## Setting up an environment for contributing to SilverStripe {#contributing} So you want to contribute to SilverStripe? Fantastic! You can do this with composer too. You have to tell composer three things in order to be able to do this: @@ -231,8 +231,9 @@ The `--keep-vcs` flag will make sure you have access to the git history of the i The `--dev` flag will add a couple modules which are useful for SilverStripe development: - * The `compass` module will regenerate CSS if you update the SCSS files * The `docsviewer` module will let you preview changes to the project documentation * The `buildtools` module which adds [phing](http://phing.info) tasks for creating SilverStripe releases -Note that you can also include those into an existing project by running `composer update --dev`. \ No newline at end of file +Note that you can also include those into an existing project by running `composer update --dev`. +Please read the ["Contributing Code"](/misc/contributing/code) documentation to find out how to +create forks and send pull requests. \ No newline at end of file diff --git a/docs/en/misc/contributing/code.md b/docs/en/misc/contributing/code.md index c78f8514a..677f1e5a4 100644 --- a/docs/en/misc/contributing/code.md +++ b/docs/en/misc/contributing/code.md @@ -16,29 +16,32 @@ We ask for this so that the ownership in the license is clear and unambiguous, a ## Step-by-step: From forking to sending the pull request - 1. Follow the [Installation for contributions](../../installation/from-source#option-2-installation-for-contributions) instructions, which explain how to fork the core modules and add the correct "upstream" remote. +1. Follow the [Installation through Composer](../../installation/composer#contributing) instructions, +which explain how to fork the core modules and add the correct "upstream" remote. In short: - 1. [Branch for new issue and develop on issue branch](code#branch-for-new-issue-and-develop-on-issue-branch) + composer create-project --keep-vcs --dev silverstripe/installer ./my/website/folder 3.0.x-dev - $ git branch ###-description - $ git checkout ###-description +2. [Branch for new issue and develop on issue branch](code#branch-for-new-issue-and-develop-on-issue-branch) - 1. As time passes, the upstream repository accumulates new commits. Keep your working copy's master branch and issue branch up to date by periodically [rebasing your development branch on the latest upstream](code#rebase-your-development-branch-on-the-latest-upstream). + git branch ###-description + git checkout ###-description - # [make sure all your changes are committed as necessary in branch] - $ git fetch upstream - $ git rebase upstream/master +3. As time passes, the upstream repository accumulates new commits. Keep your working copy's master branch and issue branch up to date by periodically [rebasing your development branch on the latest upstream](code#rebase-your-development-branch-on-the-latest-upstream). - 1. When development is complete, [squash all commit related to a single issue into a single commit](code#squash-all-commits-related-to-a-single-issue-into-a-single-commit). + # [make sure all your changes are committed as necessary in branch] + git fetch upstream + git rebase upstream/master - $ git fetch upstream - $ git rebase -i upstream/master +4. When development is complete, [squash all commit related to a single issue into a single commit](code#squash-all-commits-related-to-a-single-issue-into-a-single-commit). - 1. Push release candidate branch to GitHub + git fetch upstream + git rebase -i upstream/master - $ git push origin ###-description +5. Push release candidate branch to GitHub - 1. Issue pull request on GitHub. Visit your forked respoistory on GitHub.com and click the "Create Pull Request" button nex tot the new branch. + git push origin ###-description + +6. Issue pull request on GitHub. Visit your forked respoistory on GitHub.com and click the "Create Pull Request" button nex tot the new branch. The core team is then responsible for reviewing patches and deciding if they will make it into core. If there are any problems they will follow up with you, so please ensure they have a way to contact you! @@ -61,7 +64,10 @@ If you're familiar with it, here's the short version of what you need to know. O * **Squash your commits, so that each commit addresses a single issue.** After you rebase your work on top of the upstream master, you can squash multiple commits into one. Say, for instance, you've got three commits in related to Issue #100. Squash all three into one with the message "Issue #100 Description of the issue here." We won't accept pull requests for multiple commits related to a single issue; it's up to you to squash and clean your commit tree. (Remember, if you squash commits you've already pushed to GitHub, you won't be able to push that same branch again. Create a new local branch, squash, and push the new squashed branch.) - + * **Choose the correct branch**: Assume the current release is 3.0.3, and 3.1.0 is in beta state. + Most pull requests should go against the `3.1.x-dev` *pre-release branch*, only critical bugfixes + against the `3.0.x-dev` *release branch*. If you're changing an API or introducing a major feature, + the pull request should go against `master` (read more about our [release process](/misc/release-process)). ### Editing files directly on GitHub.com From e53280c6500e82a28b5ffec1ec3c24d2df9aad87 Mon Sep 17 00:00:00 2001 From: g4b0 Date: Thu, 20 Dec 2012 14:04:22 +0100 Subject: [PATCH 53/73] BUG SQLQuery::aggregate() with limit, groupBy and orderBy (fixes #8148) --- model/SQLQuery.php | 22 +++++++++++++--------- tests/model/SQLQueryTest.php | 14 ++++++++++++++ tests/model/SQLQueryTest.yml | 2 ++ 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/model/SQLQuery.php b/model/SQLQuery.php index e8fc21b00..e23e191c1 100644 --- a/model/SQLQuery.php +++ b/model/SQLQuery.php @@ -1060,18 +1060,22 @@ class SQLQuery { /** * Return a new SQLQuery that calls the given aggregate functions on this data. + * * @param $column An aggregate expression, such as 'MAX("Balance")', or a set of them (as an escaped SQL statement) + * @param $alias An optional alias for the aggregate column. */ - public function aggregate($column) { - if($this->groupby || $this->limit) { - throw new Exception("SQLQuery::aggregate() doesn't work with groupby or limit, yet"); - } - + public function aggregate($column, $alias = null) { + $clone = clone $this; - $clone->setLimit(array()); - $clone->setOrderBy(array()); - $clone->setGroupBy(array()); - $clone->setSelect($column); + $clone->setLimit($this->limit); + $clone->setOrderBy($this->orderby); + $clone->setGroupBy($this->groupby); + if($alias) { + $clone->selectField($column, $alias); + } else { + $clone->setSelect($column); + } + return $clone; } diff --git a/tests/model/SQLQueryTest.php b/tests/model/SQLQueryTest.php index d3e64b827..922444bbf 100755 --- a/tests/model/SQLQueryTest.php +++ b/tests/model/SQLQueryTest.php @@ -367,6 +367,19 @@ class SQLQueryTest extends SapphireTest { $this->assertEquals('Object 1', $row['Name']); } } + + /** + * Tests aggregate() function + */ + public function testAggregate() { + $query = new SQLQuery(); + $query->setFrom('"SQLQueryTest_DO"'); + $query->setGroupBy("Common"); + + $queryClone = $query->aggregate('COUNT(*)', 'cnt'); + $result = $queryClone->execute(); + $this->assertEquals(array(2), $result->column('cnt')); + } /** * Test that "_SortColumn0" is added for an aggregate in the ORDER BY @@ -399,6 +412,7 @@ class SQLQueryTest_DO extends DataObject implements TestOnly { static $db = array( "Name" => "Varchar", "Meta" => "Varchar", + "Common" => "Varchar", "Date" => "SS_Datetime" ); } diff --git a/tests/model/SQLQueryTest.yml b/tests/model/SQLQueryTest.yml index 9d88cd25b..ad9a11238 100644 --- a/tests/model/SQLQueryTest.yml +++ b/tests/model/SQLQueryTest.yml @@ -2,8 +2,10 @@ SQLQueryTest_DO: test1: Name: 'Object 1' Meta: 'Details 1' + Common: 'Common Value' Date: 2012-01-01 10:00:00 test2: Name: 'Object 2' Meta: 'Details 2' Date: 2012-05-01 09:00:00 + Common: 'Common Value' \ No newline at end of file From 775567d42715223f7c9f1e8c3d8cc7c15847d81b Mon Sep 17 00:00:00 2001 From: Simon Elvery Date: Wed, 19 Dec 2012 17:21:49 +1000 Subject: [PATCH 54/73] Allow <% if not $autoUpload %> diff --git a/tests/forms/uploadfield/UploadFieldTest.php b/tests/forms/uploadfield/UploadFieldTest.php index 2ceb16b17..8831e6206 100644 --- a/tests/forms/uploadfield/UploadFieldTest.php +++ b/tests/forms/uploadfield/UploadFieldTest.php @@ -476,6 +476,42 @@ class UploadFieldTest extends FunctionalTest { } + public function testCanUpload() { + $this->loginWithPermission('ADMIN'); + $response = $this->get('UploadFieldTest_Controller'); + $this->assertFalse($response->isError()); + + $parser = new CSSContentParser($response->getBody()); + $this->assertFalse( + (bool)$parser->getBySelector('#CanUploadFalseField .ss-uploadfield-fromcomputer-fileinput'), + 'Removes input file control' + ); + $this->assertFalse((bool)$parser->getBySelector('#CanUploadFalseField .ss-uploadfield-dropzone'), + 'Removes dropzone'); + $this->assertTrue( + (bool)$parser->getBySelector('#CanUploadFalseField .ss-uploadfield-fromfiles'), + 'Keeps "From files" button' + ); + } + + public function testCanUploadWithPermissionCode() { + $field = new UploadField('MyField'); + + $field->setConfig('canUpload', true); + $this->assertTrue($field->canUpload()); + + $field->setConfig('canUpload', false); + $this->assertFalse($field->canUpload()); + + $this->loginWithPermission('ADMIN'); + + $field->setConfig('canUpload', false); + $this->assertFalse($field->canUpload()); + + $field->setConfig('canUpload', 'ADMIN'); + $this->assertTrue($field->canUpload()); + } + public function testIsSaveable() { $form = $this->getMockForm(); @@ -775,6 +811,10 @@ class UploadFieldTest_Controller extends Controller implements TestOnly { $fieldSubfolder->setFolderName('UploadFieldTest/subfolder1'); $fieldSubfolder->setRecord($record); + $fieldCanUploadFalse = new UploadField('CanUploadFalseField'); + $fieldCanUploadFalse->setConfig('canUpload', false); + $fieldCanUploadFalse->setRecord($record); + $form = new Form( $this, 'Form', @@ -789,7 +829,8 @@ class UploadFieldTest_Controller extends Controller implements TestOnly { $fieldManyMany, $fieldReadonly, $fieldDisabled, - $fieldSubfolder + $fieldSubfolder, + $fieldCanUploadFalse ), new FieldList( new FormAction('submit') @@ -805,7 +846,8 @@ class UploadFieldTest_Controller extends Controller implements TestOnly { 'ManyManyFiles', 'ReadonlyField', 'DisabledField', - 'SubfolderField' + 'SubfolderField', + 'CanUploadFalseField' ) ); return $form; From 43601d601029e6a0ac8304fafa7510dbfa58c650 Mon Sep 17 00:00:00 2001 From: Ingo Schommer Date: Wed, 9 Jan 2013 13:28:12 +0100 Subject: [PATCH 73/73] NEW Global default config for UploadField --- _config/uploadfield.yml | 14 ++++++++++ docs/en/reference/uploadfield.md | 47 ++++++++++++++++++++++++++++---- forms/UploadField.php | 13 ++++++--- 3 files changed, 65 insertions(+), 9 deletions(-) create mode 100644 _config/uploadfield.yml diff --git a/_config/uploadfield.yml b/_config/uploadfield.yml new file mode 100644 index 000000000..6227f3e50 --- /dev/null +++ b/_config/uploadfield.yml @@ -0,0 +1,14 @@ +name: uploadfield +--- +UploadField: + defaultConfig: + autoUpload: true + allowedMaxFileNumber: + canUpload: true + previewMaxWidth: 80 + previewMaxHeight: 60 + uploadTemplateName: 'ss-uploadfield-uploadtemplate' + downloadTemplateName: 'ss-uploadfield-downloadtemplate' + fileEditFields: + fileEditActions: + fileEditValidator: \ No newline at end of file diff --git a/docs/en/reference/uploadfield.md b/docs/en/reference/uploadfield.md index 37dbbfac9..1d8db946f 100644 --- a/docs/en/reference/uploadfield.md +++ b/docs/en/reference/uploadfield.md @@ -9,7 +9,9 @@ as well. That makes it flexible enough to sometimes even replace the Gridfield, like for instance in creating and managing a simple gallery. ## Usage -The UploadField can be used in two ways: + +The field can be used in two ways: To upload a single file into a `has_one` relationship, +or allow multiple files into a fixed folder (or relationship). ### Single fileupload @@ -76,7 +78,23 @@ UploadField will detect the relation based on its $name property value: WARNING: Currently the UploadField doesn't fully support has_many relations, so use a many_many relation instead! -## Set a custom folder +## Configuration + +### Overview + +The field can either be configured on an instance level through `setConfig(, )`, +or globally by overriding the YAML defaults. + +Example: mysite/_config/uploadfield.yml + + after: framework#uploadfield + --- + UploadField: + defaultConfig: + canUpload: false + + +### Set a custom folder This example will save all uploads in the `/assets/customfolder/` folder. If the folder doesn't exist, it will be created. @@ -98,7 +116,7 @@ the folder doesn't exist, it will be created. $uploadField->getValidator()->setAllowedExtensions(array('jpg', 'jpeg', 'png', 'gif')); -## Limit the maximum file size +### Limit the maximum file size `AllowedMaxFileSize` is by default set to the lower value of the 2 php.ini configurations: `upload_max_filesize` and `post_max_size` The value is set as bytes. @@ -110,8 +128,6 @@ NOTE: this only sets the configuration for your UploadField, this does NOT chang $size = $sizeMB * 1024 * 1024; // 2 MB in bytes $this->getValidator()->setAllowedMaxFileSize($size); -## Other configuration settings - ### Preview dimensions Set the dimensions of the image preview. By default the max width is set to 80 @@ -182,6 +198,27 @@ Then, in your GalleryPage, tell the UploadField to use this function: In a similar fashion you can use 'fileEditActions' to set the actions for the editform, or 'fileEditValidator' to determine the validator (eg RequiredFields). + +### Configuration Reference + + - `autoUpload`: (boolean) + - `allowedMaxFileNumber`: (int) php validation of allowedMaxFileNumber + only works when a db relation is available, set to null to allow + unlimited if record has a has_one and allowedMaxFileNumber is null, it will be set to 1 + - `canUpload`: (boolean) Can the user upload new files, or just select from existing files. + String values are interpreted as permission codes. + - `previewMaxWidth`: (int) + - `previewMaxHeight`: (int) + - `uploadTemplateName`: (string) javascript template used to display uploading + files, see javascript/UploadField_uploadtemplate.js + - `downloadTemplateName`: (string) javascript template used to display already + uploaded files, see javascript/UploadField_downloadtemplate.js + - `fileEditFields`: (FieldList|string) FieldList $fields or string $name + (of a method on File to provide a fields) for the EditForm (Example: 'getCMSFields') + - `fileEditActions`: (FieldList|string) FieldList $actions or string $name + (of a method on File to provide a actions) for the EditForm (Example: 'getCMSActions') + - `fileEditValidator`: (string) Validator (eg RequiredFields) or string $name + (of a method on File to provide a Validator) for the EditForm (Example: 'getCMSValidator') ## TODO: Using the UploadField in a frontend form diff --git a/forms/UploadField.php b/forms/UploadField.php index c5374787f..4e957fc9b 100644 --- a/forms/UploadField.php +++ b/forms/UploadField.php @@ -13,6 +13,8 @@ * - Edit file * - allowedExtensions is by default File::$allowed_extensions
  • maxFileSize the value of min(upload_max_filesize, * post_max_size) from php.ini + * + * <>Usage * * @example * $UploadField = new UploadField('myFiles', 'Please upload some images (max. 5 files)'); @@ -66,9 +68,9 @@ class UploadField extends FileField { protected $items; /** - * Config for this field used in both, php and javascript (will be merged into the config of the javascript file - * upload plugin) - * @var array + * @var array Config for this field used in both, php and javascript + * (will be merged into the config of the javascript file upload plugin). + * See framework/_config/uploadfield.yml for configuration defaults and documentation. */ protected $ufConfig = array( /** @@ -82,7 +84,8 @@ class UploadField extends FileField { */ 'allowedMaxFileNumber' => null, /** - * @var boolean Can the user upload new files, or just select from existing files. + * @var boolean|string Can the user upload new files, or just select from existing files. + * String values are interpreted as permission codes. */ 'canUpload' => true, /** @@ -137,6 +140,8 @@ class UploadField extends FileField { $this->addExtraClass('ss-upload'); // class, used by js $this->addExtraClass('ss-uploadfield'); // class, used by css for uploadfield only + $this->ufConfig = array_merge($this->ufConfig, Config::inst()->get('UploadField', 'defaultConfig')); + parent::__construct($name, $title); if($items) $this->setItems($items);