diff --git a/admin/_config.php b/admin/_config.php index bc696cc86..dcd812565 100644 --- a/admin/_config.php +++ b/admin/_config.php @@ -25,7 +25,7 @@ HtmlEditorConfig::get('cms')->setOptions(array( 'extended_valid_elements' => "img[class|src|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name|usemap],iframe[src|name|width|height|align|frameborder|marginwidth|marginheight|scrolling],object[width|height|data|type],param[name|value],map[class|name|id],area[shape|coords|href|target|alt]" )); -HtmlEditorConfig::get('cms')->enablePlugins('media', 'fullscreen'); +HtmlEditorConfig::get('cms')->enablePlugins('media', 'fullscreen', 'autoresize'); HtmlEditorConfig::get('cms')->enablePlugins(array('ssbuttons' => '../../../cms/javascript/tinymce_ssbuttons/editor_plugin_src.js')); HtmlEditorConfig::get('cms')->insertButtonsBefore('formatselect', 'styleselect'); diff --git a/admin/code/CMSProfileController.php b/admin/code/CMSProfileController.php index 7d902b03c..c08172214 100644 --- a/admin/code/CMSProfileController.php +++ b/admin/code/CMSProfileController.php @@ -2,6 +2,7 @@ class CMSProfileController extends LeftAndMain { static $url_segment = 'myprofile'; + static $required_permission_codes = false; public function index($request) { $form = $this->Member_ProfileForm(); diff --git a/admin/code/LeftAndMain.php b/admin/code/LeftAndMain.php index 6ca31522b..a0a4562b1 100644 --- a/admin/code/LeftAndMain.php +++ b/admin/code/LeftAndMain.php @@ -9,7 +9,7 @@ * @package cms * @subpackage core */ -class LeftAndMain extends Controller { +class LeftAndMain extends Controller implements PermissionProvider { /** * The 'base' url for CMS administration areas. @@ -77,12 +77,20 @@ class LeftAndMain extends Controller { 'show', 'EditorToolbar', 'EditForm', - 'RootForm', 'AddForm', 'batchactions', 'BatchActionsForm', 'Member_ProfileForm', ); + + /** + * @var Array Codes which are required from the current user to view this controller. + * If multiple codes are provided, all of them are required. + * All CMS controllers require "CMS_ACCESS_LeftAndMain" as a baseline check, + * and fall back to "CMS_ACCESS_" if no permissions are defined here. + * See {@link canView()} for more details on permission checks. + */ + static $required_permission_codes; /** * Register additional requirements through the {@link Requirements} class. @@ -99,13 +107,10 @@ class LeftAndMain extends Controller { /** * @param Member $member - * * @return boolean */ function canView($member = null) { - if(!$member && $member !== FALSE) { - $member = Member::currentUser(); - } + if(!$member && $member !== FALSE) $member = Member::currentUser(); // cms menus only for logged-in members if(!$member) return false; @@ -115,12 +120,18 @@ class LeftAndMain extends Controller { $alternateAllowed = $this->alternateAccessCheck(); if($alternateAllowed === FALSE) return false; } - - // Default security check for LeftAndMain sub-class permissions - if(!Permission::checkMember($member, "CMS_ACCESS_$this->class") && - !Permission::checkMember($member, "CMS_ACCESS_LeftAndMain")) { - return false; + + // Check for "CMS admin" permission + if(Permission::checkMember($member, "CMS_ACCESS_LeftAndMain")) return true; + + // Check for LeftAndMain sub-class permissions + $codes = array(); + $extraCodes = $this->stat('required_permission_codes'); + if($extraCodes !== false) { // allow explicit FALSE to disable subclass check + if($extraCodes) $codes = array_merge($codes, (array)$extraCodes); + else $codes[] = "CMS_ACCESS_$this->class"; } + foreach($codes as $code) if(!Permission::checkMember($member, $code)) return false; return true; } @@ -861,18 +872,18 @@ class LeftAndMain extends Controller { $actions = $record->getCMSActions(); // add default actions if none are defined if(!$actions || !$actions->Count()) { - if($record->hasMethod('canDelete') && $record->canDelete()) { - $actions->push( - FormAction::create('delete',_t('ModelAdmin.DELETE','Delete')) - ->addExtraClass('ss-ui-action-destructive') - ); - } if($record->hasMethod('canEdit') && $record->canEdit()) { $actions->push( FormAction::create('save',_t('CMSMain.SAVE','Save')) ->addExtraClass('ss-ui-action-constructive')->setAttribute('data-icon', 'accept') ); } + if($record->hasMethod('canDelete') && $record->canDelete()) { + $actions->push( + FormAction::create('delete',_t('ModelAdmin.DELETE','Delete')) + ->addExtraClass('ss-ui-action-destructive') + ); + } } } @@ -913,16 +924,12 @@ class LeftAndMain extends Controller { $form->setFields($readonlyFields); } } else { - $form = $this->RootForm(); + $form = $this->EmptyForm(); } return $form; } - function RootForm() { - return $this->EmptyForm(); - } - /** * Returns a placeholder form, used by {@link getEditForm()} if no record is selected. * Our javascript logic always requires a form to be present in the CMS interface. @@ -1006,10 +1013,7 @@ class LeftAndMain extends Controller { $form->saveInto($record); $record->write(); - // Used in TinyMCE inline folder creation - if(isset($data['returnID'])) { - return $record->ID; - } else if($this->isAjax()) { + if($this->isAjax()) { $form = $this->getEditForm($record->ID); return $form->forTemplate(); } else { @@ -1084,11 +1088,11 @@ class LeftAndMain extends Controller { 'BatchActionsForm', new FieldList( new HiddenField('csvIDs'), - new DropdownField( + Object::create('DropdownField', 'Action', false, $actionsMap - ) + )->setAttribute('autocomplete', 'off') ), new FieldList( // TODO i18n @@ -1310,6 +1314,37 @@ class LeftAndMain extends Controller { function Locale() { return DBField::create('DBLocale', i18n::get_locale()); } + + function providePermissions() { + $perms = array( + "CMS_ACCESS_LeftAndMain" => array( + 'name' => _t('CMSMain.ACCESSALLINTERFACES', 'Access to all CMS sections'), + 'category' => _t('Permission.CMS_ACCESS_CATEGORY', 'CMS Access'), + 'help' => _t('CMSMain.ACCESSALLINTERFACESHELP', 'Overrules more specific access settings.'), + 'sort' => -100 + ) + ); + + // Add any custom ModelAdmin subclasses. Can't put this on ModelAdmin itself + // since its marked abstract, and needs to be singleton instanciated. + foreach(ClassInfo::subclassesFor('ModelAdmin') as $i => $class) { + if($class == 'ModelAdmin') continue; + if(ClassInfo::classImplements($class, 'TestOnly')) continue; + + $title = _t("{$class}.MENUTITLE", LeftAndMain::menu_title_for_class($class)); + $perms["CMS_ACCESS_" . $class] = array( + 'name' => sprintf(_t( + 'CMSMain.ACCESS', + "Access to '%s' section", + PR_MEDIUM, + "Item in permission selection identifying the admin section. Example: Access to 'Files & Images'" + ), $title, null), + 'category' => _t('Permission.CMS_ACCESS_CATEGORY', 'CMS Access') + ); + } + + return $perms; + } /** * Register the given javascript file as required in the CMS. diff --git a/admin/code/MemberTableField.php b/admin/code/MemberTableField.php deleted file mode 100644 index 9309eacc4..000000000 --- a/admin/code/MemberTableField.php +++ /dev/null @@ -1,370 +0,0 @@ -group = $group; - $members = $group->Members(); - - } elseif(isset($_REQUEST['ctf'][$this->getName()]["ID"]) && is_numeric($_REQUEST['ctf'][$this->getName()]["ID"])) { - throw new Exception("Is this still being used? It's a hack and we should remove it."); - $group = DataObject::get_by_id('Group', $_REQUEST['ctf'][$this->getName()]["ID"]); - $this->group = $group; - $members = $group->Members(); - } else { - $members = DataObject::get("Member"); - } - } - - $SNG_member = singleton('Member'); - $fieldList = $SNG_member->summaryFields(); - $memberDbFields = $SNG_member->db(); - $csvFieldList = array(); - - foreach($memberDbFields as $field => $dbFieldType) { - $csvFieldList[$field] = $field; - } - - if(!$hidePassword) { - $fieldList["SetPassword"] = "Password"; - } - - $this->hidePassword = $hidePassword; - - // Add a search filter - $SQL_search = isset($_REQUEST['MemberSearch']) ? Convert::raw2sql($_REQUEST['MemberSearch']) : null; - if(!empty($_REQUEST['MemberSearch'])) { - $searchFilters = array(); - foreach($SNG_member->searchableFields() as $fieldName => $fieldSpec) { - if(strpos($fieldName, '.') === false) $searchFilters[] = "\"$fieldName\" LIKE '%{$SQL_search}%'"; - } - $members = $members->where('(' . implode(' OR ', $searchFilters) . ')'); - } - - parent::__construct($controller, $name, $members, $fieldList); - - $this->setFieldListCsv($csvFieldList); - $this->setPageSize($this->stat('page_size')); - } - - function FieldHolder() { - $ret = parent::FieldHolder(); - - Requirements::javascript(SAPPHIRE_DIR . "/thirdparty/scriptaculous/controls.js"); - Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/javascript/MemberTableField.js'); - Requirements::javascript(SAPPHIRE_ADMIN_DIR . "/javascript/MemberTableField_popup.js"); - - return $ret; - } - - function SearchForm() { - $groupID = (isset($this->group)) ? $this->group->ID : 0; - $query = isset($_GET['MemberSearch']) ? $_GET['MemberSearch'] : null; - - $searchFields = new FieldGroup( - new TextField('MemberSearch', _t('MemberTableField.SEARCH', 'Search'), $query), - new HiddenField("ctf[ID]", '', $groupID), - new HiddenField('MemberFieldName', '', $this->name), - new HiddenField('MemberDontShowPassword', '', $this->hidePassword) - ); - - $actionFields = new LiteralField('MemberFilterButton',''); - - $fieldContainer = new FieldGroup( - $searchFields, - $actionFields - ); - - return $fieldContainer->FieldHolder(); - } - - /** - * Add existing member to group rather than creating a new member - */ - function addtogroup() { - // Protect against CSRF on destructive action - $token = $this->getForm()->getSecurityToken(); - if(!$token->checkRequest($this->controller->getRequest())) return $this->httpError(400); - - $data = $_REQUEST; - - $groupID = (isset($data['ctf']['ID'])) ? $data['ctf']['ID'] : null; - - if(!is_numeric($groupID)) { - FormResponse::status_messsage(_t('MemberTableField.ADDINGFIELD', 'Adding failed'), 'bad'); - return; - } - - // Get existing record either by ID or unique identifier. - $identifierField = Member::get_unique_identifier_field(); - $className = 'Member'; - $record = null; - if(isset($data[$identifierField])) { - $record = DataObject::get_one( - $className, - sprintf('"%s" = \'%s\'', $identifierField, $data[$identifierField]) - ); - - if($record && !$record->canEdit()) return $this->httpError('401'); - } - - // Fall back to creating a new record - if(!$record) $record = new $className(); - - // Update an existing record, or populate a new one. - // If values on an existing (autocompleted) record have been changed, - // they will overwrite current data. We need to unset 'ID' - // record as it points to the group rather than the member record, and would - // cause the member to be written to a potentially existing record. - unset($data['ID']); - $record->update($data); - - // Validate record, mainly password restrictions. - // Note: Doesn't use Member_Validator - $valid = $record->validate(); - if($valid->valid()) { - $record->write(); - $this->getDataList()->add($record); - - $this->sourceItems(); - - // TODO add javascript to highlight added row (problem: might not show up due to sorting/filtering) - FormResponse::update_dom_id($this->id(), $this->renderWith($this->template), true); - FormResponse::status_message( - _t( - 'MemberTableField.ADDEDTOGROUP','Added member to group' - ), - 'good' - ); - - } else { - $message = sprintf( - _t( - 'MemberTableField.ERRORADDINGUSER', - 'There was an error adding the user to the group: %s' - ), - Convert::raw2xml($valid->starredList()) - ); - - FormResponse::status_message($message, 'bad'); - } - - return FormResponse::respond(); - } - - /** - * ################################# - * Custom Functions - * ################################# - */ - - /** - * @return Group - */ - function getGroup() { - return $this->group; - } - - /** - * Add existing member to group by name (with JS-autocompletion) - */ - function AddRecordForm() { - $fields = new FieldList(); - foreach($this->FieldList() as $fieldName => $fieldTitle) { - // If we're adding the set password field, we want to hide the text from any peeping eyes - if($fieldName == 'SetPassword') { - $fields->push(new PasswordField($fieldName)); - } else { - $fields->push(new TextField($fieldName)); - } - } - if($this->group) { - $fields->push(new HiddenField('ctf[ID]', null, $this->group->ID)); - } - $actions = new FieldList( - new FormAction('addtogroup', _t('MemberTableField.ADD','Add')) - ); - - return new TabularStyle( - new NestedForm( - new Form( - $this, - 'AddRecordForm', - $fields, - $actions - ) - ) - ); - } - - function AddForm() { - $form = parent::AddForm(); - - // Set default groups - also implemented in MemberTableField_Popup::__construct() - if($this->group) { - $groupsField = $form->Fields()->dataFieldByName('Groups'); - // TODO Needs to be a string value (not int) because of TreeMultiselectField->getItems(), - // see http://open.silverstripe.org/ticket/5836 - if($groupsField) $groupsField->setValue((string)$this->group->ID); - } - - return $form; - } - - /** - * Same behaviour as parent class, but adds the - * member to the passed GroupID. - * - * @return string - */ - function saveComplexTableField($data, $form, $params) { - $className = $this->sourceClass(); - $childData = new $className(); - - // Needs to write before saveInto() to ensure the 'Groups' TreeMultiselectField saves - $childData->write(); - - try { - $form->saveInto($childData); - $childData->write(); - } catch(ValidationException $e) { - $form->sessionMessage($e->getResult()->message(), 'bad'); - return Director::redirectBack(); - } - - $closeLink = sprintf( - '(%s)', - _t('ComplexTableField.CLOSEPOPUP', 'Close Popup') - ); - $message = sprintf( - _t('ComplexTableField.SUCCESSADD', 'Added %s %s %s'), - $childData->singular_name(), - '' . htmlspecialchars($childData->Title, ENT_QUOTES, 'UTF-8') . '', - $closeLink - ); - $form->sessionMessage($message, 'good'); - - $this->controller->redirectBack(); - } -} - -/** - * Popup window for {@link MemberTableField}. - * @package cms - * @subpackage security - */ -class MemberTableField_Popup extends ComplexTableField_Popup { - - function __construct($controller, $name, $fields, $validator, $readonly, $dataObject) { - $group = ($controller instanceof MemberTableField) ? $controller->getGroup() : $controller->getParentController()->getGroup(); - // Set default groups - also implemented in AddForm() - if($group) { - $groupsField = $fields->dataFieldByName('Groups'); - if($groupsField) $groupsField->setValue($group->ID); - } - - parent::__construct($controller, $name, $fields, $validator, $readonly, $dataObject); - } - - function forTemplate() { - $ret = parent::forTemplate(); - - Requirements::css(SAPPHIRE_ADMIN_DIR . '/css/SecurityAdmin.css'); - Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/javascript/MemberTableField.js'); - Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/javascript/MemberTableField_popup.js'); - - return $ret; - } - -} - -/** -* @package cms -* @subpackage security -*/ -class MemberTableField_Item extends ComplexTableField_Item { - - function Actions() { - $actions = parent::Actions(); - - foreach($actions as $action) { - if($action->Name == 'delete') { - if($this->parent->getGroup()) { - $action->TitleText = _t('MemberTableField.DeleteTitleText', - 'Delete from this group', - PR_MEDIUM, - 'Delete button hover text' - ); - } else { - $action->TitleText = _t('MemberTableField.DeleteTitleTextDatabase', - 'Delete from database and all groups', - PR_MEDIUM, - 'Delete button hover text' - ); - } - } - } - - return $actions; - } -} - diff --git a/admin/code/ModelAdmin.php b/admin/code/ModelAdmin.php index 922cf59b6..c2f833e12 100644 --- a/admin/code/ModelAdmin.php +++ b/admin/code/ModelAdmin.php @@ -125,7 +125,7 @@ abstract class ModelAdmin extends LeftAndMain { * Class name of the form field used for the results list. Overloading this in subclasses * can let you customise the results table field. */ - protected $resultsTableClassName = 'TableListField'; + protected $resultsTableClassName = 'GridField'; /** * Return {@link $this->resultsTableClassName} @@ -651,24 +651,7 @@ class ModelAdmin_CollectionController extends Controller { function search($request, $form) { // Get the results form to be rendered $resultsForm = $this->ResultsForm(array_merge($form->getData(), $request)); - // Before rendering, let's get the total number of results returned - $tableField = $resultsForm->Fields()->dataFieldByName($this->modelClass); - $tableField->addExtraClass('resultsTable'); - $numResults = $tableField->TotalCount(); - - if($numResults) { - $msg = sprintf( - _t('ModelAdmin.FOUNDRESULTS',"Your search found %s matching items"), - $numResults - ); - } else { - $msg = _t('ModelAdmin.NORESULTS',"Your search didn't return any matching items"); - } - return new SS_HTTPResponse( - $resultsForm->forTemplate(), - 200, - $msg - ); + return $resultsForm->forTemplate(); } /** @@ -715,37 +698,21 @@ class ModelAdmin_CollectionController extends Controller { * * @param array $searchCriteria passed through from ResultsForm * - * @return TableListField + * @return GridField */ function getResultsTable($searchCriteria) { - $summaryFields = $this->getResultColumns($searchCriteria); - $className = $this->parentController->resultsTableClassName(); - $tf = new $className( + $datalist = $this->getSearchQuery($searchCriteria); + $numItemsPerPage = $this->parentController->stat('page_length'); + $tf = Object::create($className, $this->modelClass, - $this->modelClass, - $summaryFields - ); + false, + $datalist, + $fieldConfig = GridFieldConfig_RecordEditor::create($numItemsPerPage) + ->addComponent(new GridFieldExporter())->removeComponentsByType('GridFieldFilter') + )->setDisplayFields($this->getResultColumns($searchCriteria)); - $tf->setCustomQuery($this->getSearchQuery($searchCriteria)); - $tf->setPageSize($this->parentController->stat('page_length')); - $tf->setShowPagination(true); - // @todo Remove records that can't be viewed by the current user - $tf->setPermissions(array_merge(array('view','export'), TableListField::permissions_for_object($this->modelClass))); - - // csv export settings (select all columns regardless of user checkbox settings in 'ResultsAssembly') - $exportFields = $this->getResultColumns($searchCriteria, false); - $tf->setFieldListCsv($exportFields); - - $url = 'Link() . '/$ID/edit\">$value'; - if(count($summaryFields)) { - $tf->setFieldFormatting(array_combine( - array_keys($summaryFields), - array_fill(0,count($summaryFields), $url) - )); - } - return $tf; } @@ -757,7 +724,6 @@ class ModelAdmin_CollectionController extends Controller { * @return Form */ function ResultsForm($searchCriteria) { - if($searchCriteria instanceof SS_HTTPRequest) $searchCriteria = $searchCriteria->getVars(); $tf = $this->getResultsTable($searchCriteria); @@ -876,6 +842,13 @@ class ModelAdmin_CollectionController extends Controller { Director::redirect(Controller::join_links($this->Link(), $model->ID , 'edit')); } } + + /** + * @return ArrayList + */ + public function Breadcrumbs(){ + return new ArrayList(); + } } /** diff --git a/admin/code/SecurityAdmin.php b/admin/code/SecurityAdmin.php index 2e9723dd8..a3c8886da 100755 --- a/admin/code/SecurityAdmin.php +++ b/admin/code/SecurityAdmin.php @@ -17,15 +17,11 @@ class SecurityAdmin extends LeftAndMain implements PermissionProvider { static $subitem_class = 'Member'; static $allowed_actions = array( - 'autocomplete', - 'removememberfromgroup', - 'AddRecordForm', 'EditForm', 'MemberImportForm', 'memberimport', 'GroupImportForm', 'groupimport', - 'RootForm' ); /** @@ -47,71 +43,29 @@ class SecurityAdmin extends LeftAndMain implements PermissionProvider { $record = $this->getRecord($id); if($record && !$record->canView()) return Security::permissionFailure($this); - if($id && is_numeric($id)) { - $form = parent::getEditForm($id); - if(!$form) return false; - - $fields = $form->Fields(); - if($fields->hasTabSet() && $record->canEdit()) { - $fields->findOrMakeTab('Root.Import',_t('Group.IMPORTTABTITLE', 'Import')); - $fields->addFieldToTab('Root.Import', - new LiteralField( - 'MemberImportFormIframe', - sprintf( - '', - $this->Link('memberimport') - ) - ) - ); - if(Permission::check('APPLY_ROLES')) { - $fields->addFieldToTab( - 'Root.Roles', - new LiteralField( - 'RolesAddEditLink', - sprintf( - '

%s

', - $this->Link('show/root'), - // TODO This should include #Root_Roles to switch directly to the tab, - // but tabstrip.js doesn't display tabs when directly adressed through a URL pragma - _t('Group.RolesAddEditLink', 'Add/edit roles') - ) - ) - ); - } - - // Filter permissions - $permissionField = $form->Fields()->dataFieldByName('Permissions'); - if($permissionField) $permissionField->setHiddenPermissions(self::$hidden_permissions); - } - - $this->extend('updateEditForm', $form); - } else { - $form = $this->RootForm(); - } + $memberList = Object::create('GridField', + 'Members', + false, + DataList::create('Member'), + $memberListConfig = GridFieldConfig_RecordEditor::create() + ->addComponent(new GridFieldExporter()) + )->addExtraClass("members_grid"); + $memberListConfig->getComponentByType('GridFieldPopupForms')->setValidator(new Member_Validator()); - $form->setTemplate($this->getTemplatesWithSuffix('_EditForm')); - if($form->Fields()->hasTabset()) $form->Fields()->findOrMakeTab('Root')->setTemplate('CMSTabSet'); - $form->addExtraClass('center ss-tabset ' . $this->BaseCSSClasses()); - - return $form; - } + $groupList = Object::create('GridField', + 'Groups', + false, + DataList::create('Group'), + GridFieldConfig_RecordEditor::create() + )->setDisplayFields(array( + 'Breadcrumbs' => singleton('Group')->fieldLabel('Title') + )); - /** - * @return FieldList - */ - function RootForm() { - $config = new GridFieldConfig_Base(25); - $config->addComponent(new GridFieldAction_Edit()); - $config->addComponent(new GridFieldAction_Delete()); - $config->addComponent(new GridFieldPopupForms()); - $config->addComponent(new GridFieldExporter()); - $memberList = new GridField('Members', 'All members', DataList::create('Member'), $config); - $memberList->addExtraClass("members_grid"); $fields = new FieldList( $root = new TabSet( 'Root', - new Tab('Members', singleton('Member')->i18n_plural_name(), + new Tab('Users', _t('SecurityAdmin.Users', 'Users'), $memberList, new LiteralField('MembersCautionText', sprintf('

%s

', @@ -122,14 +76,8 @@ class SecurityAdmin extends LeftAndMain implements PermissionProvider { ) ) ), - new Tab('Import', _t('SecurityAdmin.TABIMPORT', 'Import'), - new LiteralField( - 'GroupImportFormIframe', - sprintf( - '', - $this->Link('groupimport') - ) - ) + new Tab('Groups', singleton('Group')->plural_name(), + $groupList ) ), // necessary for tree node selection in LeftAndMain.EditForm.js @@ -140,25 +88,35 @@ class SecurityAdmin extends LeftAndMain implements PermissionProvider { // Add roles editing interface if(Permission::check('APPLY_ROLES')) { - $rolesCTF = new ComplexTableField( - $this, + $rolesField = new GridField( 'Roles', - 'PermissionRole' + false, + DataList::create('PermissionRole'), + GridFieldConfig_RecordEditor::create() ); - $rolesCTF->setPermissions(array('add', 'edit', 'delete')); + // $rolesCTF->setPermissions(array('add', 'edit', 'delete')); $rolesTab = $fields->findOrMakeTab('Root.Roles', _t('SecurityAdmin.TABROLES', 'Roles')); $rolesTab->push(new LiteralField( 'RolesDescription', '' )); - $rolesTab->push($rolesCTF); + $rolesTab->push($rolesField); } + $fields->findOrMakeTab('Root.Import', _t('SecurityAdmin.TABIMPORT', 'Import')); + $fields->addFieldToTab('Root.Import', + new LiteralField( + 'GroupImportFormIframe', + sprintf( + '', + $this->Link('groupimport') + ) + ) + ); + $actions = new FieldList(); - $this->extend('updateRootFormFields', $fields, $actions); - $form = new Form( $this, 'EditForm', @@ -166,14 +124,12 @@ class SecurityAdmin extends LeftAndMain implements PermissionProvider { $actions ); $form->addExtraClass('cms-edit-form'); - - return $form; - } - - function AddForm() { - $form = parent::AddForm(); - $form->Actions()->fieldByName('action_doAdd')->setTitle(_t('SecurityAdmin.ActionAdd', 'Add group')); - + $form->setTemplate($this->getTemplatesWithSuffix('_EditForm')); + if($form->Fields()->hasTabset()) $form->Fields()->findOrMakeTab('Root')->setTemplate('CMSTabSet'); + $form->addExtraClass('center ss-tabset ' . $this->BaseCSSClasses()); + + $this->extend('updateEditForm', $form); + return $form; } @@ -237,61 +193,41 @@ class SecurityAdmin extends LeftAndMain implements PermissionProvider { return $form; } - public function AddRecordForm() { - $m = Object::create('MemberTableField', - $this, - "Members", - $this->currentPageID() - ); - return $m->AddRecordForm(); - } + public function Breadcrumbs($unlinked = false) { + $crumbs = parent::Breadcrumbs($unlinked); - /** - * Ajax autocompletion - */ - public function autocomplete() { - $fieldName = $this->urlParams['ID']; - $fieldVal = $_REQUEST[$fieldName]; - $result = ''; - $uidField = Member::get_unique_identifier_field(); - - // Make sure we only autocomplete on keys that actually exist, and that we don't autocomplete on password - if(!singleton($this->stat('subitem_class'))->hasDatabaseField($fieldName) || $fieldName == 'Password') return; - - $matches = DataObject::get($this->stat('subitem_class'),"\"$fieldName\" LIKE '" . Convert::raw2sql($fieldVal) . "%'"); - if($matches) { - $result .= ""; - return $result; + } else { + // Avoid writing "Users" (the controller menu title) as a breadcrumb + // because its confusing and inaccurate. + $crumbs = new ArrayList(); } - } - - function getCMSTreeTitle() { - return _t('SecurityAdmin.SGROUPS', 'Security Groups'); - } - public function EditedMember() { - if(Session::get('currentMember')) return DataObject::get_by_id('Member', (int) Session::get('currentMember')); + return $crumbs; } function providePermissions() { + $title = _t("SecurityAdmin.MENUTITLE", LeftAndMain::menu_title_for_class($this->class)); return array( + "CMS_ACCESS_SecurityAdmin" => array( + 'name' => sprintf(_t('CMSMain.ACCESS', "Access to '%s' section"), $title), + 'category' => _t('Permission.CMS_ACCESS_CATEGORY', 'CMS Access'), + 'help' => _t( + 'SecurityAdmin.ACCESS_HELP', + 'Allow viewing, adding and editing users, as well as assigning permissions and roles to them.' + ) + ), 'EDIT_PERMISSIONS' => array( 'name' => _t('SecurityAdmin.EDITPERMISSIONS', 'Manage permissions for groups'), 'category' => _t('Permissions.PERMISSIONS_CATEGORY', 'Roles and access permissions'), @@ -301,7 +237,7 @@ class SecurityAdmin extends LeftAndMain implements PermissionProvider { 'APPLY_ROLES' => array( 'name' => _t('SecurityAdmin.APPLY_ROLES', 'Apply roles to groups'), 'category' => _t('Permissions.PERMISSIONS_CATEGORY', 'Roles and access permissions'), - 'help' => _t('SecurityAdmin.APPLY_ROLES_HELP', 'Ability to edit the roles assigned to a group. Requires the "Access to \'Security\' section" permission.'), + 'help' => _t('SecurityAdmin.APPLY_ROLES_HELP', 'Ability to edit the roles assigned to a group. Requires the "Access to \'Users\' section" permission.'), 'sort' => 0 ) ); @@ -339,37 +275,4 @@ class SecurityAdmin extends LeftAndMain implements PermissionProvider { static function clear_hidden_permissions(){ self::$hidden_permissions = array(); } -} - -/** - * Delete multiple {@link Group} records. Usually used through the {@link SecurityAdmin} interface. - * - * @package cms - * @subpackage batchactions - */ -class SecurityAdmin_DeleteBatchAction extends CMSBatchAction { - function getActionTitle() { - return _t('AssetAdmin_DeleteBatchAction.TITLE', 'Delete groups'); - } - - function run(SS_List $records) { - $status = array( - 'modified'=>array(), - 'deleted'=>array() - ); - - foreach($records as $record) { - // TODO Provide better feedback if permission was denied - if(!$record->canDelete()) continue; - - $id = $record->ID; - $record->delete(); - $status['deleted'][$id] = array(); - $record->destroy(); - unset($record); - } - - return Convert::raw2json($status); - } -} - +} \ No newline at end of file diff --git a/admin/css/ie7.css b/admin/css/ie7.css index 7d185239c..e1776a625 100644 --- a/admin/css/ie7.css +++ b/admin/css/ie7.css @@ -15,4 +15,33 @@ html { overflow: hidden; } .jstree li a .ui-icon { text-indent: 0px !important; } -.cms table.ss-gridfield-table tbody td button span.ui-button-text { zoom: 1; } +.cms table.ss-gridfield-table tr th.extra span input { height: 23px; } + +.ss-gridfield-button-filter.ss-ui-button { margin: -1px -5px; background: #e6e6e6 url(../images/filter-icons.png) no-repeat -40px 6px; filter: none; } +.ss-gridfield-button-filter.ss-ui-button.hover-alike:active { background: #2e7ead url(../images/filter-icons.png) no-repeat -15px 7px; filter: none; } +.ss-gridfield-button-filter.ss-ui-button.hover-alike { background: #338dc1 url(../images/filter-icons.png) no-repeat -16px 6px; filter: none; } + +.ss-gridfield-button-reset.ss-ui-button { margin: -1px -5px; background: #e6e6e6 url(../images/filter-icons.png) no-repeat 8px 5px; filter: none; } +.ss-gridfield-button-reset.ss-ui-button.filtered:hover { background: red url(../images/filter-icons.png) no-repeat 8px -17px; filter: none; } +.ss-gridfield-button-reset.ss-ui-button.filtered:active { background: #e60000 url(../images/filter-icons.png) no-repeat 9px -16px; filter: none; } + +.cms table.ss-gridfield-table tr td { border-right: 1px solid #9a9a9a; } +.cms table.ss-gridfield-table tr th { border-right: 1px solid #9a9a9a; } +.cms table.ss-gridfield-table tr th.main { border-top: 1px solid #9a9a9a; border-bottom: none; } +.cms table.ss-gridfield-table tr th.extra { border-top: 1px solid #9a9a9a; padding-right: 12px; } +.cms table.ss-gridfield-table td:first-child, .cms table.ss-gridfield-table th:first-child { border-left: 1px solid #9a9a9a; } + +.cms .ss-gridfield table.ss-gridfield-table tbody td button.gridfield-button-delete { display: block; float: left; } +.cms .ss-gridfield table.ss-gridfield-table tbody td button.gridfield-button-unlink.ui-state-hover { display: block; float: left; } +.cms .ss-gridfield table.ss-gridfield-table tbody td a.edit-link { display: block; float: left; } + +.cms .cms-content .cms-content-fields .aligned_right_label { margin-left: 0; } +.cms .cms-content .cms-content-fields .field.dropdown .middleColumn { max-width: 512px; } + +.pagination-page-number { position: relative; bottom: 10px; right: 10px; } +.pagination-page-number input { width: 45px; padding: 0px; position: relative; bottom: 2px; } + +table.ss-gridfield-table tr.title th h2 { float: left; } + +table.ss-gridfield-table tr.ss-gridfield-item.odd { background: white; } +table.ss-gridfield-table tr.ss-gridfield-item.even { background: #F0F4F7; } diff --git a/admin/css/ie8.css b/admin/css/ie8.css index d1eab2242..84b24fd41 100644 --- a/admin/css/ie8.css +++ b/admin/css/ie8.css @@ -8,3 +8,19 @@ .ss-ui-button.cms-page-add-button.ui-state-hover, .cms .ss-ui-button.cms-page-add-button:hover { background: #80bf40 url("../images/btn-icon-saaa1989272.png") 5px -49px no-repeat; } .ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { background-image: none; } + +.ss-gridfield-button-filter.ss-ui-button { background: #e6e6e6 url(../images/filter-icons.png) no-repeat -40px 6px; filter: none; } +.ss-gridfield-button-filter.ss-ui-button.hover-alike:active { background: #2e7ead url(../images/filter-icons.png) no-repeat -15px 7px; filter: none; } +.ss-gridfield-button-filter.ss-ui-button.hover-alike { background: #338dc1 url(../images/filter-icons.png) no-repeat -16px 6px; filter: none; } + +.ss-gridfield-button-reset.ss-ui-button { background: #e6e6e6 url(../images/filter-icons.png) no-repeat 8px 5px; filter: none; } +.ss-gridfield-button-reset.ss-ui-button.filtered:hover { background: red url(../images/filter-icons.png) no-repeat 8px -17px; filter: none; } +.ss-gridfield-button-reset.ss-ui-button.filtered:active { background: #e60000 url(../images/filter-icons.png) no-repeat 9px -16px; filter: none; } + +.cms table.ss-gridfield-table tr td { border-right: 1px solid #9a9a9a; } +.cms table.ss-gridfield-table tr th { border-right: 1px solid #9a9a9a; } +.cms table.ss-gridfield-table tr th.main { border-top: 1px solid #9a9a9a; border-bottom: none; } +.cms table.ss-gridfield-table tr th.extra { border-top: 1px solid #9a9a9a; } +.cms table.ss-gridfield-table td:first-child, .cms table.ss-gridfield-table th:first-child { border-left: 1px solid #9a9a9a; } + +.cms .cms-content .cms-content-fields .aligned_right_label { margin-left: 0; } diff --git a/admin/css/screen.css b/admin/css/screen.css index 7c64a96de..355f28a08 100644 --- a/admin/css/screen.css +++ b/admin/css/screen.css @@ -31,7 +31,7 @@ article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, /** ---------------------------------------------------- Double tone borders http://daverupert.com/2011/06/two-tone-borders-with-css3/ ----------------------------------------------------- */ /** ----------------------------- Sprite images ----------------------------- */ /** Helper SCSS file for generating sprites for the interface. */ -.btn-icon-sprite, .ui-state-default .btn-icon-accept, .ui-state-default .btn-icon-accept_disabled, .ui-state-default .btn-icon-add, .ui-state-default .btn-icon-add_disabled, .ui-state-default .btn-icon-addpage, .ui-state-default .btn-icon-addpage_disabled, .ui-state-default .btn-icon-arrow-circle-135-left, .ui-state-default .btn-icon-back, .ui-state-default .btn-icon-back_disabled, .ui-state-default .btn-icon-cross-circle, .ui-state-default .btn-icon-cross-circle_disabled, .ui-state-default .btn-icon-decline, .ui-state-default .btn-icon-decline_disabled, .ui-state-default .btn-icon-drive-upload, .ui-state-default .btn-icon-drive-upload_disabled, .ui-state-default .btn-icon-magnifier, .ui-state-default .btn-icon-minus-circle, .ui-state-default .btn-icon-minus-circle_disabled, .ui-state-default .btn-icon-navigation, .ui-state-default .btn-icon-navigation_disabled, .ui-state-default .btn-icon-network-cloud, .ui-state-default .btn-icon-network-cloud_disabled, .ui-state-default .btn-icon-pencil, .ui-state-default .btn-icon-pencil_disabled, .ui-state-default .btn-icon-plug-disconnect-prohibition, .ui-state-default .btn-icon-plug-disconnect-prohibition_disabled, .ui-state-default .btn-icon-preview, .ui-state-default .btn-icon-preview_disabled, .ui-state-default .btn-icon-settings, .ui-state-default .btn-icon-settings_disabled, .ui-state-default .btn-icon-unpublish, .ui-state-default .btn-icon-unpublish_disabled { background: url('../images/btn-icon-s4a0551bc3f.png') no-repeat; } +.btn-icon-sprite, .ui-state-default .btn-icon-accept, .ui-state-default .btn-icon-accept_disabled, .ui-state-default .btn-icon-add, .ui-state-default .btn-icon-add_disabled, .ui-state-default .btn-icon-addpage, .ui-state-default .btn-icon-addpage_disabled, .ui-state-default .btn-icon-arrow-circle-135-left, .ui-state-default .btn-icon-back, .ui-state-default .btn-icon-back_disabled, .ui-state-default .btn-icon-chain--arrow, .ui-state-default .btn-icon-chain--exclamation, .ui-state-default .btn-icon-chain--minus, .ui-state-default .btn-icon-chain--pencil, .ui-state-default .btn-icon-chain--plus, .ui-state-default .btn-icon-chain-small, .ui-state-default .btn-icon-chain-unchain, .ui-state-default .btn-icon-chain, .ui-state-default .btn-icon-cross-circle, .ui-state-default .btn-icon-cross-circle_disabled, .ui-state-default .btn-icon-decline, .ui-state-default .btn-icon-decline_disabled, .ui-state-default .btn-icon-download-csv, .ui-state-default .btn-icon-drive-upload, .ui-state-default .btn-icon-drive-upload_disabled, .ui-state-default .btn-icon-magnifier, .ui-state-default .btn-icon-minus-circle, .ui-state-default .btn-icon-minus-circle_disabled, .ui-state-default .btn-icon-navigation, .ui-state-default .btn-icon-navigation_disabled, .ui-state-default .btn-icon-network-cloud, .ui-state-default .btn-icon-network-cloud_disabled, .ui-state-default .btn-icon-pencil, .ui-state-default .btn-icon-pencil_disabled, .ui-state-default .btn-icon-plug-disconnect-prohibition, .ui-state-default .btn-icon-plug-disconnect-prohibition_disabled, .ui-state-default .btn-icon-preview, .ui-state-default .btn-icon-preview_disabled, .ui-state-default .btn-icon-settings, .ui-state-default .btn-icon-settings_disabled, .ui-state-default .btn-icon-unpublish, .ui-state-default .btn-icon-unpublish_disabled { background: url('../images/btn-icon-sb5d07676ff.png') no-repeat; } .ui-state-default .btn-icon-accept { background-position: 0 0; } .ui-state-default .btn-icon-accept_disabled { background-position: 0 -17px; } @@ -41,30 +41,39 @@ article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, .ui-state-default .btn-icon-addpage_disabled { background-position: 0 -88px; } .ui-state-default .btn-icon-arrow-circle-135-left { background-position: 0 -104px; } .ui-state-default .btn-icon-back { background-position: 0 -120px; } -.ui-state-default .btn-icon-back_disabled { background-position: 0 -136px; } -.ui-state-default .btn-icon-cross-circle { background-position: 0 -152px; } -.ui-state-default .btn-icon-cross-circle_disabled { background-position: 0 -168px; } -.ui-state-default .btn-icon-decline { background-position: 0 -184px; } -.ui-state-default .btn-icon-decline_disabled { background-position: 0 -201px; } -.ui-state-default .btn-icon-drive-upload { background-position: 0 -218px; } -.ui-state-default .btn-icon-drive-upload_disabled { background-position: 0 -234px; } -.ui-state-default .btn-icon-magnifier { background-position: 0 -250px; } -.ui-state-default .btn-icon-minus-circle { background-position: 0 -266px; } -.ui-state-default .btn-icon-minus-circle_disabled { background-position: 0 -282px; } -.ui-state-default .btn-icon-navigation { background-position: 0 -298px; } -.ui-state-default .btn-icon-navigation_disabled { background-position: 0 -314px; } -.ui-state-default .btn-icon-network-cloud { background-position: 0 -330px; } -.ui-state-default .btn-icon-network-cloud_disabled { background-position: 0 -346px; } -.ui-state-default .btn-icon-pencil { background-position: 0 -362px; } -.ui-state-default .btn-icon-pencil_disabled { background-position: 0 -378px; } -.ui-state-default .btn-icon-plug-disconnect-prohibition { background-position: 0 -394px; } -.ui-state-default .btn-icon-plug-disconnect-prohibition_disabled { background-position: 0 -410px; } -.ui-state-default .btn-icon-preview { background-position: 0 -426px; } -.ui-state-default .btn-icon-preview_disabled { background-position: 0 -443px; } -.ui-state-default .btn-icon-settings { background-position: 0 -460px; } -.ui-state-default .btn-icon-settings_disabled { background-position: 0 -476px; } -.ui-state-default .btn-icon-unpublish { background-position: 0 -492px; } -.ui-state-default .btn-icon-unpublish_disabled { background-position: 0 -510px; } +.ui-state-default .btn-icon-back_disabled { background-position: 0 -135px; } +.ui-state-default .btn-icon-chain--arrow { background-position: 0 -150px; } +.ui-state-default .btn-icon-chain--exclamation { background-position: 0 -166px; } +.ui-state-default .btn-icon-chain--minus { background-position: 0 -182px; } +.ui-state-default .btn-icon-chain--pencil { background-position: 0 -198px; } +.ui-state-default .btn-icon-chain--plus { background-position: 0 -214px; } +.ui-state-default .btn-icon-chain-small { background-position: 0 -230px; } +.ui-state-default .btn-icon-chain-unchain { background-position: 0 -246px; } +.ui-state-default .btn-icon-chain { background-position: 0 -262px; } +.ui-state-default .btn-icon-cross-circle { background-position: 0 -278px; } +.ui-state-default .btn-icon-cross-circle_disabled { background-position: 0 -294px; } +.ui-state-default .btn-icon-decline { background-position: 0 -310px; } +.ui-state-default .btn-icon-decline_disabled { background-position: 0 -327px; } +.ui-state-default .btn-icon-download-csv { background-position: 0 -344px; } +.ui-state-default .btn-icon-drive-upload { background-position: 0 -362px; } +.ui-state-default .btn-icon-drive-upload_disabled { background-position: 0 -378px; } +.ui-state-default .btn-icon-magnifier { background-position: 0 -394px; } +.ui-state-default .btn-icon-minus-circle { background-position: 0 -410px; } +.ui-state-default .btn-icon-minus-circle_disabled { background-position: 0 -426px; } +.ui-state-default .btn-icon-navigation { background-position: 0 -442px; } +.ui-state-default .btn-icon-navigation_disabled { background-position: 0 -458px; } +.ui-state-default .btn-icon-network-cloud { background-position: 0 -474px; } +.ui-state-default .btn-icon-network-cloud_disabled { background-position: 0 -490px; } +.ui-state-default .btn-icon-pencil { background-position: 0 -506px; } +.ui-state-default .btn-icon-pencil_disabled { background-position: 0 -522px; } +.ui-state-default .btn-icon-plug-disconnect-prohibition { background-position: 0 -538px; } +.ui-state-default .btn-icon-plug-disconnect-prohibition_disabled { background-position: 0 -554px; } +.ui-state-default .btn-icon-preview { background-position: 0 -570px; } +.ui-state-default .btn-icon-preview_disabled { background-position: 0 -587px; } +.ui-state-default .btn-icon-settings { background-position: 0 -604px; } +.ui-state-default .btn-icon-settings_disabled { background-position: 0 -620px; } +.ui-state-default .btn-icon-unpublish { background-position: 0 -636px; } +.ui-state-default .btn-icon-unpublish_disabled { background-position: 0 -654px; } .icon { text-indent: -9999px; border: none; outline: none; } .icon.icon-24 { width: 24px; height: 24px; background: url('../images/menu-icons/24x24-s546fcae8fd.png'); } @@ -220,7 +229,7 @@ html, body { width: 100%; height: 100%; } body.cms { overflow: hidden; } -.cms a { color: #3ebae0; text-decoration: none; } +.cms a { color: #1556b2; text-decoration: none; } .cms a:hover, .cms a:focus { text-decoration: underline; } .cms body .ui-widget { font-family: Arial, sans-serif; font-size: 12px; } .cms strong { font-weight: bold; } @@ -237,18 +246,13 @@ body.cms { overflow: hidden; } .cms-content-header { padding: 0px 8px 8px; height: 32px; z-index: 60; background-image: url(../images/textures/cms_content_header.png); background-repeat: repeat; } .cms-content-header a { color: #1556b2; } .cms-content-header .backlink { float: left; margin-top: 7px; } +.cms-content-header .backlink span.btn-icon-back { height: 15px; } .cms-content-header h2 { float: left; padding: 8px 8px 0 8px; font-size: 14px; line-height: 24px; font-weight: bold; text-shadow: #bfcad2 1px 1px 0; max-width: 400px; margin: 0; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; o-text-overflow: ellipsis; } .cms-content-header > div { width: 9999em; overflow: hidden; } .cms-content-header .cms-content-header-tabs { position: fixed; right: 40px; } -.cms-content-header .cms-content-header-tabs .ui-tabs-nav li a { font-weight: bold; line-height: 16px; padding: 12px 20px 11px; text-indent: -9999em; } -.cms-content-header .cms-content-header-tabs .ui-tabs-nav li a.content-treeview { background: url(../images/content-header-tabs-sprite.png) no-repeat 2px 0px; } -.cms-content-header .cms-content-header-tabs .ui-tabs-nav li a.content-galleryview { background: url(../images/content-header-tabs-sprite.png) no-repeat -87px 0px; } -.cms-content-header .cms-content-header-tabs .ui-tabs-nav li a.content-listview { background: url(../images/content-header-tabs-sprite.png) no-repeat -38px 0px; } +.cms-content-header .cms-content-header-tabs .ui-tabs-nav li a { font-weight: bold; line-height: 16px; padding: 12px 20px 11px; } .cms-content-header .cms-content-header-tabs .ui-tabs-nav .ui-state-default, .cms-content-header .cms-content-header-tabs .ui-tabs-nav .ui-widget-content .ui-state-default, .cms-content-header .cms-content-header-tabs .ui-tabs-nav .ui-widget-header .ui-state-default { border-top: none; } .cms-content-header .cms-content-header-tabs .ui-tabs-nav .ui-state-active, .cms-content-header .cms-content-header-tabs .ui-tabs-nav .ui-widget-content .ui-state-active, .cms-content-header .cms-content-header-tabs .ui-tabs-nav .ui-widget-header .ui-state-active { border-top: none; } -.cms-content-header .cms-content-header-tabs .ui-tabs-nav .ui-state-active a.content-treeview, .cms-content-header .cms-content-header-tabs .ui-tabs-nav .ui-widget-content .ui-state-active a.content-treeview, .cms-content-header .cms-content-header-tabs .ui-tabs-nav .ui-widget-header .ui-state-active a.content-treeview { background: url(../images/content-header-tabs-sprite.png) no-repeat 2px -40px; } -.cms-content-header .cms-content-header-tabs .ui-tabs-nav .ui-state-active a.content-galleryview, .cms-content-header .cms-content-header-tabs .ui-tabs-nav .ui-widget-content .ui-state-active a.content-galleryview, .cms-content-header .cms-content-header-tabs .ui-tabs-nav .ui-widget-header .ui-state-active a.content-galleryview { background: url(../images/content-header-tabs-sprite.png) no-repeat -87px -40px; } -.cms-content-header .cms-content-header-tabs .ui-tabs-nav .ui-state-active a.content-listview, .cms-content-header .cms-content-header-tabs .ui-tabs-nav .ui-widget-content .ui-state-active a.content-listview, .cms-content-header .cms-content-header-tabs .ui-tabs-nav .ui-widget-header .ui-state-active a.content-listview { background: url(../images/content-header-tabs-sprite.png) no-repeat -38px -40px; } .cms-content-header .cms-content-header-tabs .ui-tabs-nav .ui-corner-all, .cms-content-header .cms-content-header-tabs .ui-tabs-nav .ui-corner-top, .cms-content-header .cms-content-header-tabs .ui-tabs-nav .ui-corner-right, .cms-content-header .cms-content-header-tabs .ui-tabs-nav .ui-corner-tr { border-radius: 0; } .cms-content-header .cms-content-header-tabs .ui-tabs-nav .ui-corner-all, .cms-content-header .cms-content-header-tabs .ui-tabs-nav .ui-corner-top, .cms-content-header .cms-content-header-tabs .ui-tabs-nav .ui-corner-left, .cms-content-header .cms-content-header-tabs .ui-tabs-nav .ui-corner-tl { border-radius: 0; } @@ -262,6 +266,15 @@ body.cms { overflow: hidden; } .ui-tabs .cms-content-header .ui-tabs-nav .ui-state-active, .ui-tabs .cms-content-header .ui-tabs-nav .ui-widget-content .ui-state-active, .ui-tabs .cms-content-header .ui-tabs-nav .ui-widget-header .ui-state-active, .cms-dialog .ui-tabs-nav .ui-state-active, .cms-dialog .ui-tabs-nav .ui-widget-content .ui-state-active, .cms-dialog .ui-tabs-nav .ui-widget-header .ui-state-active { background: #eceff1; border-right-color: #a6a6a6; border-left-color: #a6a6a6; margin-right: -1px; margin-left: -1px; z-index: 2; } .ui-tabs .cms-content-header .ui-tabs-nav .ui-state-active a, .ui-tabs .cms-content-header .ui-tabs-nav .ui-widget-content .ui-state-active a, .ui-tabs .cms-content-header .ui-tabs-nav .ui-widget-header .ui-state-active a, .cms-dialog .ui-tabs-nav .ui-state-active a, .cms-dialog .ui-tabs-nav .ui-widget-content .ui-state-active a, .cms-dialog .ui-tabs-nav .ui-widget-header .ui-state-active a { border-bottom: none; } +.CMSPagesController .cms-content-header-tabs .ui-tabs-nav li a { font-weight: bold; line-height: 16px; padding: 12px 20px 11px; text-indent: -9999em; } +.CMSPagesController .cms-content-header-tabs .ui-tabs-nav li a.content-treeview { background: url(../images/content-header-tabs-sprite.png) no-repeat 2px 0px; } +.CMSPagesController .cms-content-header-tabs .ui-tabs-nav li a.content-galleryview { background: url(../images/content-header-tabs-sprite.png) no-repeat -87px 0px; } +.CMSPagesController .cms-content-header-tabs .ui-tabs-nav li a.content-listview { background: url(../images/content-header-tabs-sprite.png) no-repeat -38px 0px; } +.CMSPagesController .cms-content-header-tabs .ui-tabs-nav .ui-state-active, .CMSPagesController .cms-content-header-tabs .ui-tabs-nav .ui-widget-content .ui-state-active, .CMSPagesController .cms-content-header-tabs .ui-tabs-nav .ui-widget-header .ui-state-active { border-top: none; } +.CMSPagesController .cms-content-header-tabs .ui-tabs-nav .ui-state-active a.content-treeview, .CMSPagesController .cms-content-header-tabs .ui-tabs-nav .ui-widget-content .ui-state-active a.content-treeview, .CMSPagesController .cms-content-header-tabs .ui-tabs-nav .ui-widget-header .ui-state-active a.content-treeview { background: url(../images/content-header-tabs-sprite.png) no-repeat 2px -40px; } +.CMSPagesController .cms-content-header-tabs .ui-tabs-nav .ui-state-active a.content-galleryview, .CMSPagesController .cms-content-header-tabs .ui-tabs-nav .ui-widget-content .ui-state-active a.content-galleryview, .CMSPagesController .cms-content-header-tabs .ui-tabs-nav .ui-widget-header .ui-state-active a.content-galleryview { background: url(../images/content-header-tabs-sprite.png) no-repeat -87px -40px; } +.CMSPagesController .cms-content-header-tabs .ui-tabs-nav .ui-state-active a.content-listview, .CMSPagesController .cms-content-header-tabs .ui-tabs-nav .ui-widget-content .ui-state-active a.content-listview, .CMSPagesController .cms-content-header-tabs .ui-tabs-nav .ui-widget-header .ui-state-active a.content-listview { background: url(../images/content-header-tabs-sprite.png) no-repeat -38px -40px; } + /** ------------------------------------------------------- Loading Interface ------------------------------------------------------- */ .cms-content-loading-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 9998; } @@ -282,7 +295,7 @@ body.cms { overflow: hidden; } .message.notice { background-color: #ffbe66; border-color: #ff9300; } .message.notice a { color: #999; } .message.warning { background-color: #ffbe66; border-color: #ff9300; } -.message.error { background-color: #ffbe66; border-color: #ff9300; } +.message.error, .message.bad, .message.required { background-color: #ffbe66; border-color: #ff9300; } .message.good { background-color: #99cc66; border-color: #669933; } .message p { margin: 0; } @@ -347,7 +360,6 @@ body.cms { overflow: hidden; } .cms-content-batchactions { float: left; position: relative; display: block; margin-left: 8px; } .cms-content-batchactions form > * { display: block; float: left; } .cms-content-batchactions form.cms-batch-actions { float: left; } -.cms-content-batchactions .Actions { display: none; } #Form_BatchActionsForm select { width: 200px; } @@ -388,6 +400,12 @@ form.member-profile-form .ui-corner-all, form.member-profile-form .ui-corner-top .cms .cms-content { border-right: 1px solid rgba(201, 205, 206, 0.8); -moz-box-shadow: 3px 0 4px rgba(0, 0, 0, 0.15); -webkit-box-shadow: 3px 0 4px rgba(0, 0, 0, 0.15); -o-box-shadow: 3px 0 4px rgba(0, 0, 0, 0.15); box-shadow: 3px 0 4px rgba(0, 0, 0, 0.15); -moz-border-radius: 0; -webkit-border-radius: 0; -o-border-radius: 0; -ms-border-radius: 0; -khtml-border-radius: 0; border-radius: 0; } .cms .cms-content-fields { /* always show a y scroll bar as popups like TreeDropdowns can trigger longer pages and the extra scroll bar doesn't fire our sizing bar */ overflow-y: auto; overflow-x: auto; background: none; width: 100%; } +.cms .cms-content-fields .aligned_right_label { margin-left: 184px; padding: 8px 0; } + +/** -------------------------------------------- "Settings" Form -------------------------------------------- */ +#CanViewType .optionset li, #CanEditType .optionset li, #CanCreateTopLevelType .optionset li { float: none; width: auto; } + +#ViewerGroups select, #EditorGroups select, #CreateTopLevelGroups select { width: 512px; } /** -------------------------------------------- Panels -------------------------------------------- */ .cms-panel { overflow: hidden; } @@ -409,7 +427,7 @@ form.member-profile-form .ui-corner-all, form.member-profile-form .ui-corner-top .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-panel-padded { width: 176px; padding: 16px 16px; overflow-x: hidden; overflow-y: auto; } +.cms .cms-panel-padded { width: 176px; padding: 16px 16px; overflow-x: hidden; overflow-y: auto; } /** ------------------------------------------------------------------ * Dialog @@ -473,6 +491,12 @@ form.small .cms-file-info-data .field { padding-bottom: 0; } form.small .cms-file-info-data .field label { width: 112px; } form.small .cms-file-info-data .field .middleColumn { margin-left: 120px; } +/** -------------------------------------------- Users Members Admin -------------------------------------------- */ +.members_grid span button#action_gridfield_relationfind { display: none; } +.members_grid p button#action_export { margin-top: 16px; } +.members_grid p button#action_export span.btn-icon-download-csv { height: 17px; } +.members_grid p button#action_export span.ui-button-text { padding-left: 27px; } + /** This file defines the jstree base styling (see http://jstree.com), as well as any customizations (see bottom of file). The styles are usually added through jstree.js on DOM load, but we need it earlier in order to correctly display the uninitialized tree. */ .cms .jstree ul, .TreeDropdownField .treedropdownfield-panel .jstree ul { display: block; margin: 0; padding: 0; background: none; list-style-type: none; } .cms .jstree li, .TreeDropdownField .treedropdownfield-panel .jstree li { display: block; margin: 0; padding: 0; list-style-type: none; display: block; min-height: 18px; line-height: 18px; white-space: nowrap; margin-left: 18px; min-width: 18px; } @@ -536,6 +560,8 @@ form.small .cms-file-info-data .field .middleColumn { margin-left: 120px; } .cms .jstree-apple.jstree-focused, .TreeDropdownField .treedropdownfield-panel .jstree-apple.jstree-focused { background: none; } .cms .jstree-apple.jstree-focused .jstree-apple > ul, .TreeDropdownField .treedropdownfield-panel .jstree-apple.jstree-focused .jstree-apple > ul { background: none; } .cms .jstree li, .TreeDropdownField .treedropdownfield-panel .jstree li { line-height: 25px; } +.cms a > .jstree-icon, .TreeDropdownField .treedropdownfield-panel a > .jstree-icon { display: none; } +.cms .draggable a > .jstree-icon, .TreeDropdownField .treedropdownfield-panel .draggable a > .jstree-icon { display: block; } .jstree-apple li, .jstree-apple .jstree-apple ins { background: none; } .jstree-apple .jstree-unchecked > a > .jstree-checkbox { margin-right: 3px; } @@ -558,12 +584,10 @@ form.small .cms-file-info-data .field .middleColumn { margin-left: 120px; } .tree-holder.jstree-apple .jstree-hovered, .cms-tree.jstree-apple .jstree-hovered { text-shadow: none; text-decoration: none; } .tree-holder.jstree-apple li, .cms-tree.jstree-apple li { padding: 0px; clear: left; } .tree-holder.jstree-apple ins, .cms-tree.jstree-apple ins { background-color: transparent; background-image: url(../images/sitetree_ss_default_icons.png); } -.tree-holder.jstree-apple li.jstree-checked a, .tree-holder.jstree-apple li.jstree-checked a:link, .cms-tree.jstree-apple li.jstree-checked a, .cms-tree.jstree-apple li.jstree-checked a:link { background-color: #efe999; } +.tree-holder.jstree-apple li.jstree-checked > a, .tree-holder.jstree-apple li.jstree-checked > a:link, .cms-tree.jstree-apple li.jstree-checked > a, .cms-tree.jstree-apple li.jstree-checked > a:link { background-color: #efe999; } .tree-holder.jstree-apple .jstree-closed > ins, .cms-tree.jstree-apple .jstree-closed > ins { background-position: 0 0; } .tree-holder.jstree-apple .jstree-open > ins, .cms-tree.jstree-apple .jstree-open > ins { background-position: -20px 0; } -.jstree-apple #record-0.jstree-open > ins { display: none; } - a .jstree-pageicon { display: block; float: left; width: 16px; height: 16px; margin-right: 4px; background-color: transparent; background-image: url(../images/sitetree_ss_pageclass_icons_default.png); background-repeat: no-repeat; } li.class-HomePage > a .jstree-pageicon { background-position: 0 -48px; } @@ -575,6 +599,8 @@ li.class-VirtualPage > a .jstree-pageicon { background-position: 0 -32px; } li.class-ErrorPage > a .jstree-pageicon { background-position: 0 -112px; } .cms-tree { visibility: hidden; } +.cms-tree.multiple li > a > .jstree-icon { display: none; } +.cms-tree.multiple li#record-0 > a .jstree-checkbox { display: none; } /** Styles for the left hand side menu and header for the admin panels. Take into consideration CSS selector performance. @package sapphire @subpackage admin */ .cms-logo-header { background-color: #00111d; position: relative; padding: 16px 8px 0 4px; line-height: 24px; background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #00111d), color-stop(50%, #003050), color-stop(100%, #00111d)); background-image: -webkit-linear-gradient(#00111d, #003050, #00111d); background-image: -moz-linear-gradient(#00111d, #003050, #00111d); background-image: -o-linear-gradient(#00111d, #003050, #00111d); background-image: -ms-linear-gradient(#00111d, #003050, #00111d); background-image: linear-gradient(#00111d, #003050, #00111d); } diff --git a/admin/images/btn-icon-s4a0551bc3f.png b/admin/images/btn-icon-s4a0551bc3f.png deleted file mode 100644 index 58982167c..000000000 Binary files a/admin/images/btn-icon-s4a0551bc3f.png and /dev/null differ diff --git a/admin/images/btn-icon-sb5d07676ff.png b/admin/images/btn-icon-sb5d07676ff.png new file mode 100644 index 000000000..6e9b49a31 Binary files /dev/null and b/admin/images/btn-icon-sb5d07676ff.png differ diff --git a/admin/images/btn-icon/back.png b/admin/images/btn-icon/back.png index 6be583d2f..019b175ca 100644 Binary files a/admin/images/btn-icon/back.png and b/admin/images/btn-icon/back.png differ diff --git a/admin/images/btn-icon/back_disabled.png b/admin/images/btn-icon/back_disabled.png index 55c27974e..b44481da4 100644 Binary files a/admin/images/btn-icon/back_disabled.png and b/admin/images/btn-icon/back_disabled.png differ diff --git a/admin/images/btn-icon/chain--arrow.png b/admin/images/btn-icon/chain--arrow.png new file mode 100755 index 000000000..4c8515cb9 Binary files /dev/null and b/admin/images/btn-icon/chain--arrow.png differ diff --git a/admin/images/btn-icon/chain--exclamation.png b/admin/images/btn-icon/chain--exclamation.png new file mode 100755 index 000000000..330c408cf Binary files /dev/null and b/admin/images/btn-icon/chain--exclamation.png differ diff --git a/admin/images/btn-icon/chain--minus.png b/admin/images/btn-icon/chain--minus.png new file mode 100755 index 000000000..bf65ff1ab Binary files /dev/null and b/admin/images/btn-icon/chain--minus.png differ diff --git a/admin/images/btn-icon/chain--pencil.png b/admin/images/btn-icon/chain--pencil.png new file mode 100755 index 000000000..d10bbb153 Binary files /dev/null and b/admin/images/btn-icon/chain--pencil.png differ diff --git a/admin/images/btn-icon/chain--plus.png b/admin/images/btn-icon/chain--plus.png new file mode 100755 index 000000000..a517282f0 Binary files /dev/null and b/admin/images/btn-icon/chain--plus.png differ diff --git a/admin/images/btn-icon/chain-small.png b/admin/images/btn-icon/chain-small.png new file mode 100755 index 000000000..3f399ebd8 Binary files /dev/null and b/admin/images/btn-icon/chain-small.png differ diff --git a/admin/images/btn-icon/chain-unchain.png b/admin/images/btn-icon/chain-unchain.png new file mode 100755 index 000000000..c56c8d8f5 Binary files /dev/null and b/admin/images/btn-icon/chain-unchain.png differ diff --git a/admin/images/btn-icon/chain.png b/admin/images/btn-icon/chain.png new file mode 100755 index 000000000..ce799797f Binary files /dev/null and b/admin/images/btn-icon/chain.png differ diff --git a/admin/images/btn-icon/download-csv.png b/admin/images/btn-icon/download-csv.png new file mode 100644 index 000000000..b0384f4bd Binary files /dev/null and b/admin/images/btn-icon/download-csv.png differ diff --git a/admin/images/filter-icons.png b/admin/images/filter-icons.png new file mode 100644 index 000000000..c5802cc39 Binary files /dev/null and b/admin/images/filter-icons.png differ diff --git a/admin/javascript/LeftAndMain.BatchActions.js b/admin/javascript/LeftAndMain.BatchActions.js index c5a2395a6..625c619da 100644 --- a/admin/javascript/LeftAndMain.BatchActions.js +++ b/admin/javascript/LeftAndMain.BatchActions.js @@ -45,12 +45,17 @@ }); $('.cms-tree-view-modes :input[name=view-mode]').bind('click', function(e) { - if($(e.target).val() == 'multiselect') { + var val = $(e.target).val(), dropdown = self.find(':input[name=Action]'); + if(val == 'multiselect') { tree.addClass('multiple'); self.serializeFromTree(); } else { tree.removeClass('multiple'); } + + // Batch actions only make sense when multiselect is enabled + if(val == 'multiselect') dropdown.removeAttr('disabled').change(); + else dropdown.attr('disabled', 'disabled').change(); }); this._super(); @@ -173,7 +178,7 @@ * {Array} ids */ setIDs: function(ids) { - if(ids) this.find(':input[name=csvIDs]').val(ids.join(',')); + this.find(':input[name=csvIDs]').val(ids ? ids.join(',') : null); }, /** @@ -193,8 +198,7 @@ * (Event) e */ onsubmit: function(e) { - var ids = this.getIDs(); - var tree = this.getTree(); + var self = this, ids = this.getIDs(), tree = this.getTree(); // if no nodes are selected, return with an error if(!ids || !ids.length) { @@ -222,56 +226,42 @@ data: this.serializeArray(), complete: function(xmlhttp, status) { button.removeClass('loading'); + + // Deselect all nodes + tree.jstree('uncheck_all'); + self.setIDs([]); + + // Reset action + self.find(':input[name=Action]').val('').change(); // status message - var msg = (xmlhttp.getResponseHeader('X-Status')) ? xmlhttp.getResponseHeader('X-Status') : xmlhttp.statusText; - statusMessage(msg, (status == 'success') ? 'good' : 'bad'); + var msg = xmlhttp.getResponseHeader('X-Status'); + if(msg) statusMessage(msg, (status == 'success') ? 'good' : 'bad'); }, success: function(data, status) { - var id; + var id, node; - // TODO This should use a more common serialization in a new tree library if(data.modified) { + var modifiedNodes = []; for(id in data.modified) { - tree.jstree('set_title', tree.getNodeByID(id), data.modified[id]['TreeTitle']); + node = tree.getNodeByID(id); + tree.jstree('set_text', node, data.modified[id]['TreeTitle']); + modifiedNodes.push(node); } + $(modifiedNodes).effect('highlight'); } if(data.deleted) { for(id in data.deleted) { - var node = tree.getNodeByID(id); - // TODO Remove node - // if(node && node.parentTreeNode) node.parentTreeNode.removeTreeNode(node); + node = tree.getNodeByID(id); + if(node.length) tree.jstree('delete_node', node); } } if(data.error) { for(id in data.error) { - var node = tree.getNodeByID(id); + node = tree.getNodeByID(id); $(node).addClass('failed'); } } - - // Deselect all nodes - tree.find('li').removeClass('selected'); - - // TODO Fix up to work properly with jstree - unclear if state setting is still required in new design - // // Check if current page still exists, and refresh it. - // // Otherwise remove the current form - // var selectedNode = tree.jstree('get_selected'); - // if(selectedNode) { - // var selectedNodeId = selectedNode.getID(); - // if(data.modified[selectedNodeId]) { - // // only if the current page was modified - // tree.jstree('select_node', selectedNode); - // } else if(data.deleted[selectedNodeId]) { - // jQuery('.cms-edit-form').entwine('ss').removeForm(); - // } - // } else { - // jQuery('.cms-edit-form').entwine('ss').removeForm(); - // } - - // close panel - // TODO Coupling with tabs - // jQuery('#TreeActions').tabs('select', -1); }, dataType: 'json' }); @@ -301,11 +291,16 @@ onchange: function(e) { var form = $(e.target.form), btn = form.find(':submit'); if($(e.target).val() == -1) { - btn.attr('disabled', 'disabled'); + btn.attr('disabled', 'disabled').button('refresh'); } else { - btn.removeAttr('disabled'); - form.entwine('ss').refreshSelected(); + btn.removeAttr('disabled').button('refresh'); + // form.submit(); } + + // TODO Should work by triggering change() along, but doesn't - entwine event bubbling? + this.trigger("liszt:updated"); + + this._super(e); } }); diff --git a/admin/javascript/LeftAndMain.Content.js b/admin/javascript/LeftAndMain.Content.js index 32a9cb426..69c5b64ed 100644 --- a/admin/javascript/LeftAndMain.Content.js +++ b/admin/javascript/LeftAndMain.Content.js @@ -158,17 +158,23 @@ if(loadResponse !== false) { self.submitForm_responseHandler(form, xmlhttp.responseText, status, xmlhttp, formData); } + + // Simulates a redirect on an ajax response - just exchange the URL without re-requesting it + if(window.History.enabled) { + var url = xmlhttp.getResponseHeader('X-ControllerURL'); + if(url) window.history.replaceState({}, '', url); + } // Re-init tabs (in case the form tag itself is a tabset) if(self.hasClass('ss-tabset')) self.removeClass('ss-tabset').addClass('ss-tabset'); - // Redraw the layout - jQuery('.cms-container').entwine('ss').redraw(); - // re-select previously saved tabs $.each(selectedTabs, function(i, selectedTab) { form.find('#' + selectedTab.id).tabs('select', selectedTab.selected); }); + + // Redraw the layout + $('.cms-container').redraw(); }, dataType: 'html' }, ajaxOptions)); @@ -296,21 +302,4 @@ } }); - /** - * Loads the link's 'href' attribute into a panel via ajax, - * as opposed to triggering a full page reload. - * Little helper to avoid repetition, and make it easy to - * "opt in" to panel loading, while by default links still exhibit their default behaviour. - * Same goes for breadcrumbs in the CMS. - */ - $('.cms-content .cms-panel-link, .cms-content a.crumb').entwine({ - onclick: function(e) { - var href = this.attr('href'), url = href ? href : this.data('href'), - data = (this.data('targetPanel')) ? {selector: this.data('targetPanel')} : null; - - $('.cms-container').entwine('ss').loadPanel(url, null, data); - e.preventDefault(); - } - }); - })(jQuery); \ No newline at end of file diff --git a/admin/javascript/LeftAndMain.EditForm.js b/admin/javascript/LeftAndMain.EditForm.js index 2649c1d2e..d0bbd08b6 100644 --- a/admin/javascript/LeftAndMain.EditForm.js +++ b/admin/javascript/LeftAndMain.EditForm.js @@ -2,6 +2,14 @@ * File: LeftAndMain.EditForm.js */ (function($) { + + // Can't bind this through jQuery + window.onbeforeunload = function(e) { + var form = $('.cms-edit-form'); + form.trigger('beforesave'); + if(form.is('.changed')) return ss.i18n._t('LeftAndMain.CONFIRMUNSAVEDSHORT'); + }; + $.entwine('ss', function($){ /** @@ -52,12 +60,6 @@ this._setupChangeTracker(); - // Can't bind this through jQuery - window.onbeforeunload = function(e) { - self.trigger('beforesave'); - if(self.is('.changed')) return ss.i18n._t('LeftAndMain.CONFIRMUNSAVEDSHORT'); - }; - // Catch navigation events before they reach handleStateChange(), // in order to avoid changing the menu state if the action is cancelled by the user // $('.cms-menu') @@ -179,6 +181,7 @@ */ onclick: function(e) { $('.cms-content').submitForm(this.parents('form'), this); + e.preventDefault(); return false; } }); diff --git a/admin/javascript/LeftAndMain.Tree.js b/admin/javascript/LeftAndMain.Tree.js index 215f76353..60079684b 100644 --- a/admin/javascript/LeftAndMain.Tree.js +++ b/admin/javascript/LeftAndMain.Tree.js @@ -12,6 +12,9 @@ onmatch: function() { this._super(); + + // Don't reapply (expensive) tree behaviour if already present + if(!$.isNaN(this.data('jstree_instance_id'))) return; var hints = this.attr('data-hints'); if(hints) this.setHints($.parseJSON(hints)); @@ -90,6 +93,9 @@ "drop_target" : false, "drag_target" : false }, + 'checkbox': { + 'two_state': true + }, 'themes': { 'theme': 'apple', 'url': 'sapphire/thirdparty/jstree/themes/apple/style.css' @@ -183,7 +189,7 @@ * DOMElement */ getNodeByID: function(id) { - return this.jstree('get_node', this.find('*[data-id='+id+']')); + return this.find('*[data-id='+id+']'); }, /** @@ -201,7 +207,7 @@ return false; }; - var handledform = $(e.target).children('.cms-edit-form:first')[0]; + var handledform = $(e.target).is('.cms-edit-form') ? $(e.target)[0] : $(e.target).find('.cms-edit-form')[0]; var id = $(handledform.ID).val(); // check if a form with a valid ID exists @@ -254,75 +260,77 @@ } } + }, + onunmatch: function() { + } }); - }); - - $('.cms-tree.multiple').entwine({ - onmatch: function() { - this._super(); + + $('.cms-tree.multiple').entwine({ + onmatch: function() { + this._super(); + this.jstree('show_checkboxes'); + }, + onunmatch: function() { + this._super(); + this.jstree('uncheck_all'); + this.jstree('hide_checkboxes'); + }, + /** + * Function: getSelectedIDs + * + * Returns: + * (Array) + */ + getSelectedIDs: function() { + return $.map($(this).jstree('get_checked'), function(el, i) {return $(el).data('id');}); + } + }); + + $('.cms-tree li').entwine({ - this.jstree('show_checkboxes'); - }, - onunmatch: function() { - this._super(); + /** + * Function: setEnabled + * + * Parameters: + * (bool) + */ + setEnabled: function(bool) { + this.toggleClass('disabled', !(bool)); + }, - this.jstree('uncheck_all'); - this.jstree('hide_checkboxes'); - }, - /** - * Function: getSelectedIDs - * - * Returns: - * (Array) - */ - getSelectedIDs: function() { - return $.map($(this).jstree('get_checked'), function(el, i) {return $(el).data('id');}); - } - }); - - $('.cms-tree li').entwine({ + /** + * Function: getClassname + * + * Returns PHP class for this element. Useful to check business rules like valid drag'n'drop targets. + */ + getClassname: function() { + var matches = this.attr('class').match(/class-([^\s]*)/i); + return matches ? matches[1] : ''; + }, + + /** + * Function: getID + * + * Returns: + * (Number) + */ + getID: function() { + return this.data('id'); + } + }); - /** - * Function: setEnabled - * - * Parameters: - * (bool) - */ - setEnabled: function(bool) { - this.toggleClass('disabled', !(bool)); - }, - - /** - * Function: getClassname - * - * Returns PHP class for this element. Useful to check business rules like valid drag'n'drop targets. - */ - getClassname: function() { - var matches = this.attr('class').match(/class-([^\s]*)/i); - return matches ? matches[1] : ''; - }, - - /** - * Function: getID - * - * Returns: - * (Number) - */ - getID: function() { - return this.data('id'); - } + $('.cms-tree-view-modes input.view-mode').entwine({ + onmatch: function() { + // set active by default + this.trigger('click'); + this._super(); + }, + onclick: function(e) { + $('.cms-tree') + .toggleClass('draggable', $(e.target).val() == 'draggable') + .toggleClass('multiple', $(e.target).val() == 'multiselect'); + } + }); }); - - $('.cms-tree-view-modes input.view-mode').entwine({ - onmatch: function() { - // set active by default - this.trigger('click'); - this._super(); - }, - onclick: function(e) { - $('.cms-tree').toggleClass('draggable', $(e.target).val() == 'draggable'); - } - }); - }(jQuery)); \ No newline at end of file diff --git a/admin/javascript/LeftAndMain.js b/admin/javascript/LeftAndMain.js index 74e8a05a3..a4a0f1c52 100644 --- a/admin/javascript/LeftAndMain.js +++ b/admin/javascript/LeftAndMain.js @@ -95,7 +95,7 @@ jQuery.noConflict(); redraw: function() { // Move from inner to outer layouts. Some of the elements might not exist. // Not all edit forms are layouted, so qualify by their data value. - + this.find('.cms-content-fields[data-layout-type]').redraw(); this.find('.cms-edit-form[data-layout-type]').redraw(); // Only redraw preview if its visible @@ -250,6 +250,12 @@ jQuery.noConflict(); } }); + $('.cms-content-fields').entwine({ + redraw: function() { + this.layout(); + } + }); + /** * Make all buttons "hoverable" with jQuery theming. * Also sets the clicked button on a form submission, making it available through @@ -271,6 +277,45 @@ jQuery.noConflict(); } }); + /** + * Loads the link's 'href' attribute into a panel via ajax, + * as opposed to triggering a full page reload. + * Little helper to avoid repetition, and make it easy to + * "opt in" to panel loading, while by default links still exhibit their default behaviour. + * Same goes for breadcrumbs in the CMS. + */ + $('.cms .cms-panel-link, .cms a.crumb').entwine({ + onclick: function(e) { + var href = this.attr('href'), url = href ? href : this.data('href'), + data = (this.data('targetPanel')) ? {selector: this.data('targetPanel')} : null; + + $('.cms-container').loadPanel(url, null, data); + e.preventDefault(); + } + }); + + /** + * Does an ajax loads of the link's 'href' attribute via ajax and displays any FormResponse messages from the CMS. + * Little helper to avoid repetition, and make it easy to trigger actions via a link, + * without reloading the page, changing the URL, or loading in any new panel content. + */ + $('.cms .cms-link-ajax').entwine({ + onclick: function(e) { + var href = this.attr('href'), url = href ? href : this.data('href'); + + jQuery.ajax({ + url: url, + // Ensure that form view is loaded (rather than whole "Content" template) + complete: function(xmlhttp, status) { + var msg = (xmlhttp.getResponseHeader('X-Status')) ? xmlhttp.getResponseHeader('X-Status') : xmlhttp.responseText; + if (typeof msg != "undefined" && msg != null) eval(msg); + }, + dataType: 'html' + }); + e.preventDefault(); + } + }); + /** * Trigger dialogs with iframe based on the links href attribute (see ssui-core.js). */ @@ -363,10 +408,15 @@ jQuery.noConflict(); * we can fix the height cropping. */ - $('.cms .field.dropdown, .cms .field.checkboxset').entwine({ + $('.cms .field.dropdown select, .cms .field select[multiple]').entwine({ onmatch: function() { - $(this).find("select:not(.no-chzn)").data('placeholder', ' ').chosen(); - $(this).addClass("has-chzn"); + if(this.is('.no-chzn')) return; + + // Explicitly disable default placeholder if no custom one is defined + if(!this.data('placeholder')) this.data('placeholder', ' '); + + // Apply chosen + this.chosen().addClass("has-chzn"); this._super(); } @@ -410,7 +460,10 @@ jQuery.noConflict(); }); var url = this.attr('action'); if(nonEmptyInputs.length) url += '?' + nonEmptyInputs.serialize(); - this.closest('.cms-container').entwine('ss').loadPanel(url); + + var container = this.closest('.cms-container'); + container.find('.cms-edit-form').tabs('select',0); //always switch to the first tab (list view) when searching + container .entwine('ss').loadPanel(url); return false; }, @@ -423,6 +476,23 @@ jQuery.noConflict(); } }); + + /** + * Simple toggle link, which points to a DOm element by its ID selector + * in the href attribute (which doubles as an anchor link to that element). + */ + $('.cms .cms-help-toggle').entwine({ + onmatch: function() { + this._super(); + + $(this.attr('href')).hide(); + }, + onclick: function(e) { + $(this.attr('href')).toggle(); + e.preventDefault(); + } + }); + }(jQuery)); var statusMessage = function(text, type) { diff --git a/admin/javascript/MemberTableField.js b/admin/javascript/MemberTableField.js deleted file mode 100644 index 1d3516353..000000000 --- a/admin/javascript/MemberTableField.js +++ /dev/null @@ -1,347 +0,0 @@ -/** - * File: MemberTableField.js - */ -(function($) { - $.entwine('ss', function($){ - /** - * Class: #Permissions .checkbox[value=ADMIN] - * - * Automatically check and disable all checkboxes if ADMIN permissions are selected. - * As they're disabled, any changes won't be submitted (which is intended behaviour), - * checking all boxes is purely presentational. - */ - $('#Permissions .checkbox[value=ADMIN]').entwine({ - onmatch: function() { - this.toggleCheckboxes(); - - this._super(); - }, - /** - * Function: onclick - */ - onclick: function(e) { - this.toggleCheckboxes(); - }, - /** - * Function: toggleCheckboxes - */ - toggleCheckboxes: function() { - var self = this, checkboxes = this.parents('.field:eq(0)').find('.checkbox').not(this); - - if(this.is(':checked')) { - checkboxes.each(function() { - $(this).data('SecurityAdmin.oldChecked', $(this).attr('checked')); - $(this).data('SecurityAdmin.oldDisabled', $(this).attr('disabled')); - $(this).attr('disabled', 'disabled'); - $(this).attr('checked', 'checked'); - }); - } else { - checkboxes.each(function() { - $(this).attr('checked', $(this).data('SecurityAdmin.oldChecked')); - $(this).attr('disabled', $(this).data('SecurityAdmin.oldDisabled')); - }); - } - } - }); - }); -}(jQuery)); - -/** - * Modified 2006-10-05, Ingo Schommer - * This is more or less a copy of Member.js, with additions and changes - * to match the switch from Member.php to MemberTableField.php all over the UI. - * Eventually it will replace Member.js (please remove this message then). - */ - -// no confirm message for removal from a group -if(typeof(ComplexTableField) != 'undefined') { - ComplexTableField.prototype.deleteConfirmMessage = null; -} - -/** - * Class: AjaxMemberLookup - * - * Auto-lookup on ajax fields - */ -AjaxMemberLookup = { - initialise : function() { - var div = document.createElement('div'); - div.id = this.id + '_ac'; - div.className = 'autocomplete'; - this.parentNode.appendChild(div); - if(this.id) { - new Ajax.Autocompleter(this.id, div.id, 'admin/security/autocomplete/' + this.name, { - afterUpdateElement : this.afterAutocomplete.bind(this) - }); - - } - }, - afterAutocomplete : function(field, selectedItem) { - var items = jQuery(selectedItem).data('fields'), form = jQuery(selectedItem).parents('form:first'); - for(name in items) { - jQuery(form).find('input[name='+name+']').val(items[name]); - } - } -} - -/** - * Class: MemberTableField - */ -MemberTableField = Class.create(); -MemberTableField.applyTo('.cms-edit-form div.MemberTableField'); -MemberTableField.prototype = { - - initialize: function() { - Behaviour.register({ - '.cms-edit-form div.MemberFilter input' : { - onkeypress : this.prepareSearch.bind(this) - }, - - '.cms-edit-form div.MemberTableField table.data tr.addtogrouprow input' : { - onkeypress : this.prepareAddToGroup.bind(this) - }, - - '.cms-edit-form div.MemberTableField table.data tr.addtogrouprow #Form_AddRecordForm_action_addtogroup' : { - onclick : this.prepareAddToGroup.bind(this) - }, - - '.cms-edit-form div.MemberTableField table.data tr.addtogrouprow td.actions input' : { - initialise: function() { - data = this.parentNode.parentNode.getElementsByTagName('input'); - var i,item,error = []; - for(i=0;item=data[i];i++) { - item.originalSerialized = Form.Element.serialize(item); - } - }, - onclick : this.addToGroup.bind(this) - }, - - //'.cms-edit-form div.MemberTableField input' : AjaxMemberLookup, - - '.cms-edit-form' : { - changeDetection_fieldsToIgnore : { - 'ctf[start]' : true, - 'ctf[ID]' : true, - 'MemberOrderByField' : true, - 'MemberOrderByOrder' : true, - 'MemberGroup' : true, - 'MemberFilterButton' : true, - 'MemberFieldName' : true, - 'MemberDontShowPassword' : true, - 'MemberSearch' : true - } - } - }); - }, - - // prevent submission of wrong form-button (MemberFilterButton) - prepareAddToGroup: function(e) { - // IE6 doesnt send an event-object with onkeypress - var event = (e) ? e : window.event; - var keyCode = (event.keyCode) ? event.keyCode : event.which; - if(keyCode == Event.KEY_RETURN) { - var el = Event.element(event); - this.addToGroup(event); - Event.stop(event); - return false; - } - }, - - // prevent submission of wrong form-button (MemberFilterButton) - prepareSearch: function(e) { - // IE6 doesnt send an event-object with onkeypress - var event = (e) ? e : window.event; - var keyCode = (event.keyCode) ? event.keyCode : event.which; - - if(keyCode == Event.KEY_RETURN) { - var el = Event.element(event); - $('MemberFilterButton').onclick(event); - Event.stop(event); - return false; - } - }, - - addToGroup: function(e) { - // only submit parts of the form - var data = this.parentNode.parentNode.getElementsByTagName('input'); - var i,item,error = []; - var form = Event.findElement(e,"form"); - - for(i=0;item=data[i];i++) { - if(item.name == 'Email' && !item.value) error[error.length] = "Email"; - if(item.name == 'Password' && !item.value) error[error.length] = "Password"; - } - - if(error.length > 0) { - alert('Please enter a ' + error.join(' and a ') + ' to add a member.'); - } else { - updateURL = ""; - updateURL += Event.findElement(e,"form").action; - // we can't set "fieldName" as a HiddenField because there might be multiple ComplexTableFields in a single EditForm-container - updateURL += "?fieldName="+$('MemberFieldName').value; - updateURL += "&action_callfieldmethod&methodName=addtogroup"; - - ajaxSubmitFieldSet(updateURL, data); - } - - return false; - } - - /* - initialise : function() { - this.headerMap = []; - - var i, item, headers = this.getElementsByTagName('thead')[0].getElementsByTagName('tr')[0].getElementsByTagName('td'); - for(i=0;item=headers[i];i++) { - this.headerMap[i] = item.className; - } - }, - - setRecordDetails : function(id, details, groupID) { - var row = document.getElementById('member-' + id); - if(row) { - var i, item, cells = row.getElementsByTagName('td'); - for(i=0;item=cells[i];i++) { - if(details[this.headerMap[i]]) { - item.innerHTML = details[this.headerMap[i]]; - } - } - } else { - this.createRecord(id, details, groupID); - } - }, - createRecord : function (id, details, groupId) { - var row = document.createElement('tr'); - row.id = 'member-' + id; - var i, cell, cellField; - for(i=0;cellField=this.headerMap[i];i++) { - cell = document.createElement('td') - if(details[cellField]) { - cell.innerHTML = details[cellField]; - } - row.appendChild(cell); - } - - // Add the delete icon - if(typeof groupId == 'undefined') - var groupId = $('Form_EditForm').elements.ID.value; - cell = document.createElement('td') - cell.innerHTML = 'delete'; - cell.getElementsByTagName('0'); - row.appendChild(cell); - - var tbody = this.getElementsByTagName('tbody')[0]; - var addRow = document.getElementsByClassName('addrow',tbody)[0]; - if(addRow) tbody.insertBefore(row, addRow); - else tbody.appendChild(row); - Behaviour.apply(row, true); - }, - clearAddForm : function() { - var tbody = this.getElementsByTagName('tbody')[0]; - var addRow = document.getElementsByClassName('addrow',tbody)[0]; - if(addRow) { - var i,field,fields = addRow.getElementsByTagName('input'); - for(i=0;field=fields[i];i++) { - if(field.type != 'hidden' && field.type != 'submit') field.value = ''; - } - } - }, - removeMember : function(memberID) { - var record; - if(record = $('member-' + memberID)) { - record.parentNode.removeChild(record); - } - } - */ -} - -/** - * Class: MemberFilterButton - */ -MemberFilterButton = Class.create(); -MemberFilterButton.applyTo('#MemberFilterButton'); -MemberFilterButton.prototype = { - initialize: function() { - this.inputFields = new Array(); - - var childNodes = this.parentNode.parentNode.getElementsByTagName('input'); - - for( var index = 0; index < childNodes.length; index++ ) { - if( childNodes[index].tagName ) { - childNodes[index].resetChanged = function() { return false; } - childNodes[index].isChanged = function() { return false; } - this.inputFields.push( childNodes[index] ); - } - } - - childNodes = this.parentNode.getElementsByTagName('select'); - - for( var index = 0; index < childNodes.length; index++ ) { - if( childNodes[index].tagName ) { - childNodes[index].resetChanged = function() { return false; } - childNodes[index].field_changed = function() { return false; } - this.inputFields.push( childNodes[index] ); - } - } - }, - - isChanged: function() { - return false; - }, - - onclick: function(e) { - if(!$('ctf-ID') || !$('MemberFieldName')) { - return false; - } - - try { - var form = Event.findElement(e,"form"); - var fieldName = $('MemberFieldName').value; - var fieldID = form.id + '_' + fieldName; - - var updateURL = form.action + '/field/' + fieldName + '?ajax=1'; - for( var index = 0; index < this.inputFields.length; index++ ) { - if( this.inputFields[index].tagName ) { - updateURL += '&' + this.inputFields[index].name + '=' + encodeURIComponent( this.inputFields[index].value ); - } - } - - jQuery($(fieldID)).get(updateURL, null, function() {Behaviour.apply($(fieldID), true);}); - } catch(er) { - errorMessage('Error searching'); - } - - return false; - } -} - -// has to be external from initialize() because otherwise request will double on each reload - WTF -Behaviour.register({ - '.cms-edit-form div.MemberTableField table.data input.text' : AjaxMemberLookup -}); - -/** - * Post the given fields to the given url - */ -function ajaxSubmitFieldSet(href, fieldSet, extraData) { - // Build data - var i,field,data = "ajax=1"; - for(i=0;field=fieldSet[i];i++) { - data += '&' + Form.Element.serialize(field); - } - if(extraData){ - data += '&'+extraData; - } - // Send request - jQuery.ajax({ - 'url': href, - 'method' : 'post', - 'data' : data, - 'success' : function(response) { - eval(response); - }, - 'error' : function(response) { - alert(response.responseText); - } - }); -} \ No newline at end of file diff --git a/admin/javascript/MemberTableField_popup.js b/admin/javascript/MemberTableField_popup.js deleted file mode 100644 index 1436bbaa5..000000000 --- a/admin/javascript/MemberTableField_popup.js +++ /dev/null @@ -1,21 +0,0 @@ -/** - * File: MemberTableField_popup.js - */ - -/** - * Class: MemberTableFieldPopupForm - */ -MemberTableFieldPopupForm = Class.extend("ComplexTableFieldPopupForm"); -MemberTableFieldPopupForm.prototype = { - initialize: function() { - this.ComplexTableFieldPopupForm.initialize(); - - Behaviour.register('MemberTableFieldPopupForm',{ - "div.MemberTableField_Popup .Actions input.action": { - onclick: this.submitForm.bind(this) - } - }); - } -} - -MemberTableFieldPopupForm.applyTo('div.MemberTableField_Popup .Actions'); \ No newline at end of file diff --git a/admin/javascript/SecurityAdmin.js b/admin/javascript/SecurityAdmin.js index 7607cfa34..4493e5b5f 100644 --- a/admin/javascript/SecurityAdmin.js +++ b/admin/javascript/SecurityAdmin.js @@ -30,42 +30,47 @@ $(this).bind('load', refreshAfterImport); } }); - }) - - /** - * Delete selected folders through "batch actions" tab. - */ - $(document).ready(function() { - $('#Form_BatchActionsForm').entwine('ss').register( - // TODO Hardcoding of base URL - 'admin/security/batchactions/delete', - function(ids) { - var confirmed = confirm( - ss.i18n.sprintf( - ss.i18n._t('SecurityAdmin.BATCHACTIONSDELETECONFIRM'), - ids.length - ) - ); - return (confirmed) ? ids : false; - } - ); }); $.entwine('ss', function($){ /** - * Class: .cms-edit-form .Actions #Form_EditForm_action_addmember + * Class: #Permissions .checkbox[value=ADMIN] + * + * Automatically check and disable all checkboxes if ADMIN permissions are selected. + * As they're disabled, any changes won't be submitted (which is intended behaviour), + * checking all boxes is purely presentational. */ - $('.cms-edit-form .Actions #Form_EditForm_action_addmember').entwine({ - // Function: onclick + $('#Permissions .checkbox[value=ADMIN]').entwine({ + onmatch: function() { + this.toggleCheckboxes(); + + this._super(); + }, + /** + * Function: onclick + */ onclick: function(e) { - // CAUTION: Assumes that a MemberTableField-instance is present as an editing form - var t = $('#Form_EditForm_Members'); - t[0].openPopup( - null, - $('base').attr('href') + t.find('a.addlink').attr('href'), - t.find('table')[0] - ); - return false; + this.toggleCheckboxes(); + }, + /** + * Function: toggleCheckboxes + */ + toggleCheckboxes: function() { + var self = this, checkboxes = this.parents('.field:eq(0)').find('.checkbox').not(this); + + if(this.is(':checked')) { + checkboxes.each(function() { + $(this).data('SecurityAdmin.oldChecked', $(this).attr('checked')); + $(this).data('SecurityAdmin.oldDisabled', $(this).attr('disabled')); + $(this).attr('disabled', 'disabled'); + $(this).attr('checked', 'checked'); + }); + } else { + checkboxes.each(function() { + $(this).attr('checked', $(this).data('SecurityAdmin.oldChecked')); + $(this).attr('disabled', $(this).data('SecurityAdmin.oldDisabled')); + }); + } } }); }); diff --git a/admin/scss/_style.scss b/admin/scss/_style.scss index 3bf2ec065..a6861edbc 100644 --- a/admin/scss/_style.scss +++ b/admin/scss/_style.scss @@ -29,7 +29,7 @@ body.cms { .cms { a { - color: $color-text-dark-link; + color: $color-text-blue-link; text-decoration: none; &:hover, @@ -80,7 +80,6 @@ body.cms { @include inline-block; } - .cms-content-header { padding: ($grid-y - 8) $grid-x $grid-y; height: $grid-y * 4; @@ -98,6 +97,9 @@ body.cms { .backlink { float:left; margin-top:$grid-x - 1; + span.btn-icon-back { + height:15px; + } } h2 { @@ -126,17 +128,6 @@ body.cms { font-weight: bold; line-height: $grid-y * 2; padding: ($grid-y * 2 - 4) ($grid-x * 2 + 4) $grid-y + 3; - text-indent:-9999em; - - &.content-treeview { - background:url(../images/content-header-tabs-sprite.png) no-repeat 2px 0px; - } - &.content-galleryview { - background:url(../images/content-header-tabs-sprite.png) no-repeat -87px 0px; - } - &.content-listview { - background:url(../images/content-header-tabs-sprite.png) no-repeat -38px 0px; - } } } @@ -154,18 +145,6 @@ body.cms { border: { top:none; } - - a { - &.content-treeview { - background:url(../images/content-header-tabs-sprite.png) no-repeat 2px -40px; - } - &.content-galleryview { - background:url(../images/content-header-tabs-sprite.png) no-repeat -87px -40px; - } - &.content-listview { - background:url(../images/content-header-tabs-sprite.png) no-repeat -38px -40px; - } - } } .ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { border-radius:0; @@ -245,6 +224,51 @@ body.cms { } } +.CMSPagesController { + .cms-content-header-tabs { + .ui-tabs-nav { + li { + a { + font-weight: bold; + line-height: $grid-y * 2; + padding: ($grid-y * 2 - 4) ($grid-x * 2 + 4) $grid-y + 3; + text-indent:-9999em; + + &.content-treeview { + background:url(../images/content-header-tabs-sprite.png) no-repeat 2px 0px; + } + &.content-galleryview { + background:url(../images/content-header-tabs-sprite.png) no-repeat -87px 0px; + } + &.content-listview { + background:url(../images/content-header-tabs-sprite.png) no-repeat -38px 0px; + } + } + } + + .ui-state-active, + .ui-widget-content .ui-state-active, + .ui-widget-header .ui-state-active { + border: { + top:none; + } + + a { + &.content-treeview { + background:url(../images/content-header-tabs-sprite.png) no-repeat 2px -40px; + } + &.content-galleryview { + background:url(../images/content-header-tabs-sprite.png) no-repeat -87px -40px; + } + &.content-listview { + background:url(../images/content-header-tabs-sprite.png) no-repeat -38px -40px; + } + } + } + } + } +} + /** ------------------------------------------------------- * Loading Interface * ------------------------------------------------------- */ @@ -356,7 +380,7 @@ body.cms { background-color: lighten($color-warning, 20%); border-color: $color-warning; } - &.error { + &.error, &.bad, &.required { background-color: lighten($color-error, 20%); border-color: $color-error; } @@ -688,9 +712,6 @@ body.cms { form.cms-batch-actions { float: left; } - .Actions { - display:none; - } } #Form_BatchActionsForm select { @@ -885,6 +906,28 @@ form.member-profile-form { overflow-x: auto; background: none; width:100%; + .aligned_right_label { + margin-left:$grid-x*23; + padding:$grid-x 0; + } + } +} + +/** -------------------------------------------- + * "Settings" Form + * -------------------------------------------- */ +#CanViewType, #CanEditType, #CanCreateTopLevelType { + .optionset li { + // All options on their own line + float: none; + width: auto; + } +} +#ViewerGroups, #EditorGroups, #CreateTopLevelGroups { + select { + // Fix for chosen.js width detection on hidden elements. + // TODO Remove once .field styling in _form.scss is refactored to allow flexible field widths + width: $grid-x * 64; } } @@ -1015,11 +1058,13 @@ form.member-profile-form { } -.cms-panel-padded { - width: ($grid-x * 22); - padding: $grid-y*2 $grid-x*2; - overflow-x: hidden; - overflow-y: auto; +.cms { + .cms-panel-padded { + width: ($grid-x * 22); + padding: $grid-y*2 $grid-x*2; + overflow-x: hidden; + overflow-y: auto; + } } /** ------------------------------------------------------------------ @@ -1295,4 +1340,23 @@ form.small { } } } +} + +/** -------------------------------------------- + * Users Members Admin + * -------------------------------------------- */ + + .members_grid { + span button#action_gridfield_relationfind { + display:none; + } + p button#action_export { + margin-top:$grid-y*2; + span.btn-icon-download-csv { + height:$grid-y*2 + 1; + } + span.ui-button-text { + padding-left:$grid-x*3 + 3; + } + } } \ No newline at end of file diff --git a/admin/scss/_tree.scss b/admin/scss/_tree.scss index dfa5e1f56..aa6f6cad8 100644 --- a/admin/scss/_tree.scss +++ b/admin/scss/_tree.scss @@ -380,6 +380,17 @@ .jstree li { line-height: 25px; } + + // Hide drag icons by default. Actual page icons + // are in nested , not handled directly through jstree lib + a > .jstree-icon { + display: none; + } + + // Show drag icons when draggable class is applied + .draggable a > .jstree-icon { + display: block; + } } .jstree-apple { @@ -519,7 +530,7 @@ background-image: url(../images/sitetree_ss_default_icons.png); } - & li.jstree-checked a, li.jstree-checked a:link { + & li.jstree-checked > a, li.jstree-checked > a:link { background-color: $color-cms-batchactions-menu-selected-background; } @@ -532,10 +543,6 @@ } } -.jstree-apple #record-0.jstree-open > ins { - display: none; -} - a .jstree-pageicon { display: block; float: left; @@ -565,4 +572,18 @@ li.class-ErrorPage > a .jstree-pageicon { .cms-tree { visibility: hidden; // enabled by JS to avoid layout glitches + + &.multiple { + // Hide draggable icon when multiselect is enabled + li > a > .jstree-icon { + display: none; + } + + li#record-0 { + // Hide checkbox on root node (shouldn't be selectable to avoid weird states when trying to e.g. remove it) + &> a .jstree-checkbox { + display: none; + } + } + } } diff --git a/admin/scss/ie7.scss b/admin/scss/ie7.scss index 00788b594..a8e249f81 100644 --- a/admin/scss/ie7.scss +++ b/admin/scss/ie7.scss @@ -53,16 +53,116 @@ html { text-indent: 0px !important; } -.cms { - table.ss-gridfield-table { - tbody { - td { - button { - span.ui-button-text { - zoom:1; - } - } +//fix for filter and reset icons on datagrid + +.cms table.ss-gridfield-table tr th.extra span input { + height:23px; +} + +.ss-gridfield-button-filter.ss-ui-button { + margin: -1px -5px; + background: #e6e6e6 url(../images/filter-icons.png) no-repeat -40px 6px; filter:none; + &.hover-alike:active { + background: darken(#338DC1, 5%) url(../images/filter-icons.png) no-repeat -15px 7px; filter:none; + } + &.hover-alike { + background: #338DC1 url(../images/filter-icons.png) no-repeat -16px 6px; filter:none; + } +} +.ss-gridfield-button-reset.ss-ui-button { + margin: -1px -5px; + background: #e6e6e6 url(../images/filter-icons.png) no-repeat 8px 5px; filter:none; + &.filtered:hover { + background: #FF0000 url(../images/filter-icons.png) no-repeat 8px -17px; filter:none; + } + &.filtered:active { + background: darken(#FF0000, 5%) url(../images/filter-icons.png) no-repeat 9px -16px; filter:none; + } +} + +//fix for borders on gridfield table + +.cms table.ss-gridfield-table { + tr { + td { + border-right: 1px solid lighten(#808080, 10%); + } + th { + border-right: 1px solid lighten(#808080, 10%); + &.main { + border-top: 1px solid lighten(#808080, 10%); + border-bottom: none; + } + &.extra { + border-top: 1px solid lighten(#808080, 10%); + padding-right:12px; } } } -} \ No newline at end of file + td:first-child, th:first-child { + border-left: 1px solid lighten(#808080, 10%); + } +} + +//fix for edit and delete icons in IE7 + +.cms .ss-gridfield table.ss-gridfield-table tbody { + td { + button { + &.gridfield-button-delete { + display:block; + float:left; + } + &.gridfield-button-unlink.ui-state-hover { + display:block; + float:left; + } + } + a.edit-link { + display:block; + float:left; + } + } +} + +//fix for wrong alignment of label on parent groups field in users groups and fix for width of parent group dropdown field + +.cms .cms-content .cms-content-fields { + .aligned_right_label { + margin-left:0; + } + .field.dropdown .middleColumn { + max-width:512px; + } +} + +//fix for input on datagrid pagination + +.pagination-page-number { + position:relative; + bottom:10px; + right:10px; + input { + width:45px; + padding:0px; + position:relative; + bottom:2px; + } +} + +//fix for wrong height on users groups gridfield table header + +table.ss-gridfield-table tr.title th h2 { + float:left; +} + +//fix for alternate colors on rows in datagrid + +table.ss-gridfield-table tr { + &.ss-gridfield-item.odd { + background: white; + } + &.ss-gridfield-item.even { + background: #F0F4F7; + } +} \ No newline at end of file diff --git a/admin/scss/ie8.scss b/admin/scss/ie8.scss index 33f6ee02c..62bfe3fc4 100644 --- a/admin/scss/ie8.scss +++ b/admin/scss/ie8.scss @@ -27,4 +27,54 @@ .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { background-image:none; -} \ No newline at end of file +} + +//fix for filter and reset icons on datagrid + +.ss-gridfield-button-filter.ss-ui-button{ + background: #e6e6e6 url(../images/filter-icons.png) no-repeat -40px 6px; filter:none; + &.hover-alike:active { + background: darken(#338DC1, 5%) url(../images/filter-icons.png) no-repeat -15px 7px; filter:none; + } + &.hover-alike { + background: #338DC1 url(../images/filter-icons.png) no-repeat -16px 6px; filter:none; + } +} +.ss-gridfield-button-reset.ss-ui-button{ + background: #e6e6e6 url(../images/filter-icons.png) no-repeat 8px 5px; filter:none; + &.filtered:hover { + background: #FF0000 url(../images/filter-icons.png) no-repeat 8px -17px; filter:none; + } + &.filtered:active { + background: darken(#FF0000, 5%) url(../images/filter-icons.png) no-repeat 9px -16px; filter:none; + } +} + +//fix for borders on gridfield table + +.cms table.ss-gridfield-table { + tr { + td { + border-right: 1px solid lighten(#808080, 10%); + } + th { + border-right: 1px solid lighten(#808080, 10%); + &.main { + border-top: 1px solid lighten(#808080, 10%); + border-bottom: none; + } + &.extra { + border-top: 1px solid lighten(#808080, 10%); + } + } + } + td:first-child, th:first-child { + border-left: 1px solid lighten(#808080, 10%); + } +} + +//fix for wrong alignment of label on parent groups field in users groups + +.cms .cms-content .cms-content-fields .aligned_right_label { + margin-left:0; +} diff --git a/admin/templates/Includes/LeftAndMain_EditForm.ss b/admin/templates/Includes/LeftAndMain_EditForm.ss index 92dccd0a0..9337ea924 100644 --- a/admin/templates/Includes/LeftAndMain_EditForm.ss +++ b/admin/templates/Includes/LeftAndMain_EditForm.ss @@ -20,7 +20,7 @@
diff --git a/admin/templates/Includes/MemberTableField.ss b/admin/templates/Includes/MemberTableField.ss deleted file mode 100644 index 9796a93a2..000000000 --- a/admin/templates/Includes/MemberTableField.ss +++ /dev/null @@ -1,62 +0,0 @@ -
-
- $SearchForm -
-
- <% if Markable %> - <% include TableListField_SelectOptions %> - <% end_if %> - <% include TableListField_PageControls %> - - - - <% if Markable %><% end_if %> - <% control Headings %> - - <% end_control %> - <% if Can(show) %><% end_if %> - <% if Can(edit) %><% end_if %> - <% if Can(delete) %><% end_if %> - - - - <% if Can(inlineadd) %> - - <% if Markable %> - - <% end_if %> - - <% if Markable %><% end_if %> - - <% if Can(show) %><% end_if %> - <% if Can(edit) %><% end_if %> - <% if Can(delete) %><% end_if %> - - - - <% if Items %> - <% control Items %> - <% include TableListField_Item %> - <% end_control %> - <% else %> - - <% if Markable %><% end_if %> - - <% control Actions %><% end_control %> - - <% end_if %> - -
 $Title   
 <% end_if %> - $AddRecordForm.CellFields - $AddRecordForm.CellActions
  - - - add<% _t('ADDNEW','Add new',50,'Followed by a member type') %> $Title -    
 <% _t('NOITEMSFOUND', 'No items found') %> 
-
- <% control Utility %> - $Title - <% end_control %> -
-
-
\ No newline at end of file diff --git a/admin/templates/Includes/ModelAdmin_Content.ss b/admin/templates/Includes/ModelAdmin_Content.ss index 43f4d5e71..caac9092b 100644 --- a/admin/templates/Includes/ModelAdmin_Content.ss +++ b/admin/templates/Includes/ModelAdmin_Content.ss @@ -1,9 +1,13 @@
-
-

<% _t('ModelAdmin.Title', 'My Model') %>

-
+

+ <% if SectionTitle %> + $SectionTitle + <% else %> + <% _t('ModelAdmin.Title', 'Data Models') %> + <% end_if %> +

$Tools diff --git a/admin/templates/Includes/ModelAdmin_Tools.ss b/admin/templates/Includes/ModelAdmin_Tools.ss index 4a078d5a1..a374438c8 100644 --- a/admin/templates/Includes/ModelAdmin_Tools.ss +++ b/admin/templates/Includes/ModelAdmin_Tools.ss @@ -6,7 +6,7 @@ <% if SearchClassSelector = tabs %>
    <% control ModelForms %> -
  • $Title
  • +
  • $Title
  • <% end_control %>
<% end_if %> @@ -16,14 +16,14 @@ Search for:
<% end_if %> <% control ModelForms %> -
+
$Content
<% end_control %> diff --git a/admin/templates/Includes/SecurityAdmin_Content.ss b/admin/templates/Includes/SecurityAdmin_Content.ss deleted file mode 100644 index cfb452a33..000000000 --- a/admin/templates/Includes/SecurityAdmin_Content.ss +++ /dev/null @@ -1,21 +0,0 @@ -
-
-
-
-

- <% include CMSBreadcrumbs %> -

-
-
- - $AddForm - -
- $SiteTreeAsUL -
- -
- - $EditForm - -
\ No newline at end of file diff --git a/admin/templates/ModelSidebar.ss b/admin/templates/ModelSidebar.ss index 6d6c994a5..e4a1c2929 100644 --- a/admin/templates/ModelSidebar.ss +++ b/admin/templates/ModelSidebar.ss @@ -1,7 +1,3 @@ -<% if CreateForm %> - $CreateForm -<% end_if %> -

<% _t('SEARCHLISTINGS','Search') %>

$SearchForm diff --git a/admin/tests/MemberTableFieldTest.php b/admin/tests/MemberTableFieldTest.php deleted file mode 100644 index f61edd47c..000000000 --- a/admin/tests/MemberTableFieldTest.php +++ /dev/null @@ -1,139 +0,0 @@ -objFromFixture('Member', 'member1'); - $member2 = $this->objFromFixture('Member', 'member2'); - $member3 = $this->objFromFixture('Member', 'member3'); - $group1 = $this->objFromFixture('Group', 'group1'); - - $tf = new MemberTableField( - $this, - "Members", - $group1 - ); - $members = $tf->sourceItems(); - - $this->assertContains($member1->ID, $members->column('ID'), - 'Members in the associated group are listed' - ); - $this->assertContains($member2->ID, $members->column('ID'), - 'Members in children groups are listed as well' - ); - $this->assertNotContains($member3->ID, $members->column('ID'), - 'Members in other groups are filtered out' - ); - } - - function testShowsAllMembersWithoutGroupParameter() { - $member1 = $this->objFromFixture('Member', 'member1'); - $member2 = $this->objFromFixture('Member', 'member2'); - $member3 = $this->objFromFixture('Member', 'member3'); - $group1 = $this->objFromFixture('Group', 'group1'); - - $tf = new MemberTableField( - $this, - "Members" - // no group assignment - ); - $members = $tf->sourceItems(); - - $this->assertContains($member1->ID, $members->column('ID'), - 'Members in the associated group are listed' - ); - $this->assertContains($member2->ID, $members->column('ID'), - 'Members in children groups are listed as well' - ); - $this->assertContains($member3->ID, $members->column('ID'), - 'Members in other groups are listed' - ); - } - - function testDeleteWithGroupOnlyDeletesRelation() { - $member1 = $this->objFromFixture('Member', 'member1'); - $group1 = $this->objFromFixture('Group', 'group1'); - - $response = $this->get('MemberTableFieldTest_Controller'); - $token = SecurityToken::inst(); - $url = sprintf('MemberTableFieldTest_Controller/Form/field/Members/item/%d/delete/?usetestmanifest=1', $member1->ID); - $url = $token->addToUrl($url); - $response = $this->get($url); - - $group1->flushCache(); - - $this->assertNotContains($member1->ID, $group1->Members()->column('ID'), - 'Member relation to group is removed' - ); - $this->assertType( - 'DataObject', - DataObject::get_by_id('Member', $member1->ID), - 'Member record still exists' - ); - } - - function testDeleteWithoutGroupDeletesFromDatabase() { - $member1 = $this->objFromFixture('Member', 'member1'); - $member1ID = $member1->ID; - $group1 = $this->objFromFixture('Group', 'group1'); - - $response = $this->get('MemberTableFieldTest_Controller'); - $token = SecurityToken::inst(); - $url = sprintf('MemberTableFieldTest_Controller/FormNoGroup/field/Members/item/%d/delete/?usetestmanifest=1', $member1->ID); - $url = $token->addToUrl($url); - $response = $this->get($url); - - $group1->flushCache(); - - $this->assertNotContains($member1->ID, $group1->Members()->column('ID'), - 'Member relation to group is removed' - ); - DataObject::flush_and_destroy_cache(); - $this->assertFalse( - DataObject::get_by_id('Member', $member1ID), - 'Member record is removed from database' - ); - } -} - -class MemberTableFieldTest_Controller extends Controller implements TestOnly { - - protected $template = 'BlankPage'; - - function Link($action = null) { - return Controller::join_links('MemberTableFieldTest_Controller', $action); - } - - function Form() { - $group1 = DataObject::get_one('Group', '"Code" = \'group1\''); - return new Form( - $this, - 'FormNoGroup', - new FieldList(new MemberTableField($this, "Members", $group1)), - new FieldList(new FormAction('submit')) - ); - } - - function FormNoGroup() { - $tf = new MemberTableField( - $this, - "Members" - // no group - ); - - return new Form( - $this, - 'FormNoGroup', - new FieldList(new MemberTableField($this, "Members")), - new FieldList(new FormAction('submit')) - ); - } - -} \ No newline at end of file diff --git a/admin/tests/MemberTableFieldTest.yml b/admin/tests/MemberTableFieldTest.yml deleted file mode 100644 index bc9785f26..000000000 --- a/admin/tests/MemberTableFieldTest.yml +++ /dev/null @@ -1,31 +0,0 @@ -Group: - admin: - Title: Administrators - Code: admin - group1: - Title: Group1 - Code: group1 - group1_child: - Title: Group1 Child - Parent: =>Group.group1 - Code: group1_child - group2: - Title: Group2 - Code: group2 -Member: - admin: - Email: admin@example.com - Groups: =>Group.admin - member1: - Email: member1@test.com - Groups: =>Group.group1 - member2: - Email: member2@test.com - Groups: =>Group.group1_child - member3: - Email: member3@test.com - Groups: =>Group.group2 -Permission: - admin: - Code: ADMIN - GroupID: =>Group.admin \ No newline at end of file diff --git a/admin/tests/SecurityAdminTest.php b/admin/tests/SecurityAdminTest.php index 387ccc16e..d9470c032 100644 --- a/admin/tests/SecurityAdminTest.php +++ b/admin/tests/SecurityAdminTest.php @@ -8,40 +8,42 @@ class SecurityAdminTest extends FunctionalTest { static $fixture_file = 'sapphire/admin/tests/LeftAndMainTest.yml'; protected $extraDataObjects = array('LeftAndMainTest_Object'); - - function testGroupExport() { - $this->session()->inst_set('loggedInAs', $this->idFromFixture('Member', 'admin')); - - /* First, open the applicable group */ - $response = $this->get('admin/security/show/' . $this->idFromFixture('Group','admin')); - $inputs = $this->cssParser()->getBySelector('input#Form_EditForm_Title'); - $this->assertNotNull($inputs); - $this->assertEquals('Administrators', (string)$inputs[0]['value']); - - /* Then load the export page */ - $this->get('admin/security/EditForm/field/Members/export'); - $lines = preg_split('/\n/', $this->content()); - $this->assertEquals(count($lines), 3, "Export with members has one content row"); - $this->assertRegExp('/"","","admin@example.com"/', $lines[1], "Member values are correctly exported"); - } + // TODO Fix export feature (moved from MemberTableField to GridFieldExporter) + // function testGroupExport() { + // $this->session()->inst_set('loggedInAs', $this->idFromFixture('Member', 'admin')); + + // /* First, open the applicable group */ + // $response = $this->get('admin/security/show/' . $this->idFromFixture('Group','admin')); + // $inputs = $this->cssParser()->getBySelector('input#Form_EditForm_Title'); + // $this->assertNotNull($inputs); + // $this->assertEquals('Administrators', (string)$inputs[0]['value']); + + // /* Then load the export page */ + // $this->get('admin/security/EditForm/field/Members/export'); + // $lines = preg_split('/\n/', $this->content()); - function testEmptyGroupExport() { - $this->session()->inst_set('loggedInAs', $this->idFromFixture('Member', 'admin')); + // $this->assertEquals(count($lines), 3, "Export with members has one content row"); + // $this->assertRegExp('/"","","admin@example.com"/', $lines[1], "Member values are correctly exported"); + // } + + // TODO Fix export feature (moved from MemberTableField to GridFieldExporter) + // function testEmptyGroupExport() { + // $this->session()->inst_set('loggedInAs', $this->idFromFixture('Member', 'admin')); - /* First, open the applicable group */ - $this->get('admin/security/show/' . $this->idFromFixture('Group','empty')); - $inputs = $this->cssParser()->getBySelector('input#Form_EditForm_Title'); - $this->assertNotNull($inputs); - $this->assertEquals('Empty Group', (string)$inputs[0]['value']); + // /* First, open the applicable group */ + // $this->get('admin/security/show/' . $this->idFromFixture('Group','empty')); + // $inputs = $this->cssParser()->getBySelector('input#Form_EditForm_Title'); + // $this->assertNotNull($inputs); + // $this->assertEquals('Empty Group', (string)$inputs[0]['value']); - /* Then load the export page */ - $this->get('admin/security/EditForm/field/Members/export'); - $lines = preg_split('/\n/', $this->content()); + // /* Then load the export page */ + // $this->get('admin/security/EditForm/field/Members/export'); + // $lines = preg_split('/\n/', $this->content()); - $this->assertEquals(count($lines), 2, "Empty export only has header fields and an empty row"); - $this->assertEquals($lines[1], '', "Empty export only has no content row"); - } + // $this->assertEquals(count($lines), 2, "Empty export only has header fields and an empty row"); + // $this->assertEquals($lines[1], '', "Empty export only has no content row"); + // } function testAddHiddenPermission() { SecurityAdmin::add_hidden_permission('CMS_ACCESS_ReportAdmin'); @@ -74,7 +76,7 @@ class SecurityAdminTest extends FunctionalTest { $group = $this->objFromFixture('Group', 'admin'); SecurityAdmin::add_hidden_permission('CMS_ACCESS_ReportAdmin'); - $response = $this->get('admin/security/show/' . $group->ID); + $response = $this->get(sprintf('admin/security/EditForm/field/Groups/item/%d/edit', $group->ID)); $this->assertContains( 'CMS_ACCESS_SecurityAdmin', diff --git a/admin/thirdparty/chosen/Cakefile b/admin/thirdparty/chosen/Cakefile index 89486e6fd..b8a3ef49b 100644 --- a/admin/thirdparty/chosen/Cakefile +++ b/admin/thirdparty/chosen/Cakefile @@ -77,7 +77,8 @@ task 'build', 'build Chosen from source', build = (cb) -> write_chosen_javascript javascript.replace(/\.js$/,'.min.js'), ( uglify.gen_code uglify.ast_squeeze uglify.ast_mangle parser.parse code ) - cb() if typeof cb is 'function' + package_npm () -> + cb() if typeof cb is 'function' catch e print_error e, file_name, file_contents @@ -94,6 +95,17 @@ task 'watch', 'watch coffee/ for changes and build Chosen', -> invoke 'build' )(file) +task 'package_npm', 'generate the package.json file for npm', package_npm = (cb) -> + try + package_file = 'package.json' + package = JSON.parse("#{fs.readFileSync package_file}") + package['version'] = version() + fs.writeFileSync package_file, JSON.stringify(package, null, 2) + console.log "Wrote #{package_file}" + cb() if typeof cb is 'function' + catch e + print_error e, package_file + run = (cmd, args, cb, err_cb) -> exec "#{cmd} #{args.join(' ')}", (err, stdout, stderr) -> if err isnt null diff --git a/admin/thirdparty/chosen/README.md b/admin/thirdparty/chosen/README.md index e19ddbb9f..a5039ef46 100644 --- a/admin/thirdparty/chosen/README.md +++ b/admin/thirdparty/chosen/README.md @@ -14,17 +14,20 @@ Contributions and pull requests are very welcome. Please follow these guidelines 1. Make all changes in Coffeescript files, **not** JavaScript files. 2. For feature changes, update both jQuery *and* Prototype versions -3. Use 'cake build' to generate Chosen's JavaScript file and minified version. -4. Don't touch the VERSION file -5. Submit a Pull Request using GitHub. +3. Use `npm install -d` to install the correct development dependencies. +4. Use `cake build` or `cake watch` to generate Chosen's JavaScript file and minified version. +5. Don't touch the `VERSION` file +6. Submit a Pull Request using GitHub. ### Using CoffeeScript & Cake -First, make sure you have the proper CoffeeScript / Cake set-up in place. +First, make sure you have the proper CoffeeScript / Cake set-up in place. We have added a package.json that makes this easy: -1. Install Coffeescript: the [CoffeeScript documentation](http://jashkenas.github.com/coffee-script/) provides easy-to-follow instructions. -2. Install UglifyJS: npm -g install uglify-js -3. Verify that your $NODE_PATH is properly configured using echo $NODE_PATH +``` +npm install -d +``` + +This will install `coffee-script` and `uglifyjs`. Once you're configured, building the JavasScript from the command line is easy: @@ -43,4 +46,5 @@ If you're interested, you can find the recipes in Cakefile. ### Notable Forks - [Chosen for MooTools](https://github.com/julesjanssen/chosen), by Jules Janssen -- [Chosen Drupal 7 Module](http://drupal.org/project/chosen), by Pol Dell'Aiera, Arshad Chummun, Bart Feenstra, Kálmán Hosszu, etc. \ No newline at end of file +- [Chosen Drupal 7 Module](http://drupal.org/project/chosen), by Pol Dell'Aiera, Arshad Chummun, Bart Feenstra, Kálmán Hosszu, etc. +- [Chosen CakePHP Plugin](https://github.com/paulredmond/chosen-cakephp), by Paul Redmond diff --git a/admin/thirdparty/chosen/VERSION b/admin/thirdparty/chosen/VERSION index b0bb87854..c81aa44af 100644 --- a/admin/thirdparty/chosen/VERSION +++ b/admin/thirdparty/chosen/VERSION @@ -1 +1 @@ -0.9.5 +0.9.7 diff --git a/admin/thirdparty/chosen/chosen/chosen-sprite.png b/admin/thirdparty/chosen/chosen/chosen-sprite.png index d08e4b7e6..231fe9055 100644 Binary files a/admin/thirdparty/chosen/chosen/chosen-sprite.png and b/admin/thirdparty/chosen/chosen/chosen-sprite.png differ diff --git a/admin/thirdparty/chosen/chosen/chosen.css b/admin/thirdparty/chosen/chosen/chosen.css index ac44796a2..a90506fd6 100644 --- a/admin/thirdparty/chosen/chosen/chosen.css +++ b/admin/thirdparty/chosen/chosen/chosen.css @@ -23,29 +23,32 @@ /* @group Single Chosen */ .chzn-container-single .chzn-single { - background-color: #fff; - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #eeeeee), color-stop(0.5, white)); - background-image: -webkit-linear-gradient(center bottom, #eeeeee 0%, white 50%); - background-image: -moz-linear-gradient(center bottom, #eeeeee 0%, white 50%); - background-image: -o-linear-gradient(top, #eeeeee 0%,#ffffff 50%); - background-image: -ms-linear-gradient(top, #eeeeee 0%,#ffffff 50%); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#eeeeee', endColorstr='#ffffff',GradientType=0 ); - background-image: linear-gradient(top, #eeeeee 0%,#ffffff 50%); - -webkit-border-radius: 4px; - -moz-border-radius : 4px; - border-radius : 4px; + background-color: #ffffff; + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#eeeeee', GradientType=0 ); + background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #ffffff), color-stop(50%, #f6f6f6), color-stop(52%, #eeeeee), color-stop(100%, #f4f4f4)); + background-image: -webkit-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%); + background-image: -moz-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%); + background-image: -o-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%); + background-image: -ms-linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%); + background-image: linear-gradient(top, #ffffff 20%, #f6f6f6 50%, #eeeeee 52%, #f4f4f4 100%); + -webkit-border-radius: 5px; + -moz-border-radius : 5px; + border-radius : 5px; -moz-background-clip : padding; -webkit-background-clip: padding-box; background-clip : padding-box; - border: 1px solid #aaa; + border: 1px solid #aaaaaa; + -webkit-box-shadow: 0 0 3px #ffffff inset, 0 1px 1px rgba(0,0,0,0.1); + -moz-box-shadow : 0 0 3px #ffffff inset, 0 1px 1px rgba(0,0,0,0.1); + box-shadow : 0 0 3px #ffffff inset, 0 1px 1px rgba(0,0,0,0.1); display: block; overflow: hidden; white-space: nowrap; position: relative; - height: 26px; - line-height: 26px; + height: 23px; + line-height: 24px; padding: 0 0 0 8px; - color: #444; + color: #444444; text-decoration: none; } .chzn-container-single .chzn-single span { @@ -61,7 +64,7 @@ display: block; position: absolute; right: 26px; - top: 8px; + top: 6px; width: 12px; height: 13px; font-size: 1px; @@ -71,21 +74,6 @@ background-position: right -11px; } .chzn-container-single .chzn-single div { - -webkit-border-radius: 0 4px 4px 0; - -moz-border-radius : 0 4px 4px 0; - border-radius : 0 4px 4px 0; - -moz-background-clip : padding; - -webkit-background-clip: padding-box; - background-clip : padding-box; - background: #ccc; - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #ccc), color-stop(0.6, #eee)); - background-image: -webkit-linear-gradient(center bottom, #ccc 0%, #eee 60%); - background-image: -moz-linear-gradient(center bottom, #ccc 0%, #eee 60%); - background-image: -o-linear-gradient(bottom, #ccc 0%, #eee 60%); - background-image: -ms-linear-gradient(top, #cccccc 0%,#eeeeee 60%); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#cccccc', endColorstr='#eeeeee',GradientType=0 ); - background-image: linear-gradient(top, #cccccc 0%,#eeeeee 60%); - border-left: 1px solid #aaa; position: absolute; right: 0; top: 0; @@ -94,7 +82,7 @@ width: 18px; } .chzn-container-single .chzn-single div b { - background: url('chosen-sprite.png') no-repeat 0 1px; + background: url('chosen-sprite.png') no-repeat 0 0; display: block; width: 100%; height: 100%; @@ -108,12 +96,12 @@ } .chzn-container-single .chzn-search input { background: #fff url('chosen-sprite.png') no-repeat 100% -22px; - background: url('chosen-sprite.png') no-repeat 100% -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, white), color-stop(0.99, #eeeeee)); - background: url('chosen-sprite.png') no-repeat 100% -22px, -webkit-linear-gradient(center bottom, white 85%, #eeeeee 99%); - background: url('chosen-sprite.png') no-repeat 100% -22px, -moz-linear-gradient(center bottom, white 85%, #eeeeee 99%); - background: url('chosen-sprite.png') no-repeat 100% -22px, -o-linear-gradient(bottom, white 85%, #eeeeee 99%); - background: url('chosen-sprite.png') no-repeat 100% -22px, -ms-linear-gradient(top, #ffffff 85%,#eeeeee 99%); - background: url('chosen-sprite.png') no-repeat 100% -22px, linear-gradient(top, #ffffff 85%,#eeeeee 99%); + background: url('chosen-sprite.png') no-repeat 100% -22px, -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff)); + background: url('chosen-sprite.png') no-repeat 100% -22px, -webkit-linear-gradient(top, #eeeeee 1%, #ffffff 15%); + background: url('chosen-sprite.png') no-repeat 100% -22px, -moz-linear-gradient(top, #eeeeee 1%, #ffffff 15%); + background: url('chosen-sprite.png') no-repeat 100% -22px, -o-linear-gradient(top, #eeeeee 1%, #ffffff 15%); + background: url('chosen-sprite.png') no-repeat 100% -22px, -ms-linear-gradient(top, #eeeeee 1%, #ffffff 15%); + background: url('chosen-sprite.png') no-repeat 100% -22px, linear-gradient(top, #eeeeee 1%, #ffffff 15%); margin: 1px 0; padding: 4px 20px 4px 5px; outline: 0; @@ -139,13 +127,12 @@ /* @group Multi Chosen */ .chzn-container-multi .chzn-choices { background-color: #fff; - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0.85, white), color-stop(0.99, #eeeeee)); - background-image: -webkit-linear-gradient(center bottom, white 85%, #eeeeee 99%); - background-image: -moz-linear-gradient(center bottom, white 85%, #eeeeee 99%); - background-image: -o-linear-gradient(bottom, white 85%, #eeeeee 99%); - background-image: -ms-linear-gradient(top, #ffffff 85%,#eeeeee 99%); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#eeeeee',GradientType=0 ); - background-image: linear-gradient(top, #ffffff 85%,#eeeeee 99%); + background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff)); + background-image: -webkit-linear-gradient(top, #eeeeee 1%, #ffffff 15%); + background-image: -moz-linear-gradient(top, #eeeeee 1%, #ffffff 15%); + background-image: -o-linear-gradient(top, #eeeeee 1%, #ffffff 15%); + background-image: -ms-linear-gradient(top, #eeeeee 1%, #ffffff 15%); + background-image: linear-gradient(top, #eeeeee 1%, #ffffff 15%); border: 1px solid #aaa; margin: 0; padding: 0; @@ -168,6 +155,9 @@ color: #666; background: transparent !important; border: 0 !important; + font-family: sans-serif; + font-size: 100%; + height: 15px; padding: 5px; margin: 1px 0; outline: 0; @@ -187,21 +177,22 @@ -webkit-background-clip: padding-box; background-clip : padding-box; background-color: #e4e4e4; - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, #e4e4e4), color-stop(0.7, #eeeeee)); - background-image: -webkit-linear-gradient(center bottom, #e4e4e4 0%, #eeeeee 70%); - background-image: -moz-linear-gradient(center bottom, #e4e4e4 0%, #eeeeee 70%); - background-image: -o-linear-gradient(bottom, #e4e4e4 0%, #eeeeee 70%); - background-image: -ms-linear-gradient(top, #e4e4e4 0%,#eeeeee 70%); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#e4e4e4', endColorstr='#eeeeee',GradientType=0 ); - background-image: linear-gradient(top, #e4e4e4 0%,#eeeeee 70%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f4f4f4', endColorstr='#eeeeee', GradientType=0 ); + background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #f4f4f4), color-stop(50%, #f0f0f0), color-stop(52%, #e8e8e8), color-stop(100%, #eeeeee)); + background-image: -webkit-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); + background-image: -moz-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); + background-image: -o-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); + background-image: -ms-linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); + background-image: linear-gradient(top, #f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eeeeee 100%); + -webkit-box-shadow: 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05); + -moz-box-shadow : 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05); + box-shadow : 0 0 2px #ffffff inset, 0 1px 0 rgba(0,0,0,0.05); color: #333; - border: 1px solid #b4b4b4; + border: 1px solid #aaaaaa; line-height: 13px; - padding: 3px 19px 3px 6px; + padding: 3px 20px 3px 5px; margin: 3px 0 3px 5px; position: relative; -} -.chzn-container-multi .chzn-choices .search-choice span { cursor: default; } .chzn-container-multi .chzn-choices .search-choice-focus { @@ -228,7 +219,7 @@ /* @group Results */ .chzn-container .chzn-results { margin: 0 4px 4px 0; - max-height: 190px; + max-height: 240px; padding: 0 0 0 4px; position: relative; overflow-x: hidden; @@ -240,8 +231,8 @@ } .chzn-container .chzn-results li { display: none; - line-height: 80%; - padding: 7px 7px 8px; + line-height: 15px; + padding: 5px 6px; margin: 0; list-style: none; } @@ -250,7 +241,14 @@ display: list-item; } .chzn-container .chzn-results .highlighted { - background: #3875d7; + background-color: #3875d7; + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#3875d7', endColorstr='#2a62bc', GradientType=0 ); + background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #3875d7), color-stop(90%, #2a62bc)); + background-image: -webkit-linear-gradient(top, #3875d7 20%, #2a62bc 90%); + background-image: -moz-linear-gradient(top, #3875d7 20%, #2a62bc 90%); + background-image: -o-linear-gradient(top, #3875d7 20%, #2a62bc 90%); + background-image: -ms-linear-gradient(top, #3875d7 20%, #2a62bc 90%); + background-image: linear-gradient(top, #3875d7 20%, #2a62bc 90%); color: #fff; } .chzn-container .chzn-results li em { @@ -270,11 +268,34 @@ font-weight: bold; } .chzn-container .chzn-results .group-option { - padding-left: 20px; + padding-left: 15px; } .chzn-container-multi .chzn-drop .result-selected { display: none; } +.chzn-container .chzn-results-scroll { + background: white; + margin: 0 4px; + position: absolute; + text-align: center; + width: 321px; /* This should by dynamic with js */ + z-index: 1; +} +.chzn-container .chzn-results-scroll span { + display: inline-block; + height: 17px; + text-indent: -5000px; + width: 9px; +} +.chzn-container .chzn-results-scroll-down { + bottom: 0; +} +.chzn-container .chzn-results-scroll-down span { + background: url('chosen-sprite.png') no-repeat -4px -3px; +} +.chzn-container .chzn-results-scroll-up span { + background: url('chosen-sprite.png') no-repeat -22px -3px; +} /* @end */ /* @group Active */ @@ -292,13 +313,13 @@ -o-box-shadow : 0 1px 0 #fff inset; box-shadow : 0 1px 0 #fff inset; background-color: #eee; - background-image: -webkit-gradient(linear, left bottom, left top, color-stop(0, white), color-stop(0.5, #eeeeee)); - background-image: -webkit-linear-gradient(center bottom, white 0%, #eeeeee 50%); - background-image: -moz-linear-gradient(center bottom, white 0%, #eeeeee 50%); - background-image: -o-linear-gradient(bottom, white 0%, #eeeeee 50%); - background-image: -ms-linear-gradient(top, #ffffff 0%,#eeeeee 50%); - filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#ffffff', endColorstr='#eeeeee',GradientType=0 ); - background-image: linear-gradient(top, #ffffff 0%,#eeeeee 50%); + filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#eeeeee', endColorstr='#ffffff', GradientType=0 ); + background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(20%, #eeeeee), color-stop(80%, #ffffff)); + background-image: -webkit-linear-gradient(top, #eeeeee 20%, #ffffff 80%); + background-image: -moz-linear-gradient(top, #eeeeee 20%, #ffffff 80%); + background-image: -o-linear-gradient(top, #eeeeee 20%, #ffffff 80%); + background-image: -ms-linear-gradient(top, #eeeeee 20%, #ffffff 80%); + background-image: linear-gradient(top, #eeeeee 20%, #ffffff 80%); -webkit-border-bottom-left-radius : 0; -webkit-border-bottom-right-radius: 0; -moz-border-radius-bottomleft : 0; @@ -338,34 +359,31 @@ } /* @group Right to Left */ -.chzn-rtl { direction:rtl;text-align: right; } -.chzn-rtl .chzn-single { padding-left: 0; padding-right: 8px; } -.chzn-rtl .chzn-single span { margin-left: 26px; margin-right: 0; } -.chzn-rtl .chzn-single div { - left: 0; right: auto; - border-left: none; border-right: 1px solid #aaaaaa; - -webkit-border-radius: 4px 0 0 4px; - -moz-border-radius : 4px 0 0 4px; - border-radius : 4px 0 0 4px; -} +.chzn-rtl { text-align: right; } +.chzn-rtl .chzn-single { padding: 0 8px 0 0; overflow: visible; } +.chzn-rtl .chzn-single span { margin-left: 26px; margin-right: 0; direction: rtl; } + +.chzn-rtl .chzn-single div { left: 3px; right: auto; } .chzn-rtl .chzn-single abbr { left: 26px; right: auto; } +.chzn-rtl .chzn-choices .search-field input { direction: rtl; } .chzn-rtl .chzn-choices li { float: right; } -.chzn-rtl .chzn-choices .search-choice { padding: 3px 6px 3px 19px; margin: 3px 5px 3px 0; } -.chzn-rtl .chzn-choices .search-choice .search-choice-close { left: 5px; right: auto; background-position: right top;} -.chzn-rtl.chzn-container-single .chzn-results { margin-left: 4px; margin-right: 0; padding-left: 0; padding-right: 4px; } -.chzn-rtl .chzn-results .group-option { padding-left: 0; padding-right: 20px; } +.chzn-rtl .chzn-choices .search-choice { padding: 3px 5px 3px 19px; margin: 3px 5px 3px 0; } +.chzn-rtl .chzn-choices .search-choice .search-choice-close { left: 4px; right: auto; background-position: right top;} +.chzn-rtl.chzn-container-single .chzn-results { margin: 0 0 4px 4px; padding: 0 4px 0 0; } +.chzn-rtl .chzn-results .group-option { padding-left: 0; padding-right: 15px; } .chzn-rtl.chzn-container-active .chzn-single-with-drop div { border-right: none; } .chzn-rtl .chzn-search input { - background: url('chosen-sprite.png') no-repeat -38px -22px, #ffffff; - background: url('chosen-sprite.png') no-repeat -38px -22px, -webkit-gradient(linear, left bottom, left top, color-stop(0.85, white), color-stop(0.99, #eeeeee)); - background: url('chosen-sprite.png') no-repeat -38px -22px, -webkit-linear-gradient(center bottom, white 85%, #eeeeee 99%); - background: url('chosen-sprite.png') no-repeat -38px -22px, -moz-linear-gradient(center bottom, white 85%, #eeeeee 99%); - background: url('chosen-sprite.png') no-repeat -38px -22px, -o-linear-gradient(bottom, white 85%, #eeeeee 99%); - background: url('chosen-sprite.png') no-repeat -38px -22px, -ms-linear-gradient(top, #ffffff 85%,#eeeeee 99%); - background: url('chosen-sprite.png') no-repeat -38px -22px, linear-gradient(top, #ffffff 85%,#eeeeee 99%); + background: #fff url('chosen-sprite.png') no-repeat -38px -22px; + background: url('chosen-sprite.png') no-repeat -38px -22px, -webkit-gradient(linear, 0% 0%, 0% 100%, color-stop(1%, #eeeeee), color-stop(15%, #ffffff)); + background: url('chosen-sprite.png') no-repeat -38px -22px, -webkit-linear-gradient(top, #eeeeee 1%, #ffffff 15%); + background: url('chosen-sprite.png') no-repeat -38px -22px, -moz-linear-gradient(top, #eeeeee 1%, #ffffff 15%); + background: url('chosen-sprite.png') no-repeat -38px -22px, -o-linear-gradient(top, #eeeeee 1%, #ffffff 15%); + background: url('chosen-sprite.png') no-repeat -38px -22px, -ms-linear-gradient(top, #eeeeee 1%, #ffffff 15%); + background: url('chosen-sprite.png') no-repeat -38px -22px, linear-gradient(top, #eeeeee 1%, #ffffff 15%); padding: 4px 5px 4px 20px; + direction: rtl; } /* @end */ diff --git a/admin/thirdparty/chosen/chosen/chosen.jquery.js b/admin/thirdparty/chosen/chosen/chosen.jquery.js index 05063bc80..491e79140 100644 --- a/admin/thirdparty/chosen/chosen/chosen.jquery.js +++ b/admin/thirdparty/chosen/chosen/chosen.jquery.js @@ -1,7 +1,7 @@ // Chosen, a Select Box Enhancer for jQuery and Protoype // by Patrick Filler for Harvest, http://getharvest.com // -// Version 0.9.5 +// Version 0.9.7 // Full source at https://github.com/harvesthq/chosen // Copyright (c) 2011 Harvest http://getharvest.com @@ -9,11 +9,14 @@ // This file is generated by `cake build`, do not edit it by hand. (function() { var SelectParser; + SelectParser = (function() { + function SelectParser() { this.options_index = 0; this.parsed = []; } + SelectParser.prototype.add_node = function(child) { if (child.nodeName === "OPTGROUP") { return this.add_group(child); @@ -21,6 +24,7 @@ return this.add_option(child); } }; + SelectParser.prototype.add_group = function(group) { var group_position, option, _i, _len, _ref, _results; group_position = this.parsed.length; @@ -39,12 +43,11 @@ } return _results; }; + SelectParser.prototype.add_option = function(option, group_position, group_disabled) { if (option.nodeName === "OPTION") { if (option.text !== "") { - if (group_position != null) { - this.parsed[group_position].children += 1; - } + if (group_position != null) this.parsed[group_position].children += 1; this.parsed.push({ array_index: this.parsed.length, options_index: this.options_index, @@ -67,8 +70,11 @@ return this.options_index += 1; } }; + return SelectParser; + })(); + SelectParser.select_to_array = function(select) { var child, parser, _i, _len, _ref; parser = new SelectParser(); @@ -79,17 +85,23 @@ } return parser.parsed; }; + this.SelectParser = SelectParser; + }).call(this); + +/* +Chosen source: generate output using 'cake build' +Copyright (c) 2011 by Harvest +*/ + (function() { - /* - Chosen source: generate output using 'cake build' - Copyright (c) 2011 by Harvest - */ var AbstractChosen, root; - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + root = this; + AbstractChosen = (function() { + function AbstractChosen(form_field, options) { this.form_field = form_field; this.options = options != null ? options : {}; @@ -101,13 +113,15 @@ this.register_observers(); this.finish_setup(); } + AbstractChosen.prototype.set_default_values = function() { - this.click_test_action = __bind(function(evt) { - return this.test_active_click(evt); - }, this); - this.activate_action = __bind(function(evt) { - return this.activate_field(evt); - }, this); + var _this = this; + this.click_test_action = function(evt) { + return _this.test_active_click(evt); + }; + this.activate_action = function(evt) { + return _this.activate_field(evt); + }; this.active_field = false; this.mouse_on_container = false; this.results_showing = false; @@ -118,52 +132,55 @@ this.choices = 0; return this.results_none_found = this.options.no_results_text || "No results match"; }; + AbstractChosen.prototype.mouse_enter = function() { return this.mouse_on_container = true; }; + AbstractChosen.prototype.mouse_leave = function() { return this.mouse_on_container = false; }; + AbstractChosen.prototype.input_focus = function(evt) { + var _this = this; if (!this.active_field) { - return setTimeout((__bind(function() { - return this.container_mousedown(); - }, this)), 50); + return setTimeout((function() { + return _this.container_mousedown(); + }), 50); } }; + AbstractChosen.prototype.input_blur = function(evt) { + var _this = this; if (!this.mouse_on_container) { this.active_field = false; - return setTimeout((__bind(function() { - return this.blur_test(); - }, this)), 100); + return setTimeout((function() { + return _this.blur_test(); + }), 100); } }; + AbstractChosen.prototype.result_add_option = function(option) { var classes, style; if (!option.disabled) { option.dom_id = this.container_id + "_o_" + option.array_index; classes = option.selected && this.is_multiple ? [] : ["active-result"]; - if (option.selected) { - classes.push("result-selected"); - } - if (option.group_array_index != null) { - classes.push("group-option"); - } - if (option.classes !== "") { - classes.push(option.classes); - } + if (option.selected) classes.push("result-selected"); + if (option.group_array_index != null) classes.push("group-option"); + if (option.classes !== "") classes.push(option.classes); style = option.style.cssText !== "" ? " style=\"" + option.style + "\"" : ""; return '
  • ' + option.html + '
  • '; } else { return ""; } }; + AbstractChosen.prototype.results_update_field = function() { this.result_clear_highlight(); this.result_single_selected = null; return this.results_build(); }; + AbstractChosen.prototype.results_toggle = function() { if (this.results_showing) { return this.results_hide(); @@ -171,6 +188,7 @@ return this.results_show(); } }; + AbstractChosen.prototype.results_search = function(evt) { if (this.results_showing) { return this.winnow_results(); @@ -178,6 +196,7 @@ return this.results_show(); } }; + AbstractChosen.prototype.keyup_checker = function(evt) { var stroke, _ref; stroke = (_ref = evt.which) != null ? _ref : evt.keyCode; @@ -193,15 +212,11 @@ break; case 13: evt.preventDefault(); - if (this.results_showing) { - return this.result_select(evt); - } + if (this.results_showing) return this.result_select(evt); break; case 27: - if (this.results_showing) { - return this.results_hide(); - } - break; + if (this.results_showing) this.results_hide(); + return true; case 9: case 38: case 40: @@ -213,62 +228,71 @@ return this.results_search(); } }; + AbstractChosen.prototype.generate_field_id = function() { var new_id; new_id = this.generate_random_id(); this.form_field.id = new_id; return new_id; }; + AbstractChosen.prototype.generate_random_char = function() { var chars, newchar, rand; chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZ"; rand = Math.floor(Math.random() * chars.length); return newchar = chars.substring(rand, rand + 1); }; + return AbstractChosen; + })(); + root.AbstractChosen = AbstractChosen; + }).call(this); + +/* +Chosen source: generate output using 'cake build' +Copyright (c) 2011 by Harvest +*/ + (function() { - /* - Chosen source: generate output using 'cake build' - Copyright (c) 2011 by Harvest - */ - var $, Chosen, get_side_border_padding, root; - var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { - for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } - function ctor() { this.constructor = child; } - ctor.prototype = parent.prototype; - child.prototype = new ctor; - child.__super__ = parent.prototype; - return child; - }, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + var $, Chosen, get_side_border_padding, root, + __hasProp = Object.prototype.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; }; + root = this; + $ = jQuery; + $.fn.extend({ chosen: function(options) { if ($.browser.msie && ($.browser.version === "6.0" || $.browser.version === "7.0")) { return this; } return $(this).each(function(input_field) { - if (!($(this)).hasClass("chzn-done")) { - return new Chosen(this, options); - } + if (!($(this)).hasClass("chzn-done")) return new Chosen(this, options); }); } }); - Chosen = (function() { - __extends(Chosen, AbstractChosen); + + Chosen = (function(_super) { + + __extends(Chosen, _super); + function Chosen() { Chosen.__super__.constructor.apply(this, arguments); } + Chosen.prototype.setup = function() { this.form_field_jq = $(this.form_field); return this.is_rtl = this.form_field_jq.hasClass("chzn-rtl"); }; + Chosen.prototype.finish_setup = function() { return this.form_field_jq.addClass("chzn-done"); }; + Chosen.prototype.set_up_html = function() { var container_div, dd_top, dd_width, sf_width; this.container_id = this.form_field.id.length ? this.form_field.id.replace(/(:|\.)/g, '_') : this.generate_field_id(); @@ -316,49 +340,56 @@ chosen: this }); }; + Chosen.prototype.register_observers = function() { - this.container.mousedown(__bind(function(evt) { - return this.container_mousedown(evt); - }, this)); - this.container.mouseup(__bind(function(evt) { - return this.container_mouseup(evt); - }, this)); - this.container.mouseenter(__bind(function(evt) { - return this.mouse_enter(evt); - }, this)); - this.container.mouseleave(__bind(function(evt) { - return this.mouse_leave(evt); - }, this)); - this.search_results.mouseup(__bind(function(evt) { - return this.search_results_mouseup(evt); - }, this)); - this.search_results.mouseover(__bind(function(evt) { - return this.search_results_mouseover(evt); - }, this)); - this.search_results.mouseout(__bind(function(evt) { - return this.search_results_mouseout(evt); - }, this)); - this.form_field_jq.bind("liszt:updated", __bind(function(evt) { - return this.results_update_field(evt); - }, this)); - this.search_field.blur(__bind(function(evt) { - return this.input_blur(evt); - }, this)); - this.search_field.keyup(__bind(function(evt) { - return this.keyup_checker(evt); - }, this)); - this.search_field.keydown(__bind(function(evt) { - return this.keydown_checker(evt); - }, this)); + var _this = this; + this.container.mousedown(function(evt) { + return _this.container_mousedown(evt); + }); + this.container.mouseup(function(evt) { + return _this.container_mouseup(evt); + }); + this.container.mouseenter(function(evt) { + return _this.mouse_enter(evt); + }); + this.container.mouseleave(function(evt) { + return _this.mouse_leave(evt); + }); + this.search_results.mouseup(function(evt) { + return _this.search_results_mouseup(evt); + }); + this.search_results.mouseover(function(evt) { + return _this.search_results_mouseover(evt); + }); + this.search_results.mouseout(function(evt) { + return _this.search_results_mouseout(evt); + }); + this.form_field_jq.bind("liszt:updated", function(evt) { + return _this.results_update_field(evt); + }); + this.search_field.blur(function(evt) { + return _this.input_blur(evt); + }); + this.search_field.keyup(function(evt) { + return _this.keyup_checker(evt); + }); + this.search_field.keydown(function(evt) { + return _this.keydown_checker(evt); + }); if (this.is_multiple) { - this.search_choices.click(__bind(function(evt) { - return this.choices_click(evt); - }, this)); - return this.search_field.focus(__bind(function(evt) { - return this.input_focus(evt); - }, this)); + this.search_choices.click(function(evt) { + return _this.choices_click(evt); + }); + return this.search_field.focus(function(evt) { + return _this.input_focus(evt); + }); + } else { + return this.container.click(function(evt) { + return evt.preventDefault(); + }); } }; + Chosen.prototype.search_field_disabled = function() { this.is_disabled = this.form_field_jq[0].disabled; if (this.is_disabled) { @@ -376,18 +407,15 @@ } } }; + Chosen.prototype.container_mousedown = function(evt) { var target_closelink; if (!this.is_disabled) { target_closelink = evt != null ? ($(evt.target)).hasClass("search-choice-close") : false; - if (evt && evt.type === "mousedown") { - evt.stopPropagation(); - } + if (evt && evt.type === "mousedown") evt.stopPropagation(); if (!this.pending_destroy_click && !target_closelink) { if (!this.active_field) { - if (this.is_multiple) { - this.search_field.val(""); - } + if (this.is_multiple) this.search_field.val(""); $(document).click(this.click_test_action); this.results_show(); } else if (!this.is_multiple && evt && (($(evt.target)[0] === this.selected_item[0]) || $(evt.target).parents("a.chzn-single").length)) { @@ -400,16 +428,17 @@ } } }; + Chosen.prototype.container_mouseup = function(evt) { - if (evt.target.nodeName === "ABBR") { - return this.results_reset(evt); - } + if (evt.target.nodeName === "ABBR") return this.results_reset(evt); }; + Chosen.prototype.blur_test = function(evt) { if (!this.active_field && this.container.hasClass("chzn-container-active")) { return this.close_field(); } }; + Chosen.prototype.close_field = function() { $(document).unbind("click", this.click_test_action); if (!this.is_multiple) { @@ -424,6 +453,7 @@ this.show_search_field_default(); return this.search_field_scale(); }; + Chosen.prototype.activate_field = function() { if (!this.is_multiple && !this.active_field) { this.search_field.attr("tabindex", this.selected_item.attr("tabindex")); @@ -434,6 +464,7 @@ this.search_field.val(this.search_field.val()); return this.search_field.focus(); }; + Chosen.prototype.test_active_click = function(evt) { if ($(evt.target).parents('#' + this.container_id).length) { return this.active_field = true; @@ -441,6 +472,7 @@ return this.close_field(); } }; + Chosen.prototype.results_build = function() { var content, data, _i, _len, _ref; this.parsing = true; @@ -468,9 +500,7 @@ this.choice_build(data); } else if (data.selected && !this.is_multiple) { this.selected_item.find("span").text(data.text); - if (this.allow_single_deselect) { - this.single_deselect_control_build(); - } + if (this.allow_single_deselect) this.single_deselect_control_build(); } } } @@ -480,6 +510,7 @@ this.search_results.html(content); return this.parsing = false; }; + Chosen.prototype.result_add_group = function(group) { if (!group.disabled) { group.dom_id = this.container_id + "_g_" + group.array_index; @@ -488,6 +519,7 @@ return ""; } }; + Chosen.prototype.result_do_highlight = function(el) { var high_bottom, high_top, maxHeight, visible_bottom, visible_top; if (el.length) { @@ -506,12 +538,12 @@ } } }; + Chosen.prototype.result_clear_highlight = function() { - if (this.result_highlight) { - this.result_highlight.removeClass("highlighted"); - } + if (this.result_highlight) this.result_highlight.removeClass("highlighted"); return this.result_highlight = null; }; + Chosen.prototype.results_show = function() { var dd_top; if (!this.is_multiple) { @@ -530,6 +562,7 @@ this.search_field.val(this.search_field.val()); return this.winnow_results(); }; + Chosen.prototype.results_hide = function() { if (!this.is_multiple) { this.selected_item.removeClass("chzn-single-with-drop"); @@ -540,6 +573,7 @@ }); return this.results_showing = false; }; + Chosen.prototype.set_tab_index = function(el) { var ti; if (this.form_field_jq.attr("tabindex")) { @@ -553,6 +587,7 @@ } } }; + Chosen.prototype.show_search_field_default = function() { if (this.is_multiple && this.choices < 1 && !this.active_field) { this.search_field.val(this.default_text); @@ -562,6 +597,7 @@ return this.search_field.removeClass("default"); } }; + Chosen.prototype.search_results_mouseup = function(evt) { var target; target = $(evt.target).hasClass("active-result") ? $(evt.target) : $(evt.target).parents(".active-result").first(); @@ -570,34 +606,38 @@ return this.result_select(evt); } }; + Chosen.prototype.search_results_mouseover = function(evt) { var target; target = $(evt.target).hasClass("active-result") ? $(evt.target) : $(evt.target).parents(".active-result").first(); - if (target) { - return this.result_do_highlight(target); - } + if (target) return this.result_do_highlight(target); }; + Chosen.prototype.search_results_mouseout = function(evt) { if ($(evt.target).hasClass("active-result" || $(evt.target).parents('.active-result').first())) { return this.result_clear_highlight(); } }; + Chosen.prototype.choices_click = function(evt) { evt.preventDefault(); if (this.active_field && !($(evt.target).hasClass("search-choice" || $(evt.target).parents('.search-choice').first)) && !this.results_showing) { return this.results_show(); } }; + Chosen.prototype.choice_build = function(item) { - var choice_id, link; + var choice_id, link, + _this = this; choice_id = this.container_id + "_c_" + item.array_index; this.choices += 1; this.search_container.before('
  • ' + item.html + '
  • '); link = $('#' + choice_id).find("a").first(); - return link.click(__bind(function(evt) { - return this.choice_destroy_link_click(evt); - }, this)); + return link.click(function(evt) { + return _this.choice_destroy_link_click(evt); + }); }; + Chosen.prototype.choice_destroy_link_click = function(evt) { evt.preventDefault(); if (!this.is_disabled) { @@ -607,6 +647,7 @@ return evt.stopPropagation; } }; + Chosen.prototype.choice_destroy = function(link) { this.choices -= 1; this.show_search_field_default(); @@ -616,16 +657,16 @@ this.result_deselect(link.attr("rel")); return link.parents('li').first().remove(); }; + Chosen.prototype.results_reset = function(evt) { this.form_field.options[0].selected = true; this.selected_item.find("span").text(this.default_text); this.show_search_field_default(); $(evt.target).remove(); this.form_field_jq.trigger("change"); - if (this.active_field) { - return this.results_hide(); - } + if (this.active_field) return this.results_hide(); }; + Chosen.prototype.result_select = function(evt) { var high, high_id, item, position; if (this.result_highlight) { @@ -647,24 +688,23 @@ this.choice_build(item); } else { this.selected_item.find("span").first().text(item.text); - if (this.allow_single_deselect) { - this.single_deselect_control_build(); - } - } - if (!(evt.metaKey && this.is_multiple)) { - this.results_hide(); + if (this.allow_single_deselect) this.single_deselect_control_build(); } + if (!(evt.metaKey && this.is_multiple)) this.results_hide(); this.search_field.val(""); this.form_field_jq.trigger("change"); return this.search_field_scale(); } }; + Chosen.prototype.result_activate = function(el) { return el.addClass("active-result"); }; + Chosen.prototype.result_deactivate = function(el) { return el.removeClass("active-result"); }; + Chosen.prototype.result_deselect = function(pos) { var result, result_data; result_data = this.results_data[pos]; @@ -677,11 +717,13 @@ this.form_field_jq.trigger("change"); return this.search_field_scale(); }; + Chosen.prototype.single_deselect_control_build = function() { if (this.allow_single_deselect && this.selected_item.find("abbr").length < 1) { return this.selected_item.find("span").first().after(""); } }; + Chosen.prototype.winnow_results = function() { var found, option, part, parts, regex, result, result_id, results, searchText, startpos, text, zregex, _i, _j, _len, _len2, _ref; this.no_results_clear(); @@ -742,6 +784,7 @@ return this.winnow_results_set_highlight(); } }; + Chosen.prototype.winnow_results_clear = function() { var li, lis, _i, _len, _results; this.search_field.val(""); @@ -750,46 +793,49 @@ for (_i = 0, _len = lis.length; _i < _len; _i++) { li = lis[_i]; li = $(li); - _results.push(li.hasClass("group-result") ? li.css('display', 'auto') : !this.is_multiple || !li.hasClass("result-selected") ? this.result_activate(li) : void 0); + if (li.hasClass("group-result")) { + _results.push(li.css('display', 'auto')); + } else if (!this.is_multiple || !li.hasClass("result-selected")) { + _results.push(this.result_activate(li)); + } else { + _results.push(void 0); + } } return _results; }; + Chosen.prototype.winnow_results_set_highlight = function() { var do_high, selected_results; if (!this.result_highlight) { selected_results = !this.is_multiple ? this.search_results.find(".result-selected.active-result") : []; do_high = selected_results.length ? selected_results.first() : this.search_results.find(".active-result").first(); - if (do_high != null) { - return this.result_do_highlight(do_high); - } + if (do_high != null) return this.result_do_highlight(do_high); } }; + Chosen.prototype.no_results = function(terms) { var no_results_html; no_results_html = $('
  • ' + this.results_none_found + ' ""
  • '); no_results_html.find("span").first().html(terms); return this.search_results.append(no_results_html); }; + Chosen.prototype.no_results_clear = function() { return this.search_results.find(".no-results").remove(); }; + Chosen.prototype.keydown_arrow = function() { var first_active, next_sib; if (!this.result_highlight) { first_active = this.search_results.find("li.active-result").first(); - if (first_active) { - this.result_do_highlight($(first_active)); - } + if (first_active) this.result_do_highlight($(first_active)); } else if (this.results_showing) { next_sib = this.result_highlight.nextAll("li.active-result").first(); - if (next_sib) { - this.result_do_highlight(next_sib); - } - } - if (!this.results_showing) { - return this.results_show(); + if (next_sib) this.result_do_highlight(next_sib); } + if (!this.results_showing) return this.results_show(); }; + Chosen.prototype.keyup_arrow = function() { var prev_sibs; if (!this.results_showing && !this.is_multiple) { @@ -799,13 +845,12 @@ if (prev_sibs.length) { return this.result_do_highlight(prev_sibs.first()); } else { - if (this.choices > 0) { - this.results_hide(); - } + if (this.choices > 0) this.results_hide(); return this.result_clear_highlight(); } } }; + Chosen.prototype.keydown_backstroke = function() { if (this.pending_backstroke) { this.choice_destroy(this.pending_backstroke.find("a").first()); @@ -815,27 +860,25 @@ return this.pending_backstroke.addClass("search-choice-focus"); } }; + Chosen.prototype.clear_backstroke = function() { if (this.pending_backstroke) { this.pending_backstroke.removeClass("search-choice-focus"); } return this.pending_backstroke = null; }; + Chosen.prototype.keydown_checker = function(evt) { var stroke, _ref; stroke = (_ref = evt.which) != null ? _ref : evt.keyCode; this.search_field_scale(); - if (stroke !== 8 && this.pending_backstroke) { - this.clear_backstroke(); - } + if (stroke !== 8 && this.pending_backstroke) this.clear_backstroke(); switch (stroke) { case 8: this.backstroke_length = this.search_field.val().length; break; case 9: - if (this.results_showing && !this.is_multiple) { - this.result_select(evt); - } + if (this.results_showing && !this.is_multiple) this.result_select(evt); this.mouse_on_container = false; break; case 13: @@ -850,6 +893,7 @@ break; } }; + Chosen.prototype.search_field_scale = function() { var dd_top, div, h, style, style_block, styles, w, _i, _len; if (this.is_multiple) { @@ -868,9 +912,7 @@ $('body').append(div); w = div.width() + 25; div.remove(); - if (w > this.f_width - 10) { - w = this.f_width - 10; - } + if (w > this.f_width - 10) w = this.f_width - 10; this.search_field.css({ 'width': w + 'px' }); @@ -880,6 +922,7 @@ }); } }; + Chosen.prototype.generate_random_id = function() { var string; string = "sel" + this.generate_random_char() + this.generate_random_char() + this.generate_random_char(); @@ -888,11 +931,16 @@ } return string; }; + return Chosen; - })(); + + })(AbstractChosen); + get_side_border_padding = function(elmt) { var side_border_padding; return side_border_padding = elmt.outerWidth() - elmt.width(); }; + root.get_side_border_padding = get_side_border_padding; + }).call(this); diff --git a/admin/thirdparty/chosen/chosen/chosen.jquery.min.js b/admin/thirdparty/chosen/chosen/chosen.jquery.min.js index 339985189..930fb9a50 100644 --- a/admin/thirdparty/chosen/chosen/chosen.jquery.min.js +++ b/admin/thirdparty/chosen/chosen/chosen.jquery.min.js @@ -1,10 +1,10 @@ // Chosen, a Select Box Enhancer for jQuery and Protoype // by Patrick Filler for Harvest, http://getharvest.com // -// Version 0.9.5 +// Version 0.9.7 // Full source at https://github.com/harvesthq/chosen // Copyright (c) 2011 Harvest http://getharvest.com // MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md // This file is generated by `cake build`, do not edit it by hand. -(function(){var a;a=function(){function a(){this.options_index=0,this.parsed=[]}return a.prototype.add_node=function(a){return a.nodeName==="OPTGROUP"?this.add_group(a):this.add_option(a)},a.prototype.add_group=function(a){var b,c,d,e,f,g;b=this.parsed.length,this.parsed.push({array_index:b,group:!0,label:a.label,children:0,disabled:a.disabled}),f=a.childNodes,g=[];for(d=0,e=f.length;d"+a.html+"")},a.prototype.results_update_field=function(){return this.result_clear_highlight(),this.result_single_selected=null,this.results_build()},a.prototype.results_toggle=function(){return this.results_showing?this.results_hide():this.results_show()},a.prototype.results_search=function(a){return this.results_showing?this.winnow_results():this.results_show()},a.prototype.keyup_checker=function(a){var b,c;b=(c=a.which)!=null?c:a.keyCode,this.search_field_scale();switch(b){case 8:if(this.is_multiple&&this.backstroke_length<1&&this.choices>0)return this.keydown_backstroke();if(!this.pending_backstroke)return this.result_clear_highlight(),this.results_search();break;case 13:a.preventDefault();if(this.results_showing)return this.result_select(a);break;case 27:if(this.results_showing)return this.results_hide();break;case 9:case 38:case 40:case 16:case 91:case 17:break;default:return this.results_search()}},a.prototype.generate_field_id=function(){var a;return a=this.generate_random_id(),this.form_field.id=a,a},a.prototype.generate_random_char=function(){var a,b,c;return a="0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZ",c=Math.floor(Math.random()*a.length),b=a.substring(c,c+1)},a}(),b.AbstractChosen=a}.call(this),function(){var a,b,c,d,e=Object.prototype.hasOwnProperty,f=function(a,b){function d(){this.constructor=a}for(var c in b)e.call(b,c)&&(a[c]=b[c]);return d.prototype=b.prototype,a.prototype=new d,a.__super__=b.prototype,a},g=function(a,b){return function(){return a.apply(b,arguments)}};d=this,a=jQuery,a.fn.extend({chosen:function(c){return!a.browser.msie||a.browser.version!=="6.0"&&a.browser.version!=="7.0"?a(this).each(function(d){if(!a(this).hasClass("chzn-done"))return new b(this,c)}):this}}),b=function(){function b(){b.__super__.constructor.apply(this,arguments)}return f(b,AbstractChosen),b.prototype.setup=function(){return this.form_field_jq=a(this.form_field),this.is_rtl=this.form_field_jq.hasClass("chzn-rtl")},b.prototype.finish_setup=function(){return this.form_field_jq.addClass("chzn-done")},b.prototype.set_up_html=function(){var b,d,e,f;return this.container_id=this.form_field.id.length?this.form_field.id.replace(/(:|\.)/g,"_"):this.generate_field_id(),this.container_id+="_chzn",this.f_width=this.form_field_jq.outerWidth(),this.default_text=this.form_field_jq.data("placeholder")?this.form_field_jq.data("placeholder"):this.default_text_default,b=a("
    ",{id:this.container_id,"class":"chzn-container"+(this.is_rtl?" chzn-rtl":""),style:"width: "+this.f_width+"px;"}),this.is_multiple?b.html('
      '):b.html(''+this.default_text+'
        '),this.form_field_jq.hide().after(b),this.container=a("#"+this.container_id),this.container.addClass("chzn-container-"+(this.is_multiple?"multi":"single")),this.dropdown=this.container.find("div.chzn-drop").first(),d=this.container.height(),e=this.f_width-c(this.dropdown),this.dropdown.css({width:e+"px",top:d+"px"}),this.search_field=this.container.find("input").first(),this.search_results=this.container.find("ul.chzn-results").first(),this.search_field_scale(),this.search_no_results=this.container.find("li.no-results").first(),this.is_multiple?(this.search_choices=this.container.find("ul.chzn-choices").first(),this.search_container=this.container.find("li.search-field").first()):(this.search_container=this.container.find("div.chzn-search").first(),this.selected_item=this.container.find(".chzn-single").first(),f=e-c(this.search_container)-c(this.search_field),this.search_field.css({width:f+"px"})),this.results_build(),this.set_tab_index(),this.form_field_jq.trigger("liszt:ready",{chosen:this})},b.prototype.register_observers=function(){this.container.mousedown(g(function(a){return this.container_mousedown(a)},this)),this.container.mouseup(g(function(a){return this.container_mouseup(a)},this)),this.container.mouseenter(g(function(a){return this.mouse_enter(a)},this)),this.container.mouseleave(g(function(a){return this.mouse_leave(a)},this)),this.search_results.mouseup(g(function(a){return this.search_results_mouseup(a)},this)),this.search_results.mouseover(g(function(a){return this.search_results_mouseover(a)},this)),this.search_results.mouseout(g(function(a){return this.search_results_mouseout(a)},this)),this.form_field_jq.bind("liszt:updated",g(function(a){return this.results_update_field(a)},this)),this.search_field.blur(g(function(a){return this.input_blur(a)},this)),this.search_field.keyup(g(function(a){return this.keyup_checker(a)},this)),this.search_field.keydown(g(function(a){return this.keydown_checker(a)},this));if(this.is_multiple)return this.search_choices.click(g(function(a){return this.choices_click(a)},this)),this.search_field.focus(g(function(a){return this.input_focus(a)},this))},b.prototype.search_field_disabled=function(){this.is_disabled=this.form_field_jq[0].disabled;if(this.is_disabled)return this.container.addClass("chzn-disabled"),this.search_field[0].disabled=!0,this.is_multiple||this.selected_item.unbind("focus",this.activate_action),this.close_field();this.container.removeClass("chzn-disabled"),this.search_field[0].disabled=!1;if(!this.is_multiple)return this.selected_item.bind("focus",this.activate_action)},b.prototype.container_mousedown=function(b){var c;if(!this.is_disabled)return c=b!=null?a(b.target).hasClass("search-choice-close"):!1,b&&b.type==="mousedown"&&b.stopPropagation(),!this.pending_destroy_click&&!c?(this.active_field?!this.is_multiple&&b&&(a(b.target)[0]===this.selected_item[0]||a(b.target).parents("a.chzn-single").length)&&(b.preventDefault(),this.results_toggle()):(this.is_multiple&&this.search_field.val(""),a(document).click(this.click_test_action),this.results_show()),this.activate_field()):this.pending_destroy_click=!1},b.prototype.container_mouseup=function(a){if(a.target.nodeName==="ABBR")return this.results_reset(a)},b.prototype.blur_test=function(a){if(!this.active_field&&this.container.hasClass("chzn-container-active"))return this.close_field()},b.prototype.close_field=function(){return a(document).unbind("click",this.click_test_action),this.is_multiple||(this.selected_item.attr("tabindex",this.search_field.attr("tabindex")),this.search_field.attr("tabindex",-1)),this.active_field=!1,this.results_hide(),this.container.removeClass("chzn-container-active"),this.winnow_results_clear(),this.clear_backstroke(),this.show_search_field_default(),this.search_field_scale()},b.prototype.activate_field=function(){return!this.is_multiple&&!this.active_field&&(this.search_field.attr("tabindex",this.selected_item.attr("tabindex")),this.selected_item.attr("tabindex",-1)),this.container.addClass("chzn-container-active"),this.active_field=!0,this.search_field.val(this.search_field.val()),this.search_field.focus()},b.prototype.test_active_click=function(b){return a(b.target).parents("#"+this.container_id).length?this.active_field=!0:this.close_field()},b.prototype.results_build=function(){var a,b,c,e,f;this.parsing=!0,this.results_data=d.SelectParser.select_to_array(this.form_field),this.is_multiple&&this.choices>0?(this.search_choices.find("li.search-choice").remove(),this.choices=0):this.is_multiple||(this.selected_item.find("span").text(this.default_text),this.form_field.options.length>this.disable_search_threshold?this.container.removeClass("chzn-container-single-nosearch"):this.container.addClass("chzn-container-single-nosearch")),a="",f=this.results_data;for(c=0,e=f.length;c'+a("
        ").text(b.label).html()+"")},b.prototype.result_do_highlight=function(a){var b,c,d,e,f;if(a.length){this.result_clear_highlight(),this.result_highlight=a,this.result_highlight.addClass("highlighted"),d=parseInt(this.search_results.css("maxHeight"),10),f=this.search_results.scrollTop(),e=d+f,c=this.result_highlight.position().top+this.search_results.scrollTop(),b=c+this.result_highlight.outerHeight();if(b>=e)return this.search_results.scrollTop(b-d>0?b-d:0);if(c'+b.html+''),d=a("#"+c).find("a").first(),d.click(g(function(a){return this.choice_destroy_link_click(a)},this))},b.prototype.choice_destroy_link_click=function(b){return b.preventDefault(),this.is_disabled?b.stopPropagation:(this.pending_destroy_click=!0,this.choice_destroy(a(b.target)))},b.prototype.choice_destroy=function(a){return this.choices-=1,this.show_search_field_default(),this.is_multiple&&this.choices>0&&this.search_field.val().length<1&&this.results_hide(),this.result_deselect(a.attr("rel")),a.parents("li").first().remove()},b.prototype.results_reset=function(b){this.form_field.options[0].selected=!0,this.selected_item.find("span").text(this.default_text),this.show_search_field_default(),a(b.target).remove(),this.form_field_jq.trigger("change");if(this.active_field)return this.results_hide()},b.prototype.result_select=function(a){var b,c,d,e;if(this.result_highlight)return b=this.result_highlight,c=b.attr("id"),this.result_clear_highlight(),this.is_multiple?this.result_deactivate(b):(this.search_results.find(".result-selected").removeClass("result-selected"),this.result_single_selected=b),b.addClass("result-selected"),e=c.substr(c.lastIndexOf("_")+1),d=this.results_data[e],d.selected=!0,this.form_field.options[d.options_index].selected=!0,this.is_multiple?this.choice_build(d):(this.selected_item.find("span").first().text(d.text),this.allow_single_deselect&&this.single_deselect_control_build()),(!a.metaKey||!this.is_multiple)&&this.results_hide(),this.search_field.val(""),this.form_field_jq.trigger("change"),this.search_field_scale()},b.prototype.result_activate=function(a){return a.addClass("active-result")},b.prototype.result_deactivate=function(a){return a.removeClass("active-result")},b.prototype.result_deselect=function(b){var c,d;return d=this.results_data[b],d.selected=!1,this.form_field.options[d.options_index].selected=!1,c=a("#"+this.container_id+"_o_"+b),c.removeClass("result-selected").addClass("active-result").show(),this.result_clear_highlight(),this.winnow_results(),this.form_field_jq.trigger("change"),this.search_field_scale()},b.prototype.single_deselect_control_build=function(){if(this.allow_single_deselect&&this.selected_item.find("abbr").length<1)return this.selected_item.find("span").first().after('')},b.prototype.winnow_results=function(){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r;this.no_results_clear(),i=0,j=this.search_field.val()===this.default_text?"":a("
        ").text(a.trim(this.search_field.val())).html(),f=new RegExp("^"+j.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),"i"),m=new RegExp(j.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),"i"),r=this.results_data;for(n=0,p=r.length;n=0||c.html.indexOf("[")===0){e=c.html.replace(/\[|\]/g,"").split(" ");if(e.length)for(o=0,q=e.length;o"+c.html.substr(k+j.length),l=l.substr(0,k)+""+l.substr(k)):l=c.html,g.html(l),this.result_activate(g),c.group_array_index!=null&&a("#"+this.results_data[c.group_array_index].dom_id).css("display","list-item")):(this.result_highlight&&h===this.result_highlight.attr("id")&&this.result_clear_highlight(),this.result_deactivate(g))}}return i<1&&j.length?this.no_results(j):this.winnow_results_set_highlight()},b.prototype.winnow_results_clear=function(){var b,c,d,e,f;this.search_field.val(""),c=this.search_results.find("li"),f=[];for(d=0,e=c.length;d'+this.results_none_found+' ""'),c.find("span").first().html(b),this.search_results.append(c)},b.prototype.no_results_clear=function(){return this.search_results.find(".no-results").remove()},b.prototype.keydown_arrow=function(){var b,c;this.result_highlight?this.results_showing&&(c=this.result_highlight.nextAll("li.active-result").first(),c&&this.result_do_highlight(c)):(b=this.search_results.find("li.active-result").first(),b&&this.result_do_highlight(a(b)));if(!this.results_showing)return this.results_show()},b.prototype.keyup_arrow=function(){var a;if(!this.results_showing&&!this.is_multiple)return this.results_show();if(this.result_highlight)return a=this.result_highlight.prevAll("li.active-result"),a.length?this.result_do_highlight(a.first()):(this.choices>0&&this.results_hide(),this.result_clear_highlight())},b.prototype.keydown_backstroke=function(){return this.pending_backstroke?(this.choice_destroy(this.pending_backstroke.find("a").first()),this.clear_backstroke()):(this.pending_backstroke=this.search_container.siblings("li.search-choice").last(),this.pending_backstroke.addClass("search-choice-focus"))},b.prototype.clear_backstroke=function(){return this.pending_backstroke&&this.pending_backstroke.removeClass("search-choice-focus"),this.pending_backstroke=null},b.prototype.keydown_checker=function(a){var b,c;b=(c=a.which)!=null?c:a.keyCode,this.search_field_scale(),b!==8&&this.pending_backstroke&&this.clear_backstroke();switch(b){case 8:this.backstroke_length=this.search_field.val().length;break;case 9:this.results_showing&&!this.is_multiple&&this.result_select(a),this.mouse_on_container=!1;break;case 13:a.preventDefault();break;case 38:a.preventDefault(),this.keyup_arrow();break;case 40:this.keydown_arrow()}},b.prototype.search_field_scale=function(){var b,c,d,e,f,g,h,i,j;if(this.is_multiple){d=0,h=0,f="position:absolute; left: -1000px; top: -1000px; display:none;",g=["font-size","font-style","font-weight","font-family","line-height","text-transform","letter-spacing"];for(i=0,j=g.length;i",{style:f}),c.text(this.search_field.val()),a("body").append(c),h=c.width()+25,c.remove(),h>this.f_width-10&&(h=this.f_width-10),this.search_field.css({width:h+"px"}),b=this.container.height(),this.dropdown.css({top:b+"px"})}},b.prototype.generate_random_id=function(){var b;b="sel"+this.generate_random_char()+this.generate_random_char()+this.generate_random_char();while(a("#"+b).length>0)b+=this.generate_random_char();return b},b}(),c=function(a){var b;return b=a.outerWidth()-a.width()},d.get_side_border_padding=c}.call(this) \ No newline at end of file +((function(){var a;a=function(){function a(){this.options_index=0,this.parsed=[]}return a.prototype.add_node=function(a){return a.nodeName==="OPTGROUP"?this.add_group(a):this.add_option(a)},a.prototype.add_group=function(a){var b,c,d,e,f,g;b=this.parsed.length,this.parsed.push({array_index:b,group:!0,label:a.label,children:0,disabled:a.disabled}),f=a.childNodes,g=[];for(d=0,e=f.length;d"+a.html+"")},a.prototype.results_update_field=function(){return this.result_clear_highlight(),this.result_single_selected=null,this.results_build()},a.prototype.results_toggle=function(){return this.results_showing?this.results_hide():this.results_show()},a.prototype.results_search=function(a){return this.results_showing?this.winnow_results():this.results_show()},a.prototype.keyup_checker=function(a){var b,c;b=(c=a.which)!=null?c:a.keyCode,this.search_field_scale();switch(b){case 8:if(this.is_multiple&&this.backstroke_length<1&&this.choices>0)return this.keydown_backstroke();if(!this.pending_backstroke)return this.result_clear_highlight(),this.results_search();break;case 13:a.preventDefault();if(this.results_showing)return this.result_select(a);break;case 27:return this.results_showing&&this.results_hide(),!0;case 9:case 38:case 40:case 16:case 91:case 17:break;default:return this.results_search()}},a.prototype.generate_field_id=function(){var a;return a=this.generate_random_id(),this.form_field.id=a,a},a.prototype.generate_random_char=function(){var a,b,c;return a="0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZ",c=Math.floor(Math.random()*a.length),b=a.substring(c,c+1)},a}(),b.AbstractChosen=a}.call(this),function(){var a,b,c,d,e=Object.prototype.hasOwnProperty,f=function(a,b){function d(){this.constructor=a}for(var c in b)e.call(b,c)&&(a[c]=b[c]);return d.prototype=b.prototype,a.prototype=new d,a.__super__=b.prototype,a};d=this,a=jQuery,a.fn.extend({chosen:function(c){return!a.browser.msie||a.browser.version!=="6.0"&&a.browser.version!=="7.0"?a(this).each(function(d){if(!a(this).hasClass("chzn-done"))return new b(this,c)}):this}}),b=function(b){function e(){e.__super__.constructor.apply(this,arguments)}return f(e,b),e.prototype.setup=function(){return this.form_field_jq=a(this.form_field),this.is_rtl=this.form_field_jq.hasClass("chzn-rtl")},e.prototype.finish_setup=function(){return this.form_field_jq.addClass("chzn-done")},e.prototype.set_up_html=function(){var b,d,e,f;return this.container_id=this.form_field.id.length?this.form_field.id.replace(/(:|\.)/g,"_"):this.generate_field_id(),this.container_id+="_chzn",this.f_width=this.form_field_jq.outerWidth(),this.default_text=this.form_field_jq.data("placeholder")?this.form_field_jq.data("placeholder"):this.default_text_default,b=a("
        ",{id:this.container_id,"class":"chzn-container"+(this.is_rtl?" chzn-rtl":""),style:"width: "+this.f_width+"px;"}),this.is_multiple?b.html('
          '):b.html(''+this.default_text+'
            '),this.form_field_jq.hide().after(b),this.container=a("#"+this.container_id),this.container.addClass("chzn-container-"+(this.is_multiple?"multi":"single")),this.dropdown=this.container.find("div.chzn-drop").first(),d=this.container.height(),e=this.f_width-c(this.dropdown),this.dropdown.css({width:e+"px",top:d+"px"}),this.search_field=this.container.find("input").first(),this.search_results=this.container.find("ul.chzn-results").first(),this.search_field_scale(),this.search_no_results=this.container.find("li.no-results").first(),this.is_multiple?(this.search_choices=this.container.find("ul.chzn-choices").first(),this.search_container=this.container.find("li.search-field").first()):(this.search_container=this.container.find("div.chzn-search").first(),this.selected_item=this.container.find(".chzn-single").first(),f=e-c(this.search_container)-c(this.search_field),this.search_field.css({width:f+"px"})),this.results_build(),this.set_tab_index(),this.form_field_jq.trigger("liszt:ready",{chosen:this})},e.prototype.register_observers=function(){var a=this;return this.container.mousedown(function(b){return a.container_mousedown(b)}),this.container.mouseup(function(b){return a.container_mouseup(b)}),this.container.mouseenter(function(b){return a.mouse_enter(b)}),this.container.mouseleave(function(b){return a.mouse_leave(b)}),this.search_results.mouseup(function(b){return a.search_results_mouseup(b)}),this.search_results.mouseover(function(b){return a.search_results_mouseover(b)}),this.search_results.mouseout(function(b){return a.search_results_mouseout(b)}),this.form_field_jq.bind("liszt:updated",function(b){return a.results_update_field(b)}),this.search_field.blur(function(b){return a.input_blur(b)}),this.search_field.keyup(function(b){return a.keyup_checker(b)}),this.search_field.keydown(function(b){return a.keydown_checker(b)}),this.is_multiple?(this.search_choices.click(function(b){return a.choices_click(b)}),this.search_field.focus(function(b){return a.input_focus(b)})):this.container.click(function(a){return a.preventDefault()})},e.prototype.search_field_disabled=function(){this.is_disabled=this.form_field_jq[0].disabled;if(this.is_disabled)return this.container.addClass("chzn-disabled"),this.search_field[0].disabled=!0,this.is_multiple||this.selected_item.unbind("focus",this.activate_action),this.close_field();this.container.removeClass("chzn-disabled"),this.search_field[0].disabled=!1;if(!this.is_multiple)return this.selected_item.bind("focus",this.activate_action)},e.prototype.container_mousedown=function(b){var c;if(!this.is_disabled)return c=b!=null?a(b.target).hasClass("search-choice-close"):!1,b&&b.type==="mousedown"&&b.stopPropagation(),!this.pending_destroy_click&&!c?(this.active_field?!this.is_multiple&&b&&(a(b.target)[0]===this.selected_item[0]||a(b.target).parents("a.chzn-single").length)&&(b.preventDefault(),this.results_toggle()):(this.is_multiple&&this.search_field.val(""),a(document).click(this.click_test_action),this.results_show()),this.activate_field()):this.pending_destroy_click=!1},e.prototype.container_mouseup=function(a){if(a.target.nodeName==="ABBR")return this.results_reset(a)},e.prototype.blur_test=function(a){if(!this.active_field&&this.container.hasClass("chzn-container-active"))return this.close_field()},e.prototype.close_field=function(){return a(document).unbind("click",this.click_test_action),this.is_multiple||(this.selected_item.attr("tabindex",this.search_field.attr("tabindex")),this.search_field.attr("tabindex",-1)),this.active_field=!1,this.results_hide(),this.container.removeClass("chzn-container-active"),this.winnow_results_clear(),this.clear_backstroke(),this.show_search_field_default(),this.search_field_scale()},e.prototype.activate_field=function(){return!this.is_multiple&&!this.active_field&&(this.search_field.attr("tabindex",this.selected_item.attr("tabindex")),this.selected_item.attr("tabindex",-1)),this.container.addClass("chzn-container-active"),this.active_field=!0,this.search_field.val(this.search_field.val()),this.search_field.focus()},e.prototype.test_active_click=function(b){return a(b.target).parents("#"+this.container_id).length?this.active_field=!0:this.close_field()},e.prototype.results_build=function(){var a,b,c,e,f;this.parsing=!0,this.results_data=d.SelectParser.select_to_array(this.form_field),this.is_multiple&&this.choices>0?(this.search_choices.find("li.search-choice").remove(),this.choices=0):this.is_multiple||(this.selected_item.find("span").text(this.default_text),this.form_field.options.length<=this.disable_search_threshold?this.container.addClass("chzn-container-single-nosearch"):this.container.removeClass("chzn-container-single-nosearch")),a="",f=this.results_data;for(c=0,e=f.length;c'+a("
            ").text(b.label).html()+"")},e.prototype.result_do_highlight=function(a){var b,c,d,e,f;if(a.length){this.result_clear_highlight(),this.result_highlight=a,this.result_highlight.addClass("highlighted"),d=parseInt(this.search_results.css("maxHeight"),10),f=this.search_results.scrollTop(),e=d+f,c=this.result_highlight.position().top+this.search_results.scrollTop(),b=c+this.result_highlight.outerHeight();if(b>=e)return this.search_results.scrollTop(b-d>0?b-d:0);if(c'+b.html+''),d=a("#"+c).find("a").first(),d.click(function(a){return e.choice_destroy_link_click(a)})},e.prototype.choice_destroy_link_click=function(b){return b.preventDefault(),this.is_disabled?b.stopPropagation:(this.pending_destroy_click=!0,this.choice_destroy(a(b.target)))},e.prototype.choice_destroy=function(a){return this.choices-=1,this.show_search_field_default(),this.is_multiple&&this.choices>0&&this.search_field.val().length<1&&this.results_hide(),this.result_deselect(a.attr("rel")),a.parents("li").first().remove()},e.prototype.results_reset=function(b){this.form_field.options[0].selected=!0,this.selected_item.find("span").text(this.default_text),this.show_search_field_default(),a(b.target).remove(),this.form_field_jq.trigger("change");if(this.active_field)return this.results_hide()},e.prototype.result_select=function(a){var b,c,d,e;if(this.result_highlight)return b=this.result_highlight,c=b.attr("id"),this.result_clear_highlight(),this.is_multiple?this.result_deactivate(b):(this.search_results.find(".result-selected").removeClass("result-selected"),this.result_single_selected=b),b.addClass("result-selected"),e=c.substr(c.lastIndexOf("_")+1),d=this.results_data[e],d.selected=!0,this.form_field.options[d.options_index].selected=!0,this.is_multiple?this.choice_build(d):(this.selected_item.find("span").first().text(d.text),this.allow_single_deselect&&this.single_deselect_control_build()),(!a.metaKey||!this.is_multiple)&&this.results_hide(),this.search_field.val(""),this.form_field_jq.trigger("change"),this.search_field_scale()},e.prototype.result_activate=function(a){return a.addClass("active-result")},e.prototype.result_deactivate=function(a){return a.removeClass("active-result")},e.prototype.result_deselect=function(b){var c,d;return d=this.results_data[b],d.selected=!1,this.form_field.options[d.options_index].selected=!1,c=a("#"+this.container_id+"_o_"+b),c.removeClass("result-selected").addClass("active-result").show(),this.result_clear_highlight(),this.winnow_results(),this.form_field_jq.trigger("change"),this.search_field_scale()},e.prototype.single_deselect_control_build=function(){if(this.allow_single_deselect&&this.selected_item.find("abbr").length<1)return this.selected_item.find("span").first().after('')},e.prototype.winnow_results=function(){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r;this.no_results_clear(),i=0,j=this.search_field.val()===this.default_text?"":a("
            ").text(a.trim(this.search_field.val())).html(),f=new RegExp("^"+j.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),"i"),m=new RegExp(j.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),"i"),r=this.results_data;for(n=0,p=r.length;n=0||c.html.indexOf("[")===0){e=c.html.replace(/\[|\]/g,"").split(" ");if(e.length)for(o=0,q=e.length;o"+c.html.substr(k+j.length),l=l.substr(0,k)+""+l.substr(k)):l=c.html,g.html(l),this.result_activate(g),c.group_array_index!=null&&a("#"+this.results_data[c.group_array_index].dom_id).css("display","list-item")):(this.result_highlight&&h===this.result_highlight.attr("id")&&this.result_clear_highlight(),this.result_deactivate(g))}}return i<1&&j.length?this.no_results(j):this.winnow_results_set_highlight()},e.prototype.winnow_results_clear=function(){var b,c,d,e,f;this.search_field.val(""),c=this.search_results.find("li"),f=[];for(d=0,e=c.length;d'+this.results_none_found+' ""'),c.find("span").first().html(b),this.search_results.append(c)},e.prototype.no_results_clear=function(){return this.search_results.find(".no-results").remove()},e.prototype.keydown_arrow=function(){var b,c;this.result_highlight?this.results_showing&&(c=this.result_highlight.nextAll("li.active-result").first(),c&&this.result_do_highlight(c)):(b=this.search_results.find("li.active-result").first(),b&&this.result_do_highlight(a(b)));if(!this.results_showing)return this.results_show()},e.prototype.keyup_arrow=function(){var a;if(!this.results_showing&&!this.is_multiple)return this.results_show();if(this.result_highlight)return a=this.result_highlight.prevAll("li.active-result"),a.length?this.result_do_highlight(a.first()):(this.choices>0&&this.results_hide(),this.result_clear_highlight())},e.prototype.keydown_backstroke=function(){return this.pending_backstroke?(this.choice_destroy(this.pending_backstroke.find("a").first()),this.clear_backstroke()):(this.pending_backstroke=this.search_container.siblings("li.search-choice").last(),this.pending_backstroke.addClass("search-choice-focus"))},e.prototype.clear_backstroke=function(){return this.pending_backstroke&&this.pending_backstroke.removeClass("search-choice-focus"),this.pending_backstroke=null},e.prototype.keydown_checker=function(a){var b,c;b=(c=a.which)!=null?c:a.keyCode,this.search_field_scale(),b!==8&&this.pending_backstroke&&this.clear_backstroke();switch(b){case 8:this.backstroke_length=this.search_field.val().length;break;case 9:this.results_showing&&!this.is_multiple&&this.result_select(a),this.mouse_on_container=!1;break;case 13:a.preventDefault();break;case 38:a.preventDefault(),this.keyup_arrow();break;case 40:this.keydown_arrow()}},e.prototype.search_field_scale=function(){var b,c,d,e,f,g,h,i,j;if(this.is_multiple){d=0,h=0,f="position:absolute; left: -1000px; top: -1000px; display:none;",g=["font-size","font-style","font-weight","font-family","line-height","text-transform","letter-spacing"];for(i=0,j=g.length;i",{style:f}),c.text(this.search_field.val()),a("body").append(c),h=c.width()+25,c.remove(),h>this.f_width-10&&(h=this.f_width-10),this.search_field.css({width:h+"px"}),b=this.container.height(),this.dropdown.css({top:b+"px"})}},e.prototype.generate_random_id=function(){var b;b="sel"+this.generate_random_char()+this.generate_random_char()+this.generate_random_char();while(a("#"+b).length>0)b+=this.generate_random_char();return b},e}(AbstractChosen),c=function(a){var b;return b=a.outerWidth()-a.width()},d.get_side_border_padding=c}.call(this) \ No newline at end of file diff --git a/admin/thirdparty/chosen/chosen/chosen.proto.js b/admin/thirdparty/chosen/chosen/chosen.proto.js index aec1c7fa8..e141a6924 100644 --- a/admin/thirdparty/chosen/chosen/chosen.proto.js +++ b/admin/thirdparty/chosen/chosen/chosen.proto.js @@ -1,7 +1,7 @@ // Chosen, a Select Box Enhancer for jQuery and Protoype // by Patrick Filler for Harvest, http://getharvest.com // -// Version 0.9.5 +// Version 0.9.7 // Full source at https://github.com/harvesthq/chosen // Copyright (c) 2011 Harvest http://getharvest.com @@ -9,11 +9,14 @@ // This file is generated by `cake build`, do not edit it by hand. (function() { var SelectParser; + SelectParser = (function() { + function SelectParser() { this.options_index = 0; this.parsed = []; } + SelectParser.prototype.add_node = function(child) { if (child.nodeName === "OPTGROUP") { return this.add_group(child); @@ -21,6 +24,7 @@ return this.add_option(child); } }; + SelectParser.prototype.add_group = function(group) { var group_position, option, _i, _len, _ref, _results; group_position = this.parsed.length; @@ -39,12 +43,11 @@ } return _results; }; + SelectParser.prototype.add_option = function(option, group_position, group_disabled) { if (option.nodeName === "OPTION") { if (option.text !== "") { - if (group_position != null) { - this.parsed[group_position].children += 1; - } + if (group_position != null) this.parsed[group_position].children += 1; this.parsed.push({ array_index: this.parsed.length, options_index: this.options_index, @@ -67,8 +70,11 @@ return this.options_index += 1; } }; + return SelectParser; + })(); + SelectParser.select_to_array = function(select) { var child, parser, _i, _len, _ref; parser = new SelectParser(); @@ -79,17 +85,23 @@ } return parser.parsed; }; + this.SelectParser = SelectParser; + }).call(this); + +/* +Chosen source: generate output using 'cake build' +Copyright (c) 2011 by Harvest +*/ + (function() { - /* - Chosen source: generate output using 'cake build' - Copyright (c) 2011 by Harvest - */ var AbstractChosen, root; - var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + root = this; + AbstractChosen = (function() { + function AbstractChosen(form_field, options) { this.form_field = form_field; this.options = options != null ? options : {}; @@ -101,13 +113,15 @@ this.register_observers(); this.finish_setup(); } + AbstractChosen.prototype.set_default_values = function() { - this.click_test_action = __bind(function(evt) { - return this.test_active_click(evt); - }, this); - this.activate_action = __bind(function(evt) { - return this.activate_field(evt); - }, this); + var _this = this; + this.click_test_action = function(evt) { + return _this.test_active_click(evt); + }; + this.activate_action = function(evt) { + return _this.activate_field(evt); + }; this.active_field = false; this.mouse_on_container = false; this.results_showing = false; @@ -118,52 +132,55 @@ this.choices = 0; return this.results_none_found = this.options.no_results_text || "No results match"; }; + AbstractChosen.prototype.mouse_enter = function() { return this.mouse_on_container = true; }; + AbstractChosen.prototype.mouse_leave = function() { return this.mouse_on_container = false; }; + AbstractChosen.prototype.input_focus = function(evt) { + var _this = this; if (!this.active_field) { - return setTimeout((__bind(function() { - return this.container_mousedown(); - }, this)), 50); + return setTimeout((function() { + return _this.container_mousedown(); + }), 50); } }; + AbstractChosen.prototype.input_blur = function(evt) { + var _this = this; if (!this.mouse_on_container) { this.active_field = false; - return setTimeout((__bind(function() { - return this.blur_test(); - }, this)), 100); + return setTimeout((function() { + return _this.blur_test(); + }), 100); } }; + AbstractChosen.prototype.result_add_option = function(option) { var classes, style; if (!option.disabled) { option.dom_id = this.container_id + "_o_" + option.array_index; classes = option.selected && this.is_multiple ? [] : ["active-result"]; - if (option.selected) { - classes.push("result-selected"); - } - if (option.group_array_index != null) { - classes.push("group-option"); - } - if (option.classes !== "") { - classes.push(option.classes); - } + if (option.selected) classes.push("result-selected"); + if (option.group_array_index != null) classes.push("group-option"); + if (option.classes !== "") classes.push(option.classes); style = option.style.cssText !== "" ? " style=\"" + option.style + "\"" : ""; return '
          • ' + option.html + '
          • '; } else { return ""; } }; + AbstractChosen.prototype.results_update_field = function() { this.result_clear_highlight(); this.result_single_selected = null; return this.results_build(); }; + AbstractChosen.prototype.results_toggle = function() { if (this.results_showing) { return this.results_hide(); @@ -171,6 +188,7 @@ return this.results_show(); } }; + AbstractChosen.prototype.results_search = function(evt) { if (this.results_showing) { return this.winnow_results(); @@ -178,6 +196,7 @@ return this.results_show(); } }; + AbstractChosen.prototype.keyup_checker = function(evt) { var stroke, _ref; stroke = (_ref = evt.which) != null ? _ref : evt.keyCode; @@ -193,15 +212,11 @@ break; case 13: evt.preventDefault(); - if (this.results_showing) { - return this.result_select(evt); - } + if (this.results_showing) return this.result_select(evt); break; case 27: - if (this.results_showing) { - return this.results_hide(); - } - break; + if (this.results_showing) this.results_hide(); + return true; case 9: case 38: case 40: @@ -213,48 +228,57 @@ return this.results_search(); } }; + AbstractChosen.prototype.generate_field_id = function() { var new_id; new_id = this.generate_random_id(); this.form_field.id = new_id; return new_id; }; + AbstractChosen.prototype.generate_random_char = function() { var chars, newchar, rand; chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZ"; rand = Math.floor(Math.random() * chars.length); return newchar = chars.substring(rand, rand + 1); }; + return AbstractChosen; + })(); + root.AbstractChosen = AbstractChosen; + }).call(this); + +/* +Chosen source: generate output using 'cake build' +Copyright (c) 2011 by Harvest +*/ + (function() { - /* - Chosen source: generate output using 'cake build' - Copyright (c) 2011 by Harvest - */ - var Chosen, get_side_border_padding, root; - var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { - for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } - function ctor() { this.constructor = child; } - ctor.prototype = parent.prototype; - child.prototype = new ctor; - child.__super__ = parent.prototype; - return child; - }, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + var Chosen, get_side_border_padding, root, + __hasProp = Object.prototype.hasOwnProperty, + __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; }; + root = this; - Chosen = (function() { - __extends(Chosen, AbstractChosen); + + Chosen = (function(_super) { + + __extends(Chosen, _super); + function Chosen() { Chosen.__super__.constructor.apply(this, arguments); } + Chosen.prototype.setup = function() { return this.is_rtl = this.form_field.hasClassName("chzn-rtl"); }; + Chosen.prototype.finish_setup = function() { return this.form_field.addClassName("chzn-done"); }; + Chosen.prototype.set_default_values = function() { Chosen.__super__.set_default_values.call(this); this.single_temp = new Template('#{default}
              '); @@ -262,6 +286,7 @@ this.choice_temp = new Template('
            • #{choice}
            • '); return this.no_results_temp = new Template('
            • ' + this.results_none_found + ' "#{terms}"
            • '); }; + Chosen.prototype.set_up_html = function() { var base_template, container_props, dd_top, dd_width, sf_width; this.container_id = this.form_field.identify().replace(/(:|\.)/g, '_') + "_chzn"; @@ -310,49 +335,56 @@ chosen: this }); }; + Chosen.prototype.register_observers = function() { - this.container.observe("mousedown", __bind(function(evt) { - return this.container_mousedown(evt); - }, this)); - this.container.observe("mouseup", __bind(function(evt) { - return this.container_mouseup(evt); - }, this)); - this.container.observe("mouseenter", __bind(function(evt) { - return this.mouse_enter(evt); - }, this)); - this.container.observe("mouseleave", __bind(function(evt) { - return this.mouse_leave(evt); - }, this)); - this.search_results.observe("mouseup", __bind(function(evt) { - return this.search_results_mouseup(evt); - }, this)); - this.search_results.observe("mouseover", __bind(function(evt) { - return this.search_results_mouseover(evt); - }, this)); - this.search_results.observe("mouseout", __bind(function(evt) { - return this.search_results_mouseout(evt); - }, this)); - this.form_field.observe("liszt:updated", __bind(function(evt) { - return this.results_update_field(evt); - }, this)); - this.search_field.observe("blur", __bind(function(evt) { - return this.input_blur(evt); - }, this)); - this.search_field.observe("keyup", __bind(function(evt) { - return this.keyup_checker(evt); - }, this)); - this.search_field.observe("keydown", __bind(function(evt) { - return this.keydown_checker(evt); - }, this)); + var _this = this; + this.container.observe("mousedown", function(evt) { + return _this.container_mousedown(evt); + }); + this.container.observe("mouseup", function(evt) { + return _this.container_mouseup(evt); + }); + this.container.observe("mouseenter", function(evt) { + return _this.mouse_enter(evt); + }); + this.container.observe("mouseleave", function(evt) { + return _this.mouse_leave(evt); + }); + this.search_results.observe("mouseup", function(evt) { + return _this.search_results_mouseup(evt); + }); + this.search_results.observe("mouseover", function(evt) { + return _this.search_results_mouseover(evt); + }); + this.search_results.observe("mouseout", function(evt) { + return _this.search_results_mouseout(evt); + }); + this.form_field.observe("liszt:updated", function(evt) { + return _this.results_update_field(evt); + }); + this.search_field.observe("blur", function(evt) { + return _this.input_blur(evt); + }); + this.search_field.observe("keyup", function(evt) { + return _this.keyup_checker(evt); + }); + this.search_field.observe("keydown", function(evt) { + return _this.keydown_checker(evt); + }); if (this.is_multiple) { - this.search_choices.observe("click", __bind(function(evt) { - return this.choices_click(evt); - }, this)); - return this.search_field.observe("focus", __bind(function(evt) { - return this.input_focus(evt); - }, this)); + this.search_choices.observe("click", function(evt) { + return _this.choices_click(evt); + }); + return this.search_field.observe("focus", function(evt) { + return _this.input_focus(evt); + }); + } else { + return this.container.observe("click", function(evt) { + return evt.preventDefault(); + }); } }; + Chosen.prototype.search_field_disabled = function() { this.is_disabled = this.form_field.disabled; if (this.is_disabled) { @@ -370,18 +402,15 @@ } } }; + Chosen.prototype.container_mousedown = function(evt) { var target_closelink; if (!this.is_disabled) { target_closelink = evt != null ? evt.target.hasClassName("search-choice-close") : false; - if (evt && evt.type === "mousedown") { - evt.stop(); - } + if (evt && evt.type === "mousedown") evt.stop(); if (!this.pending_destroy_click && !target_closelink) { if (!this.active_field) { - if (this.is_multiple) { - this.search_field.clear(); - } + if (this.is_multiple) this.search_field.clear(); document.observe("click", this.click_test_action); this.results_show(); } else if (!this.is_multiple && evt && (evt.target === this.selected_item || evt.target.up("a.chzn-single"))) { @@ -393,16 +422,17 @@ } } }; + Chosen.prototype.container_mouseup = function(evt) { - if (evt.target.nodeName === "ABBR") { - return this.results_reset(evt); - } + if (evt.target.nodeName === "ABBR") return this.results_reset(evt); }; + Chosen.prototype.blur_test = function(evt) { if (!this.active_field && this.container.hasClassName("chzn-container-active")) { return this.close_field(); } }; + Chosen.prototype.close_field = function() { document.stopObserving("click", this.click_test_action); if (!this.is_multiple) { @@ -417,6 +447,7 @@ this.show_search_field_default(); return this.search_field_scale(); }; + Chosen.prototype.activate_field = function() { if (!this.is_multiple && !this.active_field) { this.search_field.tabIndex = this.selected_item.tabIndex; @@ -427,6 +458,7 @@ this.search_field.value = this.search_field.value; return this.search_field.focus(); }; + Chosen.prototype.test_active_click = function(evt) { if (evt.target.up('#' + this.container_id)) { return this.active_field = true; @@ -434,6 +466,7 @@ return this.close_field(); } }; + Chosen.prototype.results_build = function() { var content, data, _i, _len, _ref; this.parsing = true; @@ -461,9 +494,7 @@ this.choice_build(data); } else if (data.selected && !this.is_multiple) { this.selected_item.down("span").update(data.html); - if (this.allow_single_deselect) { - this.single_deselect_control_build(); - } + if (this.allow_single_deselect) this.single_deselect_control_build(); } } } @@ -473,6 +504,7 @@ this.search_results.update(content); return this.parsing = false; }; + Chosen.prototype.result_add_group = function(group) { if (!group.disabled) { group.dom_id = this.container_id + "_g_" + group.array_index; @@ -481,6 +513,7 @@ return ""; } }; + Chosen.prototype.result_do_highlight = function(el) { var high_bottom, high_top, maxHeight, visible_bottom, visible_top; this.result_clear_highlight(); @@ -497,12 +530,14 @@ return this.search_results.scrollTop = high_top; } }; + Chosen.prototype.result_clear_highlight = function() { if (this.result_highlight) { this.result_highlight.removeClassName('highlighted'); } return this.result_highlight = null; }; + Chosen.prototype.results_show = function() { var dd_top; if (!this.is_multiple) { @@ -521,6 +556,7 @@ this.search_field.value = this.search_field.value; return this.winnow_results(); }; + Chosen.prototype.results_hide = function() { if (!this.is_multiple) { this.selected_item.removeClassName('chzn-single-with-drop'); @@ -531,6 +567,7 @@ }); return this.results_showing = false; }; + Chosen.prototype.set_tab_index = function(el) { var ti; if (this.form_field.tabIndex) { @@ -544,6 +581,7 @@ } } }; + Chosen.prototype.show_search_field_default = function() { if (this.is_multiple && this.choices < 1 && !this.active_field) { this.search_field.value = this.default_text; @@ -553,6 +591,7 @@ return this.search_field.removeClassName("default"); } }; + Chosen.prototype.search_results_mouseup = function(evt) { var target; target = evt.target.hasClassName("active-result") ? evt.target : evt.target.up(".active-result"); @@ -561,26 +600,29 @@ return this.result_select(evt); } }; + Chosen.prototype.search_results_mouseover = function(evt) { var target; target = evt.target.hasClassName("active-result") ? evt.target : evt.target.up(".active-result"); - if (target) { - return this.result_do_highlight(target); - } + if (target) return this.result_do_highlight(target); }; + Chosen.prototype.search_results_mouseout = function(evt) { if (evt.target.hasClassName('active-result') || evt.target.up('.active-result')) { return this.result_clear_highlight(); } }; + Chosen.prototype.choices_click = function(evt) { evt.preventDefault(); if (this.active_field && !(evt.target.hasClassName('search-choice') || evt.target.up('.search-choice')) && !this.results_showing) { return this.results_show(); } }; + Chosen.prototype.choice_build = function(item) { - var choice_id, link; + var choice_id, link, + _this = this; choice_id = this.container_id + "_c_" + item.array_index; this.choices += 1; this.search_container.insert({ @@ -591,10 +633,11 @@ }) }); link = $(choice_id).down('a'); - return link.observe("click", __bind(function(evt) { - return this.choice_destroy_link_click(evt); - }, this)); + return link.observe("click", function(evt) { + return _this.choice_destroy_link_click(evt); + }); }; + Chosen.prototype.choice_destroy_link_click = function(evt) { evt.preventDefault(); if (!this.is_disabled) { @@ -602,6 +645,7 @@ return this.choice_destroy(evt.target); } }; + Chosen.prototype.choice_destroy = function(link) { this.choices -= 1; this.show_search_field_default(); @@ -611,18 +655,16 @@ this.result_deselect(link.readAttribute("rel")); return link.up('li').remove(); }; + Chosen.prototype.results_reset = function(evt) { this.form_field.options[0].selected = true; this.selected_item.down("span").update(this.default_text); this.show_search_field_default(); evt.target.remove(); - if (typeof Event.simulate === 'function') { - this.form_field.simulate("change"); - } - if (this.active_field) { - return this.results_hide(); - } + if (typeof Event.simulate === 'function') this.form_field.simulate("change"); + if (this.active_field) return this.results_hide(); }; + Chosen.prototype.result_select = function(evt) { var high, item, position; if (this.result_highlight) { @@ -643,13 +685,9 @@ this.choice_build(item); } else { this.selected_item.down("span").update(item.html); - if (this.allow_single_deselect) { - this.single_deselect_control_build(); - } - } - if (!(evt.metaKey && this.is_multiple)) { - this.results_hide(); + if (this.allow_single_deselect) this.single_deselect_control_build(); } + if (!(evt.metaKey && this.is_multiple)) this.results_hide(); this.search_field.value = ""; if (typeof Event.simulate === 'function') { this.form_field.simulate("change"); @@ -657,12 +695,15 @@ return this.search_field_scale(); } }; + Chosen.prototype.result_activate = function(el) { return el.addClassName("active-result"); }; + Chosen.prototype.result_deactivate = function(el) { return el.removeClassName("active-result"); }; + Chosen.prototype.result_deselect = function(pos) { var result, result_data; result_data = this.results_data[pos]; @@ -672,11 +713,10 @@ result.removeClassName("result-selected").addClassName("active-result").show(); this.result_clear_highlight(); this.winnow_results(); - if (typeof Event.simulate === 'function') { - this.form_field.simulate("change"); - } + if (typeof Event.simulate === 'function') this.form_field.simulate("change"); return this.search_field_scale(); }; + Chosen.prototype.single_deselect_control_build = function() { if (this.allow_single_deselect && !this.selected_item.down("abbr")) { return this.selected_item.down("span").insert({ @@ -684,6 +724,7 @@ }); } }; + Chosen.prototype.winnow_results = function() { var found, option, part, parts, regex, result_id, results, searchText, startpos, text, zregex, _i, _j, _len, _len2, _ref; this.no_results_clear(); @@ -723,9 +764,7 @@ } else { text = option.html; } - if ($(result_id).innerHTML !== text) { - $(result_id).update(text); - } + if ($(result_id).innerHTML !== text) $(result_id).update(text); this.result_activate($(result_id)); if (option.group_array_index != null) { $(this.results_data[option.group_array_index].dom_id).setStyle({ @@ -747,6 +786,7 @@ return this.winnow_results_set_highlight(); } }; + Chosen.prototype.winnow_results_clear = function() { var li, lis, _i, _len, _results; this.search_field.clear(); @@ -754,10 +794,17 @@ _results = []; for (_i = 0, _len = lis.length; _i < _len; _i++) { li = lis[_i]; - _results.push(li.hasClassName("group-result") ? li.show() : !this.is_multiple || !li.hasClassName("result-selected") ? this.result_activate(li) : void 0); + if (li.hasClassName("group-result")) { + _results.push(li.show()); + } else if (!this.is_multiple || !li.hasClassName("result-selected")) { + _results.push(this.result_activate(li)); + } else { + _results.push(void 0); + } } return _results; }; + Chosen.prototype.winnow_results_set_highlight = function() { var do_high; if (!this.result_highlight) { @@ -767,16 +814,16 @@ if (!(do_high != null)) { do_high = this.search_results.down(".active-result"); } - if (do_high != null) { - return this.result_do_highlight(do_high); - } + if (do_high != null) return this.result_do_highlight(do_high); } }; + Chosen.prototype.no_results = function(terms) { return this.search_results.insert(this.no_results_temp.evaluate({ terms: terms })); }; + Chosen.prototype.no_results_clear = function() { var nr, _results; nr = null; @@ -786,6 +833,7 @@ } return _results; }; + Chosen.prototype.keydown_arrow = function() { var actives, nexts, sibs; actives = this.search_results.select("li.active-result"); @@ -795,15 +843,12 @@ } else if (this.results_showing) { sibs = this.result_highlight.nextSiblings(); nexts = sibs.intersect(actives); - if (nexts.length) { - this.result_do_highlight(nexts.first()); - } - } - if (!this.results_showing) { - return this.results_show(); + if (nexts.length) this.result_do_highlight(nexts.first()); } + if (!this.results_showing) return this.results_show(); } }; + Chosen.prototype.keyup_arrow = function() { var actives, prevs, sibs; if (!this.results_showing && !this.is_multiple) { @@ -815,13 +860,12 @@ if (prevs.length) { return this.result_do_highlight(prevs.first()); } else { - if (this.choices > 0) { - this.results_hide(); - } + if (this.choices > 0) this.results_hide(); return this.result_clear_highlight(); } } }; + Chosen.prototype.keydown_backstroke = function() { if (this.pending_backstroke) { this.choice_destroy(this.pending_backstroke.down("a")); @@ -831,27 +875,25 @@ return this.pending_backstroke.addClassName("search-choice-focus"); } }; + Chosen.prototype.clear_backstroke = function() { if (this.pending_backstroke) { this.pending_backstroke.removeClassName("search-choice-focus"); } return this.pending_backstroke = null; }; + Chosen.prototype.keydown_checker = function(evt) { var stroke, _ref; stroke = (_ref = evt.which) != null ? _ref : evt.keyCode; this.search_field_scale(); - if (stroke !== 8 && this.pending_backstroke) { - this.clear_backstroke(); - } + if (stroke !== 8 && this.pending_backstroke) this.clear_backstroke(); switch (stroke) { case 8: this.backstroke_length = this.search_field.value.length; break; case 9: - if (this.results_showing && !this.is_multiple) { - this.result_select(evt); - } + if (this.results_showing && !this.is_multiple) this.result_select(evt); this.mouse_on_container = false; break; case 13: @@ -866,6 +908,7 @@ break; } }; + Chosen.prototype.search_field_scale = function() { var dd_top, div, h, style, style_block, styles, w, _i, _len; if (this.is_multiple) { @@ -883,9 +926,7 @@ document.body.appendChild(div); w = Element.measure(div, 'width') + 25; div.remove(); - if (w > this.f_width - 10) { - w = this.f_width - 10; - } + if (w > this.f_width - 10) w = this.f_width - 10; this.search_field.setStyle({ 'width': w + 'px' }); @@ -895,18 +936,25 @@ }); } }; + return Chosen; - })(); + + })(AbstractChosen); + root.Chosen = Chosen; + if (Prototype.Browser.IE) { if (/MSIE (\d+\.\d+);/.test(navigator.userAgent)) { Prototype.BrowserFeatures['Version'] = new Number(RegExp.$1); } } + get_side_border_padding = function(elmt) { var layout, side_border_padding; layout = new Element.Layout(elmt); return side_border_padding = layout.get("border-left") + layout.get("border-right") + layout.get("padding-left") + layout.get("padding-right"); }; + root.get_side_border_padding = get_side_border_padding; + }).call(this); diff --git a/admin/thirdparty/chosen/chosen/chosen.proto.min.js b/admin/thirdparty/chosen/chosen/chosen.proto.min.js index d0f68d0b3..8e80774f1 100644 --- a/admin/thirdparty/chosen/chosen/chosen.proto.min.js +++ b/admin/thirdparty/chosen/chosen/chosen.proto.min.js @@ -1,10 +1,10 @@ // Chosen, a Select Box Enhancer for jQuery and Protoype // by Patrick Filler for Harvest, http://getharvest.com // -// Version 0.9.5 +// Version 0.9.7 // Full source at https://github.com/harvesthq/chosen // Copyright (c) 2011 Harvest http://getharvest.com // MIT License, https://github.com/harvesthq/chosen/blob/master/LICENSE.md // This file is generated by `cake build`, do not edit it by hand. -(function(){var a;a=function(){function a(){this.options_index=0,this.parsed=[]}return a.prototype.add_node=function(a){return a.nodeName==="OPTGROUP"?this.add_group(a):this.add_option(a)},a.prototype.add_group=function(a){var b,c,d,e,f,g;b=this.parsed.length,this.parsed.push({array_index:b,group:!0,label:a.label,children:0,disabled:a.disabled}),f=a.childNodes,g=[];for(d=0,e=f.length;d"+a.html+"")},a.prototype.results_update_field=function(){return this.result_clear_highlight(),this.result_single_selected=null,this.results_build()},a.prototype.results_toggle=function(){return this.results_showing?this.results_hide():this.results_show()},a.prototype.results_search=function(a){return this.results_showing?this.winnow_results():this.results_show()},a.prototype.keyup_checker=function(a){var b,c;b=(c=a.which)!=null?c:a.keyCode,this.search_field_scale();switch(b){case 8:if(this.is_multiple&&this.backstroke_length<1&&this.choices>0)return this.keydown_backstroke();if(!this.pending_backstroke)return this.result_clear_highlight(),this.results_search();break;case 13:a.preventDefault();if(this.results_showing)return this.result_select(a);break;case 27:if(this.results_showing)return this.results_hide();break;case 9:case 38:case 40:case 16:case 91:case 17:break;default:return this.results_search()}},a.prototype.generate_field_id=function(){var a;return a=this.generate_random_id(),this.form_field.id=a,a},a.prototype.generate_random_char=function(){var a,b,c;return a="0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZ",c=Math.floor(Math.random()*a.length),b=a.substring(c,c+1)},a}(),b.AbstractChosen=a}.call(this),function(){var a,b,c,d=Object.prototype.hasOwnProperty,e=function(a,b){function e(){this.constructor=a}for(var c in b)d.call(b,c)&&(a[c]=b[c]);return e.prototype=b.prototype,a.prototype=new e,a.__super__=b.prototype,a},f=function(a,b){return function(){return a.apply(b,arguments)}};c=this,a=function(){function a(){a.__super__.constructor.apply(this,arguments)}return e(a,AbstractChosen),a.prototype.setup=function(){return this.is_rtl=this.form_field.hasClassName("chzn-rtl")},a.prototype.finish_setup=function(){return this.form_field.addClassName("chzn-done")},a.prototype.set_default_values=function(){return a.__super__.set_default_values.call(this),this.single_temp=new Template('#{default}
                '),this.multi_temp=new Template('
                  '),this.choice_temp=new Template('
                • #{choice}
                • '),this.no_results_temp=new Template('
                • '+this.results_none_found+' "#{terms}"
                • ')},a.prototype.set_up_html=function(){var a,c,d,e,f;return this.container_id=this.form_field.identify().replace(/(:|\.)/g,"_")+"_chzn",this.f_width=this.form_field.getStyle("width")?parseInt(this.form_field.getStyle("width"),10):this.form_field.getWidth(),c={id:this.container_id,"class":"chzn-container"+(this.is_rtl?" chzn-rtl":""),style:"width: "+this.f_width+"px"},this.default_text=this.form_field.readAttribute("data-placeholder")?this.form_field.readAttribute("data-placeholder"):this.default_text_default,a=this.is_multiple?(new Element("div",c)).update(this.multi_temp.evaluate({"default":this.default_text})):(new Element("div",c)).update(this.single_temp.evaluate({"default":this.default_text})),this.form_field.hide().insert({after:a}),this.container=$(this.container_id),this.container.addClassName("chzn-container-"+(this.is_multiple?"multi":"single")),this.dropdown=this.container.down("div.chzn-drop"),d=this.container.getHeight(),e=this.f_width-b(this.dropdown),this.dropdown.setStyle({width:e+"px",top:d+"px"}),this.search_field=this.container.down("input"),this.search_results=this.container.down("ul.chzn-results"),this.search_field_scale(),this.search_no_results=this.container.down("li.no-results"),this.is_multiple?(this.search_choices=this.container.down("ul.chzn-choices"),this.search_container=this.container.down("li.search-field")):(this.search_container=this.container.down("div.chzn-search"),this.selected_item=this.container.down(".chzn-single"),f=e-b(this.search_container)-b(this.search_field),this.search_field.setStyle({width:f+"px"})),this.results_build(),this.set_tab_index(),this.form_field.fire("liszt:ready",{chosen:this})},a.prototype.register_observers=function(){this.container.observe("mousedown",f(function(a){return this.container_mousedown(a)},this)),this.container.observe("mouseup",f(function(a){return this.container_mouseup(a)},this)),this.container.observe("mouseenter",f(function(a){return this.mouse_enter(a)},this)),this.container.observe("mouseleave",f(function(a){return this.mouse_leave(a)},this)),this.search_results.observe("mouseup",f(function(a){return this.search_results_mouseup(a)},this)),this.search_results.observe("mouseover",f(function(a){return this.search_results_mouseover(a)},this)),this.search_results.observe("mouseout",f(function(a){return this.search_results_mouseout(a)},this)),this.form_field.observe("liszt:updated",f(function(a){return this.results_update_field(a)},this)),this.search_field.observe("blur",f(function(a){return this.input_blur(a)},this)),this.search_field.observe("keyup",f(function(a){return this.keyup_checker(a)},this)),this.search_field.observe("keydown",f(function(a){return this.keydown_checker(a)},this));if(this.is_multiple)return this.search_choices.observe("click",f(function(a){return this.choices_click(a)},this)),this.search_field.observe("focus",f(function(a){return this.input_focus(a)},this))},a.prototype.search_field_disabled=function(){this.is_disabled=this.form_field.disabled;if(this.is_disabled)return this.container.addClassName("chzn-disabled"),this.search_field.disabled=!0,this.is_multiple||this.selected_item.stopObserving("focus",this.activate_action),this.close_field();this.container.removeClassName("chzn-disabled"),this.search_field.disabled=!1;if(!this.is_multiple)return this.selected_item.observe("focus",this.activate_action)},a.prototype.container_mousedown=function(a){var b;if(!this.is_disabled)return b=a!=null?a.target.hasClassName("search-choice-close"):!1,a&&a.type==="mousedown"&&a.stop(),!this.pending_destroy_click&&!b?(this.active_field?!this.is_multiple&&a&&(a.target===this.selected_item||a.target.up("a.chzn-single"))&&this.results_toggle():(this.is_multiple&&this.search_field.clear(),document.observe("click",this.click_test_action),this.results_show()),this.activate_field()):this.pending_destroy_click=!1},a.prototype.container_mouseup=function(a){if(a.target.nodeName==="ABBR")return this.results_reset(a)},a.prototype.blur_test=function(a){if(!this.active_field&&this.container.hasClassName("chzn-container-active"))return this.close_field()},a.prototype.close_field=function(){return document.stopObserving("click",this.click_test_action),this.is_multiple||(this.selected_item.tabIndex=this.search_field.tabIndex,this.search_field.tabIndex=-1),this.active_field=!1,this.results_hide(),this.container.removeClassName("chzn-container-active"),this.winnow_results_clear(),this.clear_backstroke(),this.show_search_field_default(),this.search_field_scale()},a.prototype.activate_field=function(){return!this.is_multiple&&!this.active_field&&(this.search_field.tabIndex=this.selected_item.tabIndex,this.selected_item.tabIndex=-1),this.container.addClassName("chzn-container-active"),this.active_field=!0,this.search_field.value=this.search_field.value,this.search_field.focus()},a.prototype.test_active_click=function(a){return a.target.up("#"+this.container_id)?this.active_field=!0:this.close_field()},a.prototype.results_build=function(){var a,b,d,e,f;this.parsing=!0,this.results_data=c.SelectParser.select_to_array(this.form_field),this.is_multiple&&this.choices>0?(this.search_choices.select("li.search-choice").invoke("remove"),this.choices=0):this.is_multiple||(this.selected_item.down("span").update(this.default_text),this.form_field.options.length>this.disable_search_threshold?this.container.removeClassName("chzn-container-single-nosearch"):this.container.addClassName("chzn-container-single-nosearch")),a="",f=this.results_data;for(d=0,e=f.length;d'+a.label.escapeHTML()+"")},a.prototype.result_do_highlight=function(a){var b,c,d,e,f;this.result_clear_highlight(),this.result_highlight=a,this.result_highlight.addClassName("highlighted"),d=parseInt(this.search_results.getStyle("maxHeight"),10),f=this.search_results.scrollTop,e=d+f,c=this.result_highlight.positionedOffset().top,b=c+this.result_highlight.getHeight();if(b>=e)return this.search_results.scrollTop=b-d>0?b-d:0;if(c0&&this.search_field.value.length<1&&this.results_hide(),this.result_deselect(a.readAttribute("rel")),a.up("li").remove()},a.prototype.results_reset=function(a){this.form_field.options[0].selected=!0,this.selected_item.down("span").update(this.default_text),this.show_search_field_default(),a.target.remove(),typeof Event.simulate=="function"&&this.form_field.simulate("change");if(this.active_field)return this.results_hide()},a.prototype.result_select=function(a){var b,c,d;if(this.result_highlight)return b=this.result_highlight,this.result_clear_highlight(),this.is_multiple?this.result_deactivate(b):(this.search_results.descendants(".result-selected").invoke("removeClassName","result-selected"),this.result_single_selected=b),b.addClassName("result-selected"),d=b.id.substr(b.id.lastIndexOf("_")+1),c=this.results_data[d],c.selected=!0,this.form_field.options[c.options_index].selected=!0,this.is_multiple?this.choice_build(c):(this.selected_item.down("span").update(c.html),this.allow_single_deselect&&this.single_deselect_control_build()),(!a.metaKey||!this.is_multiple)&&this.results_hide(),this.search_field.value="",typeof Event.simulate=="function"&&this.form_field.simulate("change"),this.search_field_scale()},a.prototype.result_activate=function(a){return a.addClassName("active-result")},a.prototype.result_deactivate=function(a){return a.removeClassName("active-result")},a.prototype.result_deselect=function(a){var b,c;return c=this.results_data[a],c.selected=!1,this.form_field.options[c.options_index].selected=!1,b=$(this.container_id+"_o_"+a),b.removeClassName("result-selected").addClassName("active-result").show(),this.result_clear_highlight(),this.winnow_results(),typeof Event.simulate=="function"&&this.form_field.simulate("change"),this.search_field_scale()},a.prototype.single_deselect_control_build=function(){if(this.allow_single_deselect&&!this.selected_item.down("abbr"))return this.selected_item.down("span").insert({after:''})},a.prototype.winnow_results=function(){var a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p;this.no_results_clear(),g=0,h=this.search_field.value===this.default_text?"":this.search_field.value.strip().escapeHTML(),e=new RegExp("^"+h.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),"i"),k=new RegExp(h.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),"i"),p=this.results_data;for(l=0,n=p.length;l=0||b.html.indexOf("[")===0){d=b.html.replace(/\[|\]/g,"").split(" ");if(d.length)for(m=0,o=d.length;m"+b.html.substr(i+h.length),j=j.substr(0,i)+""+j.substr(i)):j=b.html,$(f).innerHTML!==j&&$(f).update(j),this.result_activate($(f)),b.group_array_index!=null&&$(this.results_data[b.group_array_index].dom_id).setStyle({display:"list-item"})):($(f)===this.result_highlight&&this.result_clear_highlight(),this.result_deactivate($(f)))}}return g<1&&h.length?this.no_results(h):this.winnow_results_set_highlight()},a.prototype.winnow_results_clear=function(){var a,b,c,d,e;this.search_field.clear(),b=this.search_results.select("li"),e=[];for(c=0,d=b.length;c0&&this.results_hide(),this.result_clear_highlight())},a.prototype.keydown_backstroke=function(){return this.pending_backstroke?(this.choice_destroy(this.pending_backstroke.down("a")),this.clear_backstroke()):(this.pending_backstroke=this.search_container.siblings("li.search-choice").last(),this.pending_backstroke.addClassName("search-choice-focus"))},a.prototype.clear_backstroke=function(){return this.pending_backstroke&&this.pending_backstroke.removeClassName("search-choice-focus"),this.pending_backstroke=null},a.prototype.keydown_checker=function(a){var b,c;b=(c=a.which)!=null?c:a.keyCode,this.search_field_scale(),b!==8&&this.pending_backstroke&&this.clear_backstroke();switch(b){case 8:this.backstroke_length=this.search_field.value.length;break;case 9:this.results_showing&&!this.is_multiple&&this.result_select(a),this.mouse_on_container=!1;break;case 13:a.preventDefault();break;case 38:a.preventDefault(),this.keyup_arrow();break;case 40:this.keydown_arrow()}},a.prototype.search_field_scale=function(){var a,b,c,d,e,f,g,h,i;if(this.is_multiple){c=0,g=0,e="position:absolute; left: -1000px; top: -1000px; display:none;",f=["font-size","font-style","font-weight","font-family","line-height","text-transform","letter-spacing"];for(h=0,i=f.length;hthis.f_width-10&&(g=this.f_width-10),this.search_field.setStyle({width:g+"px"}),a=this.container.getHeight(),this.dropdown.setStyle({top:a+"px"})}},a}(),c.Chosen=a,Prototype.Browser.IE&&/MSIE (\d+\.\d+);/.test(navigator.userAgent)&&(Prototype.BrowserFeatures.Version=new Number(RegExp.$1)),b=function(a){var b,c;return b=new Element.Layout(a),c=b.get("border-left")+b.get("border-right")+b.get("padding-left")+b.get("padding-right")},c.get_side_border_padding=b}.call(this) \ No newline at end of file +((function(){var a;a=function(){function a(){this.options_index=0,this.parsed=[]}return a.prototype.add_node=function(a){return a.nodeName==="OPTGROUP"?this.add_group(a):this.add_option(a)},a.prototype.add_group=function(a){var b,c,d,e,f,g;b=this.parsed.length,this.parsed.push({array_index:b,group:!0,label:a.label,children:0,disabled:a.disabled}),f=a.childNodes,g=[];for(d=0,e=f.length;d"+a.html+"")},a.prototype.results_update_field=function(){return this.result_clear_highlight(),this.result_single_selected=null,this.results_build()},a.prototype.results_toggle=function(){return this.results_showing?this.results_hide():this.results_show()},a.prototype.results_search=function(a){return this.results_showing?this.winnow_results():this.results_show()},a.prototype.keyup_checker=function(a){var b,c;b=(c=a.which)!=null?c:a.keyCode,this.search_field_scale();switch(b){case 8:if(this.is_multiple&&this.backstroke_length<1&&this.choices>0)return this.keydown_backstroke();if(!this.pending_backstroke)return this.result_clear_highlight(),this.results_search();break;case 13:a.preventDefault();if(this.results_showing)return this.result_select(a);break;case 27:return this.results_showing&&this.results_hide(),!0;case 9:case 38:case 40:case 16:case 91:case 17:break;default:return this.results_search()}},a.prototype.generate_field_id=function(){var a;return a=this.generate_random_id(),this.form_field.id=a,a},a.prototype.generate_random_char=function(){var a,b,c;return a="0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZ",c=Math.floor(Math.random()*a.length),b=a.substring(c,c+1)},a}(),b.AbstractChosen=a}.call(this),function(){var a,b,c,d=Object.prototype.hasOwnProperty,e=function(a,b){function e(){this.constructor=a}for(var c in b)d.call(b,c)&&(a[c]=b[c]);return e.prototype=b.prototype,a.prototype=new e,a.__super__=b.prototype,a};c=this,a=function(a){function d(){d.__super__.constructor.apply(this,arguments)}return e(d,a),d.prototype.setup=function(){return this.is_rtl=this.form_field.hasClassName("chzn-rtl")},d.prototype.finish_setup=function(){return this.form_field.addClassName("chzn-done")},d.prototype.set_default_values=function(){return d.__super__.set_default_values.call(this),this.single_temp=new Template('#{default}
                    '),this.multi_temp=new Template('
                      '),this.choice_temp=new Template('
                    • #{choice}
                    • '),this.no_results_temp=new Template('
                    • '+this.results_none_found+' "#{terms}"
                    • ')},d.prototype.set_up_html=function(){var a,c,d,e,f;return this.container_id=this.form_field.identify().replace(/(:|\.)/g,"_")+"_chzn",this.f_width=this.form_field.getStyle("width")?parseInt(this.form_field.getStyle("width"),10):this.form_field.getWidth(),c={id:this.container_id,"class":"chzn-container"+(this.is_rtl?" chzn-rtl":""),style:"width: "+this.f_width+"px"},this.default_text=this.form_field.readAttribute("data-placeholder")?this.form_field.readAttribute("data-placeholder"):this.default_text_default,a=this.is_multiple?(new Element("div",c)).update(this.multi_temp.evaluate({"default":this.default_text})):(new Element("div",c)).update(this.single_temp.evaluate({"default":this.default_text})),this.form_field.hide().insert({after:a}),this.container=$(this.container_id),this.container.addClassName("chzn-container-"+(this.is_multiple?"multi":"single")),this.dropdown=this.container.down("div.chzn-drop"),d=this.container.getHeight(),e=this.f_width-b(this.dropdown),this.dropdown.setStyle({width:e+"px",top:d+"px"}),this.search_field=this.container.down("input"),this.search_results=this.container.down("ul.chzn-results"),this.search_field_scale(),this.search_no_results=this.container.down("li.no-results"),this.is_multiple?(this.search_choices=this.container.down("ul.chzn-choices"),this.search_container=this.container.down("li.search-field")):(this.search_container=this.container.down("div.chzn-search"),this.selected_item=this.container.down(".chzn-single"),f=e-b(this.search_container)-b(this.search_field),this.search_field.setStyle({width:f+"px"})),this.results_build(),this.set_tab_index(),this.form_field.fire("liszt:ready",{chosen:this})},d.prototype.register_observers=function(){var a=this;return this.container.observe("mousedown",function(b){return a.container_mousedown(b)}),this.container.observe("mouseup",function(b){return a.container_mouseup(b)}),this.container.observe("mouseenter",function(b){return a.mouse_enter(b)}),this.container.observe("mouseleave",function(b){return a.mouse_leave(b)}),this.search_results.observe("mouseup",function(b){return a.search_results_mouseup(b)}),this.search_results.observe("mouseover",function(b){return a.search_results_mouseover(b)}),this.search_results.observe("mouseout",function(b){return a.search_results_mouseout(b)}),this.form_field.observe("liszt:updated",function(b){return a.results_update_field(b)}),this.search_field.observe("blur",function(b){return a.input_blur(b)}),this.search_field.observe("keyup",function(b){return a.keyup_checker(b)}),this.search_field.observe("keydown",function(b){return a.keydown_checker(b)}),this.is_multiple?(this.search_choices.observe("click",function(b){return a.choices_click(b)}),this.search_field.observe("focus",function(b){return a.input_focus(b)})):this.container.observe("click",function(a){return a.preventDefault()})},d.prototype.search_field_disabled=function(){this.is_disabled=this.form_field.disabled;if(this.is_disabled)return this.container.addClassName("chzn-disabled"),this.search_field.disabled=!0,this.is_multiple||this.selected_item.stopObserving("focus",this.activate_action),this.close_field();this.container.removeClassName("chzn-disabled"),this.search_field.disabled=!1;if(!this.is_multiple)return this.selected_item.observe("focus",this.activate_action)},d.prototype.container_mousedown=function(a){var b;if(!this.is_disabled)return b=a!=null?a.target.hasClassName("search-choice-close"):!1,a&&a.type==="mousedown"&&a.stop(),!this.pending_destroy_click&&!b?(this.active_field?!this.is_multiple&&a&&(a.target===this.selected_item||a.target.up("a.chzn-single"))&&this.results_toggle():(this.is_multiple&&this.search_field.clear(),document.observe("click",this.click_test_action),this.results_show()),this.activate_field()):this.pending_destroy_click=!1},d.prototype.container_mouseup=function(a){if(a.target.nodeName==="ABBR")return this.results_reset(a)},d.prototype.blur_test=function(a){if(!this.active_field&&this.container.hasClassName("chzn-container-active"))return this.close_field()},d.prototype.close_field=function(){return document.stopObserving("click",this.click_test_action),this.is_multiple||(this.selected_item.tabIndex=this.search_field.tabIndex,this.search_field.tabIndex=-1),this.active_field=!1,this.results_hide(),this.container.removeClassName("chzn-container-active"),this.winnow_results_clear(),this.clear_backstroke(),this.show_search_field_default(),this.search_field_scale()},d.prototype.activate_field=function(){return!this.is_multiple&&!this.active_field&&(this.search_field.tabIndex=this.selected_item.tabIndex,this.selected_item.tabIndex=-1),this.container.addClassName("chzn-container-active"),this.active_field=!0,this.search_field.value=this.search_field.value,this.search_field.focus()},d.prototype.test_active_click=function(a){return a.target.up("#"+this.container_id)?this.active_field=!0:this.close_field()},d.prototype.results_build=function(){var a,b,d,e,f;this.parsing=!0,this.results_data=c.SelectParser.select_to_array(this.form_field),this.is_multiple&&this.choices>0?(this.search_choices.select("li.search-choice").invoke("remove"),this.choices=0):this.is_multiple||(this.selected_item.down("span").update(this.default_text),this.form_field.options.length<=this.disable_search_threshold?this.container.addClassName("chzn-container-single-nosearch"):this.container.removeClassName("chzn-container-single-nosearch")),a="",f=this.results_data;for(d=0,e=f.length;d'+a.label.escapeHTML()+"")},d.prototype.result_do_highlight=function(a){var b,c,d,e,f;this.result_clear_highlight(),this.result_highlight=a,this.result_highlight.addClassName("highlighted"),d=parseInt(this.search_results.getStyle("maxHeight"),10),f=this.search_results.scrollTop,e=d+f,c=this.result_highlight.positionedOffset().top,b=c+this.result_highlight.getHeight();if(b>=e)return this.search_results.scrollTop=b-d>0?b-d:0;if(c0&&this.search_field.value.length<1&&this.results_hide(),this.result_deselect(a.readAttribute("rel")),a.up("li").remove()},d.prototype.results_reset=function(a){this.form_field.options[0].selected=!0,this.selected_item.down("span").update(this.default_text),this.show_search_field_default(),a.target.remove(),typeof Event.simulate=="function"&&this.form_field.simulate("change");if(this.active_field)return this.results_hide()},d.prototype.result_select=function(a){var b,c,d;if(this.result_highlight)return b=this.result_highlight,this.result_clear_highlight(),this.is_multiple?this.result_deactivate(b):(this.search_results.descendants(".result-selected").invoke("removeClassName","result-selected"),this.result_single_selected=b),b.addClassName("result-selected"),d=b.id.substr(b.id.lastIndexOf("_")+1),c=this.results_data[d],c.selected=!0,this.form_field.options[c.options_index].selected=!0,this.is_multiple?this.choice_build(c):(this.selected_item.down("span").update(c.html),this.allow_single_deselect&&this.single_deselect_control_build()),(!a.metaKey||!this.is_multiple)&&this.results_hide(),this.search_field.value="",typeof Event.simulate=="function"&&this.form_field.simulate("change"),this.search_field_scale()},d.prototype.result_activate=function(a){return a.addClassName("active-result")},d.prototype.result_deactivate=function(a){return a.removeClassName("active-result")},d.prototype.result_deselect=function(a){var b,c;return c=this.results_data[a],c.selected=!1,this.form_field.options[c.options_index].selected=!1,b=$(this.container_id+"_o_"+a),b.removeClassName("result-selected").addClassName("active-result").show(),this.result_clear_highlight(),this.winnow_results(),typeof Event.simulate=="function"&&this.form_field.simulate("change"),this.search_field_scale()},d.prototype.single_deselect_control_build=function(){if(this.allow_single_deselect&&!this.selected_item.down("abbr"))return this.selected_item.down("span").insert({after:''})},d.prototype.winnow_results=function(){var a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p;this.no_results_clear(),g=0,h=this.search_field.value===this.default_text?"":this.search_field.value.strip().escapeHTML(),e=new RegExp("^"+h.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),"i"),k=new RegExp(h.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&"),"i"),p=this.results_data;for(l=0,n=p.length;l=0||b.html.indexOf("[")===0){d=b.html.replace(/\[|\]/g,"").split(" ");if(d.length)for(m=0,o=d.length;m"+b.html.substr(i+h.length),j=j.substr(0,i)+""+j.substr(i)):j=b.html,$(f).innerHTML!==j&&$(f).update(j),this.result_activate($(f)),b.group_array_index!=null&&$(this.results_data[b.group_array_index].dom_id).setStyle({display:"list-item"})):($(f)===this.result_highlight&&this.result_clear_highlight(),this.result_deactivate($(f)))}}return g<1&&h.length?this.no_results(h):this.winnow_results_set_highlight()},d.prototype.winnow_results_clear=function(){var a,b,c,d,e;this.search_field.clear(),b=this.search_results.select("li"),e=[];for(c=0,d=b.length;c0&&this.results_hide(),this.result_clear_highlight())},d.prototype.keydown_backstroke=function(){return this.pending_backstroke?(this.choice_destroy(this.pending_backstroke.down("a")),this.clear_backstroke()):(this.pending_backstroke=this.search_container.siblings("li.search-choice").last(),this.pending_backstroke.addClassName("search-choice-focus"))},d.prototype.clear_backstroke=function(){return this.pending_backstroke&&this.pending_backstroke.removeClassName("search-choice-focus"),this.pending_backstroke=null},d.prototype.keydown_checker=function(a){var b,c;b=(c=a.which)!=null?c:a.keyCode,this.search_field_scale(),b!==8&&this.pending_backstroke&&this.clear_backstroke();switch(b){case 8:this.backstroke_length=this.search_field.value.length;break;case 9:this.results_showing&&!this.is_multiple&&this.result_select(a),this.mouse_on_container=!1;break;case 13:a.preventDefault();break;case 38:a.preventDefault(),this.keyup_arrow();break;case 40:this.keydown_arrow()}},d.prototype.search_field_scale=function(){var a,b,c,d,e,f,g,h,i;if(this.is_multiple){c=0,g=0,e="position:absolute; left: -1000px; top: -1000px; display:none;",f=["font-size","font-style","font-weight","font-family","line-height","text-transform","letter-spacing"];for(h=0,i=f.length;hthis.f_width-10&&(g=this.f_width-10),this.search_field.setStyle({width:g+"px"}),a=this.container.getHeight(),this.dropdown.setStyle({top:a+"px"})}},d}(AbstractChosen),c.Chosen=a,Prototype.Browser.IE&&/MSIE (\d+\.\d+);/.test(navigator.userAgent)&&(Prototype.BrowserFeatures.Version=new Number(RegExp.$1)),b=function(a){var b,c;return b=new Element.Layout(a),c=b.get("border-left")+b.get("border-right")+b.get("padding-left")+b.get("padding-right")},c.get_side_border_padding=b}.call(this) \ No newline at end of file diff --git a/admin/thirdparty/chosen/coffee/chosen.jquery.coffee b/admin/thirdparty/chosen/coffee/chosen.jquery.coffee index 56b3b3f9f..d65d0354a 100644 --- a/admin/thirdparty/chosen/coffee/chosen.jquery.coffee +++ b/admin/thirdparty/chosen/coffee/chosen.jquery.coffee @@ -90,6 +90,8 @@ class Chosen extends AbstractChosen if @is_multiple @search_choices.click (evt) => this.choices_click(evt) @search_field.focus (evt) => this.input_focus(evt) + else + @container.click (evt) => evt.preventDefault() # gobble click of anchor search_field_disabled: -> @is_disabled = @form_field_jq[0].disabled diff --git a/admin/thirdparty/chosen/coffee/chosen.proto.coffee b/admin/thirdparty/chosen/coffee/chosen.proto.coffee index db747d1fd..4c306a766 100644 --- a/admin/thirdparty/chosen/coffee/chosen.proto.coffee +++ b/admin/thirdparty/chosen/coffee/chosen.proto.coffee @@ -83,6 +83,8 @@ class Chosen extends AbstractChosen if @is_multiple @search_choices.observe "click", (evt) => this.choices_click(evt) @search_field.observe "focus", (evt) => this.input_focus(evt) + else + @container.observe "click", (evt) => evt.preventDefault() # gobble click of anchor search_field_disabled: -> @is_disabled = @form_field.disabled diff --git a/admin/thirdparty/chosen/coffee/lib/abstract-chosen.coffee b/admin/thirdparty/chosen/coffee/lib/abstract-chosen.coffee index b9ca3315e..a7c1b01da 100644 --- a/admin/thirdparty/chosen/coffee/lib/abstract-chosen.coffee +++ b/admin/thirdparty/chosen/coffee/lib/abstract-chosen.coffee @@ -91,6 +91,7 @@ class AbstractChosen this.result_select(evt) if this.results_showing when 27 this.results_hide() if @results_showing + return true when 9, 38, 40, 16, 91, 17 # don't do anything on these keys else this.results_search() diff --git a/admin/thirdparty/chosen/example.proto.html b/admin/thirdparty/chosen/example.proto.html index daddecbb2..77c48c71f 100644 --- a/admin/thirdparty/chosen/example.proto.html +++ b/admin/thirdparty/chosen/example.proto.html @@ -54,13 +54,12 @@

                      Chosen

                      Chosen is a JavaScript plugin for jQuery and Prototype that makes long, unwieldy select boxes much more user-friendly. For more information (including usage, explanation and faqs), check out the online documentation.

                      -

                      Standard Select

                      +

                      Multiple Select

                      Turns This - + @@ -307,11 +306,11 @@
                      Into This - - + - + @@ -453,7 +452,7 @@ - + @@ -555,213 +554,268 @@
                      - -

                      Multiple Select

                      + +

                      <optgroup> Support

                      - Turns This - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                      +
                      + Multiple Select with Groups + +
                      +
                      + +

                      Selected and Disabled Support

                      +
                      +

                      Chosen automatically highlights selected options and removes disabled options.

                      +
                      + Single Select + +
                      +
                      + Multiple Select + +
                      +
                      + +

                      Default Text Support

                      +
                      +

                      Chosen automatically sets the default field text ("Choose a country...") by reading the select element's data-placeholder value. If no data-placeholder value is present, it will default to "Select Some Option" or "Select Some Options" depending on whether the select is single or multiple. You can change these elements in the plugin js file as you see fit.

                      + <select data-placeholder="Choose a country..." style="width:350px;" multiple class="chzn-select"> +

                      Note: on single selects, the first element is assumed to be selected by the browser. To take advantage of the default text support, you will need to include a blank option as the first element of your select list.

                      +
                      + +

                      No Results Text Support

                      +
                      +

                      Setting the "No results" search text is as easy as passing an option when you create Chosen:

                      + + New Chosen($("chzn_select_field"),{no_results_text: "No results matched"}); + +
                      + +

                      Allow Deselect on Single Selects

                      +
                      +

                      When a single select box isn't a required field, you can set allow_single_deselect: true and Chosen will add a UI element for option deselection. This will only work if the first option has blank text.

                      +
                      + +
                      +
                      + +

                      Right to Left Support

                      +
                      +

                      Chosen supports right to left select boxes too. just add "chzn-rtl" in addition to "chzn-select" to your select tags and you are good to go.

                      +

                      <select class="chzn-select chzn-rtl">

                      +
                      + Single right to left select + +
                      +
                      + Multiple right to left select + +
                      +
                      + +

                      Change / Update Events

                      +
                      +
                        +
                      • +

                        Form Field Change

                        +

                        When working with form fields, you often want to perform some behavior after a value has been selected or deselected. Whenever a user selects a field in Chosen, it triggers a "change" event* on the original form field. That let's you do something like this:

                        +

                        $("#form_field").chosen().change( … );

                        +

                        Note: Prototype doesn't offer support for triggering standard browser events. Event.simulate is required to trigger the change event when using the Prototype version.

                        +
                      • +
                      • +

                        Updating Chosen Dynamically

                        +

                        If you need to update the options in your select field and want Chosen to pick up the changes, you'll need to trigger the "liszt:updated" event on the field. Chosen will re-build itself based on the updated content.

                        +
                          +
                        • jQuery Version: $("#form_field").trigger("liszt:updated");
                        • +
                        • Prototype Version: Event.fire($("form_field"), "liszt:updated");
                        • +
                        +
                      • +
                      +
                      + +

                      Setup (for Prototype)

                      +

                      Using Chosen is easy as can be.

                      +
                        +
                      1. Download the plugin and copy the chosen files to your app.
                      2. +
                      3. Activate the plugin by creating a new instance of Chosen: new Chosen(some_form_field);
                      4. +
                      5. Disco.
                      6. +
                      + +
                      + + + + +orgia and The South Sandwich Islands">South Georgia and The South Sandwich Islands diff --git a/admin/thirdparty/chosen/package.json b/admin/thirdparty/chosen/package.json new file mode 100644 index 000000000..a26bb42c8 --- /dev/null +++ b/admin/thirdparty/chosen/package.json @@ -0,0 +1,18 @@ +{ + "author": "harvest", + "name": "chosen", + "version": "0.9.7", + "description": "Chosen is a JavaScript plugin that makes long, unwieldy select boxes much more user-friendly. It is currently available in both jQuery and Prototype flavors.", + "repository": { + "type": "git", + "url": "https://github.com/harvesthq/chosen" + }, + "engines": { + "node": ">=0.4.0" + }, + "dependencies": {}, + "devDependencies": { + "coffee-script": ">= 1.2", + "uglify-js": ">= 1.2.5" + } +} \ No newline at end of file diff --git a/css/GridField.css b/css/GridField.css index 26a7f227b..16b55b33b 100644 --- a/css/GridField.css +++ b/css/GridField.css @@ -4,18 +4,20 @@ .cms .ss-gridfield[data-selectable] td { cursor: pointer; } .cms table.ss-gridfield-table { display: table; box-shadow: none; padding: 0; border-collapse: separate; border-bottom: 0 none; width: 100%; } .cms table.ss-gridfield-table thead { color: #1d2224; background: transparent; } +.cms table.ss-gridfield-table thead tr.filter-header .fieldgroup { max-width: 512px; } .cms table.ss-gridfield-table tbody { background: #FFF; } -.cms table.ss-gridfield-table tbody td { /* Emulate a link by default */ } .cms table.ss-gridfield-table tbody td button { border: none; background: none; margin: 0 0 0 2px; padding: 0; width: auto; text-shadow: none; } -.cms table.ss-gridfield-table tbody td button.ui-state-hover { background: none; border: none; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; } -.cms table.ss-gridfield-table tbody td button span.ui-button-text { text-indent: -9999em; background: url(../images/icons/decline.png) no-repeat 0 2px; padding: 0; width: 20px; height: 20px; } -.cms table.ss-gridfield-table tbody td a.edit-link { display: inline-block; height: 20px; width: 20px; text-indent: -9999em; background: url(../images/icons/document--pencil.png) no-repeat 0 1px; } +.cms table.ss-gridfield-table tbody td button.gridfield-button-delete.ui-state-hover { background: none; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; } +.cms table.ss-gridfield-table tbody td button.gridfield-button-delete.ui-state-active { border: none; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; } +.cms table.ss-gridfield-table tbody td button.gridfield-button-unlink.ui-state-hover { background: none; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; } +.cms table.ss-gridfield-table tbody td button.gridfield-button-unlink.ui-state-active { border: none; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; } +.cms table.ss-gridfield-table tbody td a.edit-link { display: inline-block; width: 20px; height: 20px; text-indent: -9999em; background: url(../images/icons/document--pencil.png) no-repeat 0 1px; } .cms table.ss-gridfield-table tfoot { color: #1d2224; } .cms table.ss-gridfield-table tfoot tr td { background: #95a5ab; padding: .7em; border-bottom: 1px solid rgba(0, 0, 0, 0.1); } .cms table.ss-gridfield-table tr.title { -moz-border-radius-topleft: 7px; -webkit-border-top-left-radius: 7px; -o-border-top-left-radius: 7px; -ms-border-top-left-radius: 7px; -khtml-border-top-left-radius: 7px; border-top-left-radius: 7px; -moz-border-radius-topright: 7px; -webkit-border-top-right-radius: 7px; -o-border-top-right-radius: 7px; -ms-border-top-right-radius: 7px; -khtml-border-top-right-radius: 7px; border-top-right-radius: 7px; } .cms table.ss-gridfield-table tr.title th { position: relative; background: #7f9198; border-top: 1px solid rgba(0, 0, 0, 0.1); padding: 5px; min-height: 40px; background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #b1c0c5), color-stop(100%, #7f9198)); background-image: -webkit-linear-gradient(#b1c0c5, #7f9198); background-image: -moz-linear-gradient(#b1c0c5, #7f9198); background-image: -o-linear-gradient(#b1c0c5, #7f9198); background-image: -ms-linear-gradient(#b1c0c5, #7f9198); background-image: linear-gradient(#b1c0c5, #7f9198); -moz-border-radius-topleft: 7px; -webkit-border-top-left-radius: 7px; -o-border-top-left-radius: 7px; -ms-border-top-left-radius: 7px; -khtml-border-top-left-radius: 7px; border-top-left-radius: 7px; -moz-border-radius-topright: 7px; -webkit-border-top-right-radius: 7px; -o-border-top-right-radius: 7px; -ms-border-top-right-radius: 7px; -khtml-border-top-right-radius: 7px; border-top-right-radius: 7px; text-shadow: rgba(0, 0, 0, 0.3) 0px -1px 0; } .cms table.ss-gridfield-table tr.title th h2 { padding: 0px; font-size: 16.8px; color: #fff; margin: 3px 8px 0; display: inline-block; } -.cms table.ss-gridfield-table tr.title th .new { font-size: 14.4px; border-color: rgba(0, 0, 0, 0.1); float: right; } +.cms table.ss-gridfield-table tr.title th .new { font-size: 14.4px; float: right; } .cms table.ss-gridfield-table tr.sortable-header { background: #bac8ce; } .cms table.ss-gridfield-table tr.sortable-header th { padding: 0px; } .cms table.ss-gridfield-table tr:hover { background: #FFFAD6 !important; } @@ -44,15 +46,27 @@ .cms table.ss-gridfield-table tr th button.ss-gridfield-sort.ss-gridfield-sorted-desc { background-position: right -72px; } .cms table.ss-gridfield-table tr th button.ss-gridfield-sort.ss-gridfield-sorted-asc { background-position: right -116px; } .cms table.ss-gridfield-table tr th button.ss-gridfield-button-filter.ss-ui-button { position: absolute; right: 7px; top: -28px; display: block; text-indent: -9999em; width: 30px; height: 28px; border-top-left-radius: 0px; border-bottom-left-radius: 0px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-width: 1px; border-color: #9a9a9a; background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ffffff), color-stop(100%, #d9d9d9)); background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, -webkit-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, -moz-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, -o-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, -ms-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat -40px 6px, linear-gradient(#ffffff, #d9d9d9); } -.cms table.ss-gridfield-table tr th button.ss-gridfield-button-filter.ss-ui-button:hover { background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #4199cd), color-stop(100%, #2e7ead)); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -webkit-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -moz-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -o-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -ms-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, linear-gradient(#4199cd, #2e7ead); } -.cms table.ss-gridfield-table tr th button.ss-gridfield-button-filter.ss-ui-button:active { background: url(../images/icons/filter-icons.png) no-repeat -16px -17px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #4199cd), color-stop(100%, #2e7ead)); background: url(../images/icons/filter-icons.png) no-repeat -16px -17px, -webkit-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px -17px, -moz-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px -17px, -o-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px -17px, -ms-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px -17px, linear-gradient(#4199cd, #2e7ead); -moz-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); -webkit-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); -o-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); } +.cms table.ss-gridfield-table tr th button.ss-gridfield-button-filter.ss-ui-button.hover-alike:active { background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #4199cd), color-stop(100%, #2e7ead)); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -webkit-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -moz-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -o-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -ms-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, linear-gradient(#4199cd, #2e7ead); -moz-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); -webkit-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); -o-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); } +.cms table.ss-gridfield-table tr th button.ss-gridfield-button-filter.ss-ui-button.hover-alike { background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #4199cd), color-stop(100%, #2e7ead)); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -webkit-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -moz-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -o-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, -ms-linear-gradient(#4199cd, #2e7ead); background: url(../images/icons/filter-icons.png) no-repeat -16px 6px, linear-gradient(#4199cd, #2e7ead); } .cms table.ss-gridfield-table tr th button.ss-gridfield-button-reset.ss-ui-button { position: absolute; right: 36px; top: -28px; display: block; text-indent: -9999em; width: 30px; height: 28px; float: right; border-radius: 0px; border-bottom-width: 1px; border-color: #9a9a9a; background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ffffff), color-stop(100%, #d9d9d9)); background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, -webkit-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, -moz-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, -o-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, -ms-linear-gradient(#ffffff, #d9d9d9); background: url(../images/icons/filter-icons.png) no-repeat 8px 5px, linear-gradient(#ffffff, #d9d9d9); } -.cms table.ss-gridfield-table tr th button.ss-gridfield-button-reset.ss-ui-button:hover { background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ff0000), color-stop(100%, #cc0000)); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -webkit-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -moz-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -o-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -ms-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, linear-gradient(#ff0000, #cc0000); } -.cms table.ss-gridfield-table tr th button.ss-gridfield-button-reset.ss-ui-button:active { background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ff0000), color-stop(100%, #cc0000)); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -webkit-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -moz-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -o-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -ms-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, linear-gradient(#ff0000, #cc0000); -moz-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); -webkit-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); -o-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); } +.cms table.ss-gridfield-table tr th button.ss-gridfield-button-reset.ss-ui-button.filtered:hover { background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ff0000), color-stop(100%, #cc0000)); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -webkit-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -moz-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -o-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -ms-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, linear-gradient(#ff0000, #cc0000); } +.cms table.ss-gridfield-table tr th button.ss-gridfield-button-reset.ss-ui-button.filtered:active { background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #ff0000), color-stop(100%, #cc0000)); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -webkit-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -moz-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -o-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, -ms-linear-gradient(#ff0000, #cc0000); background: url(../images/icons/filter-icons.png) no-repeat 8px -17px, linear-gradient(#ff0000, #cc0000); -moz-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); -webkit-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); -o-box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); box-shadow: inset 0 1px 3px #17181a, 0 1px 0 rgba(255, 255, 255, 0.6); } .cms table.ss-gridfield-table tr th input.ss-gridfield-sort { padding: 2px; } .cms table.ss-gridfield-table tr th input.ss-gridfield-sort:focus { -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; } -.cms table.ss-gridfield-table tr th span.non-sortable { padding: .4em 1em; } +.cms table.ss-gridfield-table tr th span.non-sortable { padding: 1em 1em; display: block; } .cms table.ss-gridfield-table tr td { border-right: 1px solid rgba(0, 0, 0, 0.1); padding: 6.4px 12px; color: #666666; } .cms table.ss-gridfield-table tr td.bottom-all { -moz-border-radius-bottomleft: 7px; -webkit-border-bottom-left-radius: 7px; -o-border-bottom-left-radius: 7px; -ms-border-bottom-left-radius: 7px; -khtml-border-bottom-left-radius: 7px; border-bottom-left-radius: 7px; -moz-border-radius-bottomright: 7px; -webkit-border-bottom-right-radius: 7px; -o-border-bottom-right-radius: 7px; -ms-border-bottom-right-radius: 7px; -khtml-border-bottom-right-radius: 7px; border-bottom-right-radius: 7px; background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #b1c0c5), color-stop(100%, #7f9198)); background-image: -webkit-linear-gradient(#b1c0c5, #7f9198); background-image: -moz-linear-gradient(#b1c0c5, #7f9198); background-image: -o-linear-gradient(#b1c0c5, #7f9198); background-image: -ms-linear-gradient(#b1c0c5, #7f9198); background-image: linear-gradient(#b1c0c5, #7f9198); } +.cms table.ss-gridfield-table tr td.bottom-all .datagrid-pagination { padding-top: 2px; position: absolute; left: 50%; margin-left: -116px; } +.cms table.ss-gridfield-table tr td.bottom-all .datagrid-pagination .pagination-page-number { color: white; } +.cms table.ss-gridfield-table tr td.bottom-all .datagrid-pagination .pagination-page-number input { width: 35px; height: 20px; margin-bottom: -6px; padding: 0px; } +.cms table.ss-gridfield-table tr td.bottom-all .datagrid-pagination button.ss-gridfield-previouspage { background: url(../images/icons/pagination-arrows.png) no-repeat -23px 7px; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; border: none; width: 10px; margin: 0 10px; } +.cms table.ss-gridfield-table tr td.bottom-all .datagrid-pagination button.ss-gridfield-previouspage span { text-indent: -9999em; } +.cms table.ss-gridfield-table tr td.bottom-all .datagrid-pagination button.ss-gridfield-nextpage { background: url(../images/icons/pagination-arrows.png) no-repeat -47px 7px; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; border: none; width: 10px; margin: 0 10px; } +.cms table.ss-gridfield-table tr td.bottom-all .datagrid-pagination button.ss-gridfield-nextpage span { text-indent: -9999em; } +.cms table.ss-gridfield-table tr td.bottom-all .datagrid-pagination button.ss-gridfield-firstpage { background: url(../images/icons/pagination-arrows.png) no-repeat 0px 7px; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; border: none; width: 10px; margin: 0 10px; } +.cms table.ss-gridfield-table tr td.bottom-all .datagrid-pagination button.ss-gridfield-firstpage span { text-indent: -9999em; } +.cms table.ss-gridfield-table tr td.bottom-all .datagrid-pagination button.ss-gridfield-lastpage { background: url(../images/icons/pagination-arrows.png) no-repeat -73px 7px; -moz-box-shadow: none; -webkit-box-shadow: none; box-shadow: none; border: none; width: 10px; margin: 0 10px; } +.cms table.ss-gridfield-table tr td.bottom-all .datagrid-pagination button.ss-gridfield-lastpage span { text-indent: -9999em; } +.cms table.ss-gridfield-table tr td.bottom-all .pagination-records-number { float: right; padding: 6px 0; color: white; } .cms table.ss-gridfield-table tr.last td { border-bottom: 0 none; } .cms table.ss-gridfield-table td:first-child, .cms table.ss-gridfield-table th:first-child { border-left: 1px solid rgba(0, 0, 0, 0.1); } diff --git a/docs/en/changelogs/3.0.0.md b/docs/en/changelogs/3.0.0.md index 7d6e38d44..ed49257a6 100644 --- a/docs/en/changelogs/3.0.0.md +++ b/docs/en/changelogs/3.0.0.md @@ -192,3 +192,4 @@ BreadcrumbsTemplate.ss from cms/template to your theme or application. * `DataObjectLog`: There is no replacement for this. * `GeoIP`: Moved to separate ["geoip" module](https://github.com/silverstripe-labs/silverstripe-geoip) * `NZGovtPasswordValidator`: Moved to ["securityextras" module](https://github.com/silverstripe-labs/silverstripe-securityextras) +* `MemberTableField`: Use GridField with GridFieldConfig_RelationEditor instead diff --git a/docs/en/reference/cms-architecture.md b/docs/en/reference/cms-architecture.md index 9773beb90..63f6117ff 100644 --- a/docs/en/reference/cms-architecture.md +++ b/docs/en/reference/cms-architecture.md @@ -36,6 +36,7 @@ Each file describes its purpose at the top of the declarations. Note that you ca plain CSS without SCSS for your custom CMS interfaces as well, we just mandate SCSS for core usage. As there's a whole lot of CSS driving the CMS, we have certain best practives around writing it: + * Use the `id` attribute sparingly. Remember that it "closes off" the structure to code reuse, as HTML elements require unique `id` attributes. Code reuse can happen both in CSS and JavaScript behaviour. * Separate presentation from structure in class names, e.g. `left-menu` is encoding the component position @@ -178,6 +179,56 @@ Alternatively, form-related Ajax calls can be invoked through their own wrappers which don't cause history events and hence allow callbacks: `$('.cms-content').loadForm()` and `$('.cms-content').submitForm()`. +## State through HTTP response metadata + +By loading mostly HTML responses, we don't have an easy way to communicate +information which can't be directly contained in the produced HTML. +For example, the currently used controller class might've changed due to a "redirect", +which affects the currently active menu entry. We're using HTTP response headers to contain this data +without affecting the response body. + + :::php + class MyController extends LeftAndMain { + class myaction() { + // ... + $this->response->addHeader('X-Controller', 'MyOtherController'); + return $html; + } + } + +Built-in headers are: + + * `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. + +## Special Links + +Some links should do more than load a new page in the browser window. +To avoid repetition, we've written some helpers for various use cases: + + * Load into a panel: `` + * Load via ajax, and show response status message: `` + * Load URL as an iframe into a popup/dialog: `` + +## Buttons + +SilverStripe automatically applies a [jQuery UI button style](http://jqueryui.com/demos/button/) +to all elements with the class `.ss-ui-button`. We've extended the jQuery UI widget a bit +to support defining icons via HTML5 data attributes (see `ssui.core.js`). +These icon identifiers relate to icon files in `sapphire/admin/images/btn-icons`, +and are sprited into a single file through SCSS and the Compass framework +(see [tutorial](http://compass-style.org/help/tutorials/spriting/)). +Compass also creates the correct CSS classes to show those sprites via background images +(see `sapphire/admin/scss/_sprites.scss`). + +Input: `Button text` + +Output: `Button text` + +Note that you can create buttons from pretty much any element, although +when using an input of type button, submit or reset, support is limited to plain text labels with no icons. + ## Menu The navigation menu in the CMS is created through the `[api:CMSMenu]` API, diff --git a/docs/en/topics/grid-field.md b/docs/en/topics/grid-field.md index 7739c7627..ce3e6e834 100644 --- a/docs/en/topics/grid-field.md +++ b/docs/en/topics/grid-field.md @@ -2,7 +2,7 @@ The `GridField` is a flexible form field for creating tables of data. It's new in SilverStripe 3.0 and replaces `ComplexTableField`, `TableListField`, and `TableField`. It's built as a lean core with a number of components that you plug into it. By selecting from the components that we provide or writing your own, you can grid a wide variety of grid controls. -# Using GridField +## Using GridField A GridField is created like any other field: you create an instance of the GridField object and add it to the fields of a form. At its simplest, GridField takes 3 arguments: field name, field title, and an `SS_List` of records to display. @@ -19,11 +19,11 @@ This example might come from a Controller designed to manage the members of a gr Note that the only way to specify the data that is listed in a grid field is with `SS_List` argument. If you want to customise the data displayed, you can do so by customising this object. -This will create a read-only grid field that will show the columns specified in the Member's `$summary_fields` setting, and will let you sort and/or filter by those columns, as well as show pagination controls with 25 records per page. +This will create a read-only grid field that will show the columns specified in the Member's `$summary_fields` setting, and will let you sort and/or filter by those columns, as well as show pagination controls with a handful of records per page. -## GridFieldConfig +## GridFieldConfig: Portable configuration -This grid create above a useful default case, but when developing applications you may need to control the behaviour of your grid more precisely than this. To this end, the `GridField` constructor allows for 4th argument, `$config`, where you can pass a `GridFieldConfig` object. +The example above a useful default case, but when developing applications you may need to control the behaviour of your grid more precisely than this. To this end, the `GridField` constructor allows for fourth argument, `$config`, where you can pass a `GridFieldConfig` object. This example creates exactly the same kind of grid as the previous example, but it creates the configuration manually: @@ -49,10 +49,12 @@ If we wanted to make a simpler grid without pagination or filtering, we could do $config->addComponent(new GridFieldPaginator(25)); $field = new GridField("Members", "Members of this group", $this->group->Members(), $config); -A `GridFieldConfig` is made up of a new of `GridFieldComponent` objects. `GridFieldComponent` is a family of interfaces. +A `GridFieldConfig` is made up of a new of `GridFieldComponent` objects, which are described in the next chapter. -## Built-in components +## GridFieldComponent: Modular features + +`GridFieldComponent` is a family of interfaces. SilverStripe Framework comes with the following components that you can use out of the box. ### GridFieldDefaultColumns @@ -91,7 +93,7 @@ You can also specify formatting replacements, to replace column contents with HT 'Email' => '$Email', )); -**EXPERIMENTAL API WARNING:** We will most likely refactor this so that this configuration methods are called on the component rather than the grid field. Whoever does this should also update this documentation page. :-) +**EXPERIMENTAL API WARNING:** We will most likely refactor this so that this configuration methods are called on the component rather than the grid field. ### GridFieldSortableHeader @@ -105,7 +107,40 @@ This component will add a header row with a text field filter for each column, l This component will limit output to a fixed number of items per page add a footer row with pagination controls. The constructor takes 1 argument: the number of items per page. -# Extending GridField with custom components +### GridFieldAction + +TODO Describe component, including GridFieldEditAction/GridFieldDeleteAction + +### GridFieldRelationAdd + +This class is is responsible for adding objects to another object's has_many and many_many relation, +as defined by the `[api:RelationList]` passed to the GridField constructor. +Objects can be searched through an input field (partially matching one or more fields). +Selecting from the results will add the object to the relation. +Often used alongside `[api:GridFieldRelationDelete]` for detaching existing records from a relatinship. +For easier setup, have a look at a sample configuration in `[api:GridFieldConfig_RelationEditor]`. + +### GridFieldRelationDelete + +Allows to detach an item from an existing has_many or many_many relationship. +Similar to {@link GridFieldDeleteAction}, but allows to distinguish between +a "delete" and "detach" action in the UI - and to use both in parallel, if required. +Requires the GridField to be populated with a `[api:RelationList]` rather than a plain DataList. +Often used alongside `[api:GridFieldRelationAdd]` to add existing records to the relationship. + +### GridFieldPopupForms + +TODO Describe component, including how it relates to GridFieldEditAction. Point to GridFieldConfig_RelationEditor for easier defaults. + +### GridFieldTitle + +TODO + +### GridFieldExporter + +TODO + +## Extending GridField with custom components You can create a custom component by building a class that implements one or more of the following interfaces: `GridField_HTMLProvider`, `GridField_ColumnProvider`, `GridField_ActionProvider`, or `GridField_DataManipulator`. @@ -196,7 +231,7 @@ To provide your actions, define the following two functions: * **`function getActions($gridField)`:** Return a list of actions that this component provides. There is no namespacing on these actions, so you need to ensure that they don't conflict with other components. * **`function handleAction(GridField $gridField, $actionName, $arguments, $data)`:** Handle the action defined by `$actionName` and `$arguments`. `$data` will contain the full data from the form, if you need to access that. -To call your actions, you need to create `GridField_Action` elsewhere in your component. Read more about them below. +To call your actions, you need to create `GridField_FormAction` elsewhere in your component. Read more about them below. **EXPERIMENTAL API WARNING:** handleAction implementations often contain a big switch statement and this interface might be amended on, such that each action is defined in a separate method. If we do this, it will be done before 3.0 stable so that we can lock down the API, but early adopters should be aware of this potential for change! diff --git a/filesystem/File.php b/filesystem/File.php index 22b75708b..60d9f3b7e 100644 --- a/filesystem/File.php +++ b/filesystem/File.php @@ -363,7 +363,11 @@ class File extends DataObject { )->setName("FilePreview")->addExtraClass('cms-file-info'); $urlField->dontEscape = true; - return new FieldList( + //get a tree listing with only folder, no files + $folderTree = new TreeDropdownField("ParentID", _t('AssetTableField.FOLDER','Folder'), 'Folder'); + $folderTree->setChildrenMethod('ChildFolders'); + + $fields = new FieldList( new TabSet('Root', new Tab('Main', $filePreview, @@ -371,11 +375,15 @@ class File extends DataObject { // $uploadField, new TextField("Title", _t('AssetTableField.TITLE','Title')), new TextField("Name", _t('AssetTableField.FILENAME','Filename')), - new DropdownField("OwnerID", _t('AssetTableField.OWNER','Owner'), Member::mapInCMSGroups()) + new DropdownField("OwnerID", _t('AssetTableField.OWNER','Owner'), Member::mapInCMSGroups()), + $folderTree ) ) ); + + return $fields; } + /** * Returns a category based on the file extension. diff --git a/forms/AjaxUniqueTextField.php b/forms/AjaxUniqueTextField.php index ffdadde24..b8b73d627 100644 --- a/forms/AjaxUniqueTextField.php +++ b/forms/AjaxUniqueTextField.php @@ -47,7 +47,7 @@ class AjaxUniqueTextField extends TextField { 'id' => $this->id(), 'name' => $this->getName(), 'value' => $this->Value(), - 'tabindex' => $this->getTabIndex(), + 'tabindex' => $this->getAttribute('tabindex'), 'maxlength' => ($this->maxLength) ? $this->maxLength : null ); diff --git a/forms/CheckboxSetField.php b/forms/CheckboxSetField.php index 2c0a44bed..84f976408 100644 --- a/forms/CheckboxSetField.php +++ b/forms/CheckboxSetField.php @@ -181,21 +181,16 @@ class CheckboxSetField extends OptionsetField { * @param DataObject $record The record to save into */ function saveInto(DataObject $record) { - $fieldname = $this->name ; - if($fieldname && $record && ($record->has_many($fieldname) || $record->many_many($fieldname))) { + $fieldname = $this->name; + $relation = ($fieldname && $record && $record->hasMethod($fieldname)) ? $record->$fieldname() : null; + if($fieldname && $record && $relation && $relation instanceof RelationList) { $idList = array(); - // Works for both style - array('val1' => true, 'val2' => true). - // The name}[3]\" value=\"$parts[3]\" maxlength=\"4\"" . $this->getTabIndexHTML(3) . " />"; return $field; } + + /** + * Get tabindex HTML string + * + * @param int $increment Increase current tabindex by this value + * @return string + */ + protected function getTabIndexHTML($increment = 0) { + $tabIndex = (int)$this->getTabIndex() + (int)$increment; + return (is_numeric($tabIndex)) ? ' tabindex = "' . $tabIndex . '"' : ''; + } function dataValue() { if(is_array($this->value)) return implode("", $this->value); diff --git a/forms/FormField.php b/forms/FormField.php index 15d39773e..44e79aabb 100644 --- a/forms/FormField.php +++ b/forms/FormField.php @@ -50,13 +50,6 @@ class FormField extends RequestHandler { */ protected $leftTitle; - /** - * Set the "tabindex" HTML attribute on the field. - * - * @var int - */ - protected $tabIndex; - /** * Stores a reference to the FieldList that contains this object. * @var FieldList @@ -225,32 +218,26 @@ class FormField extends RequestHandler { * Set tabindex HTML attribute * (defaults to none). * + * @deprecated 3.0 Use setAttribute("tabindex") instead * @param int $index */ public function setTabIndex($index) { - $this->tabIndex = $index; + Deprecation::notice('3.0', 'Use setAttribute("tabindex") instead'); + $this->setAttribute($index); return $this; } /** * Get tabindex (if previously set) + * + * @deprecated 3.0 Use getAttribute("tabindex") instead * @return int */ public function getTabIndex() { - return $this->tabIndex; + Deprecation::notice('3.0', 'Use getAttribute("tabindex") instead'); + return $this->getAttribute('tabindex'); } - /** - * Get tabindex HTML string - * - * @param int $increment Increase current tabindex by this value - * @return string - */ - protected function getTabIndexHTML($increment = 0) { - $tabIndex = (int)$this->getTabIndex() + (int)$increment; - return (is_numeric($tabIndex)) ? ' tabindex = "' . $tabIndex . '"' : ''; - } - /** * Compiles all CSS-classes. Optionally includes a "nolabel"-class * if no title was set on the formfield. @@ -301,6 +288,12 @@ class FormField extends RequestHandler { /** * Set an HTML attribute on the field element, mostly an tag. * + * Some attributes are best set through more specialized methods, to avoid interfereing with built-in behaviour: + * - 'class': {@link addExtraClass()} + * - 'title': {@link setDescription()} + * - 'value': {@link setValue} + * - 'name': {@link setName} + * * CAUTION Doesn't work on most fields which are composed of more than one HTML form field: * AjaxUniqueTextField, CheckboxSetField, ComplexTableField, CompositeField, ConfirmedPasswordField, CountryDropdownField, * CreditCardField, CurrencyField, DateField, DatetimeField, FieldGroup, GridField, HtmlEditorField, @@ -335,8 +328,8 @@ class FormField extends RequestHandler { 'value' => $this->Value(), 'class' => $this->extraClass(), 'id' => $this->ID(), - 'tabindex' => $this->getTabIndex(), 'disabled' => $this->isDisabled(), + 'title' => $this->getDescription(), ); return array_merge($attrs, $this->attributes); } @@ -689,16 +682,24 @@ class FormField extends RequestHandler { return true; } + /** + * @deprecated 3.0 Use setDescription() + */ + function describe($description) { + Deprecation::notice('3.0', 'Use setDescription()'); + $this->setDescription($description); + return $this; + } + /** * Describe this field, provide help text for it. - * The function returns this so it can be used like this: - * $action = FormAction::create('submit', 'Submit')->describe("Send your changes to be approved") + * By default, renders as a "title" attribute on the form field. * * @return string Description */ - function describe($description) { + function setDescription($description) { $this->description = $description; - return $this; + return $this; } /** diff --git a/forms/HasManyComplexTableField.php b/forms/HasManyComplexTableField.php index acc651500..625734585 100644 --- a/forms/HasManyComplexTableField.php +++ b/forms/HasManyComplexTableField.php @@ -27,6 +27,8 @@ * * @see http://doc.silverstripe.org/tutorial/5-dataobject-relationship-management * + * @deprecated 3.0 Use GridField with GridFieldConfig_RelationEditor + * * @package forms * @subpackage fields-relational */ @@ -48,6 +50,8 @@ class HasManyComplexTableField extends ComplexTableField { function __construct($controller, $name, $sourceClass, $fieldList = null, $detailFormFields = null, $sourceFilter = "", $sourceSort = "", $sourceJoin = "") { parent::__construct($controller, $name, $sourceClass, $fieldList, $detailFormFields, $sourceFilter, $sourceSort, $sourceJoin); + + Deprecation::notice('3.0', 'Use GridField with GridFieldConfig_RelationEditor'); $this->Markable = true; diff --git a/forms/HtmlEditorField.php b/forms/HtmlEditorField.php index 271087b3d..a372676b8 100644 --- a/forms/HtmlEditorField.php +++ b/forms/HtmlEditorField.php @@ -13,7 +13,7 @@ class HtmlEditorField extends TextareaField { */ static $use_gzip = true; - protected $rows = 30; + protected $rows = null; /** * Includes the JavaScript neccesary for this field to work using the {@link Requirements} system. @@ -90,7 +90,6 @@ class HtmlEditorField extends TextareaField { parent::getAttributes(), array( 'tinymce' => 'true', - 'style' => 'width: 97%; height: ' . ($this->rows * 16) . 'px', // prevents horizontal scrollbars 'value' => null, ) ); diff --git a/forms/ListboxField.php b/forms/ListboxField.php index 81701bcb0..c52df9f8b 100644 --- a/forms/ListboxField.php +++ b/forms/ListboxField.php @@ -40,6 +40,16 @@ class ListboxField extends DropdownField { * @var boolean */ protected $multiple = false; + + /** + * @var Array + */ + protected $disabledItems = array(); + + /** + * @var Array + */ + protected $defaultItems = array(); /** * Creates a new dropdown field. @@ -61,43 +71,31 @@ class ListboxField extends DropdownField { * Returns a ' + ); + var addbutton = $(this).closest(".ss-gridfield").find("#action_gridfield_relationadd"); + if(addbutton.data('button')){ + addbutton.button('enable'); + }else{ + addbutton.removeAttr('disabled'); + } + } + }); + } + }); + + $(".ss-gridfield .pagination-page-number input").entwine({ + onkeydown: function(event) { + if(event.keyCode == 13) { + var newpage = parseInt($(this).val(), 10); + + var gridfield = $(this).getGridField(); + gridfield.setState('GridFieldPaginator', {currentPage: newpage}); + gridfield.reload(); + return false; } } diff --git a/javascript/GridFieldSearch.js b/javascript/GridFieldSearch.js deleted file mode 100644 index d745e96ab..000000000 --- a/javascript/GridFieldSearch.js +++ /dev/null @@ -1,41 +0,0 @@ -jQuery(function($){ - - $(document).delegate(".ss-gridfield .relation-search", "focus", function (event) { - $(this).autocomplete({ - source: function(request, response){ - var searchField = $(this.element); - var form = $(this.element).closest("form"); - // Due to some very weird behaviout of jquery.metadata, the url have to be double quoted - var suggestionUrl = $(searchField).attr('data-search-url').substr(1,$(searchField).attr('data-search-url').length-2); - $.ajax({ - headers: { - "X-Get-Fragment" : 'Partial' - }, - type: "GET", - url: suggestionUrl+'/'+request.term, - data: form.serialize()+'&'+escape(searchField.attr('name'))+'='+escape(searchField.val()), - success: function(data) { - response( $.map(JSON.parse(data), function( name, id ) { - return { label: name, value: name, id: id }; - })); - }, - error: function(e) { - alert(ss.i18n._t('GRIDFIELD.ERRORINTRANSACTION', 'An error occured while fetching data from the server\n Please try again later.')); - } - }); - }, - select: function(event, ui) { - $(this).closest(".ss-gridfield").find("#action_gridfield_relationfind").replaceWith( - '' - ); - var addbutton = $(this).closest(".ss-gridfield").find("#action_gridfield_relationadd"); - if(addbutton.data('button')){ - addbutton.button('enable'); - }else{ - addbutton.removeAttr('disabled'); - } - } - }); - }); - -}); \ No newline at end of file diff --git a/javascript/MemberDatetimeOptionsetField.js b/javascript/MemberDatetimeOptionsetField.js deleted file mode 100644 index a88feae02..000000000 --- a/javascript/MemberDatetimeOptionsetField.js +++ /dev/null @@ -1,7 +0,0 @@ -(function($) { - $('.formattingHelpText').hide(); - $('.formattingHelpToggle').click(function() { - $(this).parent().find('.formattingHelpText').toggle(); - return false; - }) -})(jQuery); \ No newline at end of file diff --git a/javascript/PermissionCheckboxSetField.js b/javascript/PermissionCheckboxSetField.js index 8a40111f4..46548d494 100644 --- a/javascript/PermissionCheckboxSetField.js +++ b/javascript/PermissionCheckboxSetField.js @@ -8,6 +8,11 @@ * checking all boxes is purely presentational. */ $('.permissioncheckboxset .valADMIN input').entwine({ + onmatch: function() { + this._super(); + + this.toggleCheckboxes(); + }, onclick: function(e) { this.toggleCheckboxes(); }, @@ -26,8 +31,8 @@ // only update attributes if previous values have been saved var oldChecked = $(this).data('SecurityAdmin.oldChecked'); var oldDisabled = $(this).data('SecurityAdmin.oldDisabled'); - if(oldChecked != null) $(this).attr('checked', oldChecked); - if(oldDisabled != null) $(this).attr('disabled', oldDisabled); + if(oldChecked !== null) $(this).attr('checked', oldChecked); + if(oldDisabled !== null) $(this).attr('disabled', oldDisabled); }); } } diff --git a/javascript/TreeDropdownField.js b/javascript/TreeDropdownField.js index 91cc00f31..588475863 100644 --- a/javascript/TreeDropdownField.js +++ b/javascript/TreeDropdownField.js @@ -306,7 +306,7 @@ $('.TreeDropdownField.multiple').entwine({ getTreeConfig: function() { var cfg = this._super(); - cfg.checkbox = {override_ui: true}; + cfg.checkbox = {override_ui: true, two_state: true}; cfg.plugins.push('checkbox'); cfg.ui.select_limit = -1; return cfg; diff --git a/lang/en_US.php b/lang/en_US.php index 93ed18602..a09a58066 100644 --- a/lang/en_US.php +++ b/lang/en_US.php @@ -281,7 +281,7 @@ $lang['en_US']['Group']['Parent'] = array( PR_MEDIUM, 'One group has one parent group' ); -$lang['en_US']['Group']['RolesAddEditLink'] = 'Add/edit roles'; +$lang['en_US']['Group']['RolesAddEditLink'] = 'Manage roles'; $lang['en_US']['Group']['SINGULARNAME'] = array( 'Group', 50, @@ -716,7 +716,7 @@ $lang['en_US']['Security']['PASSWORDSENTHEADER'] = 'Password reset link sent to $lang['en_US']['Security']['PASSWORDSENTTEXT'] = 'Thank you! A reset link has been sent to \'%s\', provided an account exists for this email address.'; $lang['en_US']['SecurityAdmin']['ADDMEMBER'] = 'Add Member'; $lang['en_US']['SecurityAdmin']['APPLY_ROLES'] = 'Apply roles to groups'; -$lang['en_US']['SecurityAdmin']['APPLY_ROLES_HELP'] = 'Ability to edit the roles assigned to a group. Requires the "Access to \'Security\' section" permission.'; +$lang['en_US']['SecurityAdmin']['APPLY_ROLES_HELP'] = 'Ability to edit the roles assigned to a group. Requires the "Access to \'Users\' section" permission.'; $lang['en_US']['SecurityAdmin']['EDITPERMISSIONS'] = 'Manage permissions for groups'; $lang['en_US']['SecurityAdmin']['EDITPERMISSIONS_HELP'] = 'Ability to edit Permissions and IP Addresses for a group. Requires the "Access to \'Security\' section" permission.'; $lang['en_US']['SecurityAdmin']['GROUPNAME'] = 'Group name'; @@ -730,7 +730,7 @@ $lang['en_US']['SecurityAdmin']['MemberListCaution'] = 'Caution: Removing member $lang['en_US']['SecurityAdmin']['NEWGROUP'] = 'New Group'; $lang['en_US']['SecurityAdmin']['PERMISSIONS'] = 'Permissions'; $lang['en_US']['SecurityAdmin']['ROLES'] = 'Roles'; -$lang['en_US']['SecurityAdmin']['ROLESDESCRIPTION'] = 'This section allows you to add roles to this group. Roles are logical groupings of permissions, which can be editied in the Roles tab'; +$lang['en_US']['SecurityAdmin']['ROLESDESCRIPTION'] = 'Roles are predefined sets of permissions, and can be assigned to groups.
                      They are inherited from parent groups if required.'; $lang['en_US']['SecurityAdmin']['SGROUPS'] = 'Security Groups'; $lang['en_US']['SecurityAdmin']['TABIMPORT'] = 'Import'; $lang['en_US']['SecurityAdmin']['TABROLES'] = 'Roles'; diff --git a/model/DataObject.php b/model/DataObject.php index 8b8cb300a..ca972f6b2 100644 --- a/model/DataObject.php +++ b/model/DataObject.php @@ -1320,7 +1320,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity $result = new HasManyList($componentClass, $joinField); if($this->model) $result->setModel($this->model); - if($this->ID) $result->setForeignID($this->ID); + $result->setForeignID($this->ID); $result = $result->where($filter)->limit($limit)->sort($sort); if($join) $result = $result->join($join); @@ -1412,7 +1412,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity // If this is called on a singleton, then we return an 'orphaned relation' that can have the // foreignID set elsewhere. - if($this->ID) $result->setForeignID($this->ID); + $result->setForeignID($this->ID); return $result->where($filter)->sort($sort)->limit($limit); } diff --git a/model/DataQuery.php b/model/DataQuery.php index 25a44f4ab..a11dca4e0 100644 --- a/model/DataQuery.php +++ b/model/DataQuery.php @@ -62,7 +62,7 @@ class DataQuery { } } - if(!$matched) user_error("Couldn't find $fieldExpression in the query filter.", E_USER_WARNING); + if(!$matched) throw new InvalidArgumentException("Couldn't find $fieldExpression in the query filter."); return $this; } diff --git a/model/HasManyList.php b/model/HasManyList.php index 5be23c927..3d38bb52e 100644 --- a/model/HasManyList.php +++ b/model/HasManyList.php @@ -26,7 +26,7 @@ class HasManyList extends RelationList { if(is_array($this->foreignID)) { return "\"$this->foreignKey\" IN ('" . implode("', '", array_map('Convert::raw2sql', $this->foreignID)) . "')"; - } else if($this->foreignID){ + } else if($this->foreignID !== null){ return "\"$this->foreignKey\" = '" . Convert::raw2sql($this->foreignID) . "'"; } diff --git a/model/ManyManyList.php b/model/ManyManyList.php index 76e4db2b8..70fd32245 100644 --- a/model/ManyManyList.php +++ b/model/ManyManyList.php @@ -73,7 +73,7 @@ class ManyManyList extends RelationList { if(is_array($this->foreignID)) { return "\"$this->joinTable\".\"$this->foreignKey\" IN ('" . implode("', '", array_map('Convert::raw2sql', $this->foreignID)) . "')"; - } else if($this->foreignID){ + } else if($this->foreignID !== null){ return "\"$this->joinTable\".\"$this->foreignKey\" = '" . Convert::raw2sql($this->foreignID) . "'"; } @@ -93,25 +93,24 @@ class ManyManyList extends RelationList { if(!$this->foreignID) { throw new Exception("ManyManyList::add() can't be called until a foreign ID is set", E_USER_WARNING); } - if(is_array($this->foreignID)) { - throw new Exception("ManyManyList::add() can't be called on a list linked to mulitple foreign IDs", E_USER_WARNING); - } - + // Delete old entries, to prevent duplication $this->removeById($itemID); - // Insert new entry - $manipulation = array(); - $manipulation[$this->joinTable]['command'] = 'insert'; + // Insert new entry/entries + foreach((array)$this->foreignID as $foreignID) { + $manipulation = array(); + $manipulation[$this->joinTable]['command'] = 'insert'; - if($extraFields) foreach($extraFields as $k => $v) { - $manipulation[$this->joinTable]['fields'][$k] = "'" . Convert::raw2sql($v) . "'"; + if($extraFields) foreach($extraFields as $k => $v) { + $manipulation[$this->joinTable]['fields'][$k] = "'" . Convert::raw2sql($v) . "'"; + } + + $manipulation[$this->joinTable]['fields'][$this->localKey] = $itemID; + $manipulation[$this->joinTable]['fields'][$this->foreignKey] = $foreignID; + + DB::manipulate($manipulation); } - - $manipulation[$this->joinTable]['fields'][$this->localKey] = $itemID; - $manipulation[$this->joinTable]['fields'][$this->foreignKey] = $this->foreignID; - - DB::manipulate($manipulation); } /** diff --git a/model/RelationList.php b/model/RelationList.php index 27f72f6d0..993769a79 100644 --- a/model/RelationList.php +++ b/model/RelationList.php @@ -14,11 +14,21 @@ abstract class RelationList extends DataList { * @param $id A single ID, or an array of IDs */ function setForeignID($id) { + // If already filtered on foreign ID, remove that first + if($this->foreignID !== null) { + $oldFilter = $this->foreignIDFilter(); + try { + $this->dataQuery->removeFilterOn($oldFilter); + } catch(InvalidArgumentException $e) {} + } + // Turn a 1-element array into a simple value if(is_array($id) && sizeof($id) == 1) $id = reset($id); $this->foreignID = $id; $this->dataQuery->where($this->foreignIDFilter()); + + return $this; } /** diff --git a/scss/GridField.scss b/scss/GridField.scss index ffb28e3d6..685a8de4d 100644 --- a/scss/GridField.scss +++ b/scss/GridField.scss @@ -26,6 +26,7 @@ $gf_color_border_filter_button: #9A9A9A; $gf_color_button: #e6e6e6; $gf_color_button_filter_hover: #338DC1; $gf_color_button_reset_hover: #FF0000; +$color-text-light: white; $gf_grid_y: 12px; $gf_grid_x: 16px; @@ -39,7 +40,7 @@ $gf_grid_x: 16px; .cms { .ss-gridfield { & > div { - margin-bottom: 35px; + margin-bottom: $gf_grid_y*3 - 1; } &[data-selectable] { @@ -64,36 +65,44 @@ $gf_grid_x: 16px; thead { color: darken($gf_colour_base, 50%); background: transparent; + tr.filter-header { + .fieldgroup { + max-width:$gf_grid_x*32; + } + } } tbody { background: #FFF; td { - /* Emulate a link by default */ button { border: none; background: none; - margin: 0 0 0 2px; + margin: 0 0 0 $gf_grid_x/8; padding: 0; width: auto; text-shadow: none; - &.ui-state-hover { + &.gridfield-button-delete.ui-state-hover { background:none; + @include box-shadow-none; + } + &.gridfield-button-delete.ui-state-active { border:none; @include box-shadow-none; } - span.ui-button-text { - text-indent:-9999em; - background: url(../images/icons/decline.png) no-repeat 0 2px; - padding:0; - width:20px; - height:20px; + &.gridfield-button-unlink.ui-state-hover { + background:none; + @include box-shadow-none; + } + &.gridfield-button-unlink.ui-state-active { + border:none; + @include box-shadow-none; } } a.edit-link { display:inline-block; - height:20px; - width:20px; + width:$gf_grid_x + 4; + height:$gf_grid_y*2 - 4; text-indent:-9999em; background: url(../images/icons/document--pencil.png) no-repeat 0 1px; } @@ -119,7 +128,7 @@ $gf_grid_x: 16px; background: $gf_colour_gradient_dark; border-top: 1px solid $gf_colour_border; padding: 5px; - min-height: 40px; + min-height: $gf_grid_y*3 + 4; @include background-image(linear-gradient($gf_colour_gradient_light, $gf_colour_gradient_dark)); @include border-top-radius($gf_border_radius); @include single-text-shadow($gf_colour_text_shadow, 0px, -1px, 0); @@ -127,12 +136,11 @@ $gf_grid_x: 16px; padding: 0px; font-size: $gf_grid_y*1.4; color:#fff; - margin:3px $gf_grid_x/2 0; + margin:$gf_grid_y/4 $gf_grid_x/2 0; display:inline-block; } .new{ font-size: $gf_grid_y*1.2; - border-color: $gf_colour_border; float: right; } } @@ -179,7 +187,7 @@ $gf_grid_x: 16px; position:relative; } &.fieldgroup { - min-width: 200px; + min-width: $gf_grid_x*12.5; padding-right:0; } } @@ -201,7 +209,6 @@ $gf_grid_x: 16px; span{ @include single-text-shadow($gf_colour_text_shadow, 0px, -1px, 0); } - } &.extra { background: $gf_colour_subheader; @@ -212,7 +219,7 @@ $gf_grid_x: 16px; display: inline; position: static; input { - height:28px; + height:$gf_grid_y*2 + 4; } } button.ss-ui-button { @@ -247,7 +254,7 @@ $gf_grid_x: 16px; border:none; width:100%; text-align: left; - padding: 4px 0; + padding: $gf_grid_y/3 0; @include single-text-shadow($gf_colour_text_shadow, 0px, -1px, 0); color: #fff; @include border-radius(0); @@ -282,20 +289,20 @@ $gf_grid_x: 16px; lighten($gf_color_button, 10%), darken($gf_color_button, 5%) )); - &:hover { + &.hover-alike:active { @include background (url(../images/icons/filter-icons.png) no-repeat -16px 6px, linear-gradient( lighten($gf_color_button_filter_hover, 5%), darken($gf_color_button_filter_hover, 5%) )); + @include box-shadow(inset 0 1px 3px rgb(23, 24, 26), 0 1px 0 rgba(255, 255, 255, .6)); } - &:active { - @include background (url(../images/icons/filter-icons.png) no-repeat -16px -17px, + &.hover-alike { + @include background (url(../images/icons/filter-icons.png) no-repeat -16px 6px, linear-gradient( lighten($gf_color_button_filter_hover, 5%), darken($gf_color_button_filter_hover, 5%) )); - @include box-shadow(inset 0 1px 3px rgb(23, 24, 26), 0 1px 0 rgba(255, 255, 255, .6)); } } &.ss-gridfield-button-reset.ss-ui-button{ @@ -318,14 +325,14 @@ $gf_grid_x: 16px; darken($gf_color_button, 5%) )) ); - &:hover { + &.filtered:hover { @include background (url(../images/icons/filter-icons.png) no-repeat 8px -17px, linear-gradient( $gf_color_button_reset_hover, darken($gf_color_button_reset_hover, 10%) )); } - &:active { + &.filtered:active { @include background (url(../images/icons/filter-icons.png) no-repeat 8px -17px, linear-gradient( $gf_color_button_reset_hover, @@ -347,7 +354,8 @@ $gf_grid_x: 16px; } span.non-sortable { - padding:.4em 1em; + padding:1em 1em; + display:block; } } @@ -357,7 +365,67 @@ $gf_grid_x: 16px; color: $gf_colour_font; &.bottom-all { @include border-bottom-radius($gf_border_radius); - @include background-image(linear-gradient($gf_colour_gradient_light, $gf_colour_gradient_dark)); + @include background-image(linear-gradient($gf_colour_gradient_light, $gf_colour_gradient_dark)); + .datagrid-pagination { + padding-top:2px; + position:absolute; + left:50%; + margin-left:$gf_grid_x*-7 - 4; + .pagination-page-number { + color:$color-text-light; + input { + width:$gf_grid_x*2 + 3; + height:$gf_grid_y*2 - 4; + margin-bottom:-$gf_grid_y/2; + padding:0px; + } + } + button.ss-gridfield-previouspage { + @include background (url(../images/icons/pagination-arrows.png) no-repeat -23px 7px); + @include box-shadow-none; + border:none; + width:$gf_grid_x - 6; + margin:0 ($gf_grid_x - 6); + span { + text-indent:-9999em; + } + } + button.ss-gridfield-nextpage { + @include background (url(../images/icons/pagination-arrows.png) no-repeat -47px 7px); + @include box-shadow-none; + border:none; + width:$gf_grid_x - 6; + margin:0 ($gf_grid_x - 6); + span { + text-indent:-9999em; + } + } + button.ss-gridfield-firstpage { + @include background (url(../images/icons/pagination-arrows.png) no-repeat 0px 7px); + @include box-shadow-none; + border:none; + width:$gf_grid_x - 6; + margin:0 ($gf_grid_x - 6); + span { + text-indent:-9999em; + } + } + button.ss-gridfield-lastpage { + @include background (url(../images/icons/pagination-arrows.png) no-repeat -73px 7px); + @include box-shadow-none; + border:none; + width:$gf_grid_x - 6; + margin:0 ($gf_grid_x - 6); + span { + text-indent:-9999em; + } + } + } + .pagination-records-number { + float:right; + padding:($gf_grid_y/2) 0; + color:$color-text-light; + } } } &.last td { diff --git a/search/SearchContext.php b/search/SearchContext.php index d28985a6b..282fdd911 100644 --- a/search/SearchContext.php +++ b/search/SearchContext.php @@ -111,8 +111,8 @@ class SearchContext extends Object { * @param string|array $sort Database column to sort on. * Falls back to {@link DataObject::$default_sort} if not provided. * @param string|array $limit - * @param SQLQuery $existingQuery - * @return SQLQuery + * @param DataList $existingQuery + * @return DataList */ public function getQuery($searchParams, $sort = false, $limit = false, $existingQuery = null) { if($existingQuery) { diff --git a/security/Group.php b/security/Group.php index 8925ba472..411c50aea 100755 --- a/security/Group.php +++ b/security/Group.php @@ -55,36 +55,26 @@ class Group extends DataObject { /** * Caution: Only call on instances, not through a singleton. + * The "root group" fields will be created through {@link SecurityAdmin->EditForm()}. * * @return FieldList */ public function getCMSFields() { Requirements::javascript(SAPPHIRE_DIR . '/javascript/PermissionCheckboxSetField.js'); - $config = new GridFieldConfig(); - $config->addComponent(new GridFieldTitle()); - $configs = new GridFieldConfig_ManyManyEditor('FirstName', 20); - $components = $configs->getComponents(); - foreach($components as $component) $config->addComponent($component); - $config->addComponents(new GridFieldExporter()); - - $config->getComponentByType('GridFieldRelationAdd') - ->setResultsFormat('$Title ($Email)')->setSearchFields(array('FirstName', 'Surname', 'Email')); - $memberList = new GridField('Members','Members', $this->Members(), $config); - $memberList->addExtraClass('members_grid'); - - // @todo Implement permission checking on GridField - //$memberList->setPermissions(array('edit', 'delete', 'export', 'add', 'inlineadd')); - //$memberList->setPopupCaption(_t('SecurityAdmin.VIEWUSER', 'View User')); $fields = new FieldList( new TabSet("Root", new Tab('Members', _t('SecurityAdmin.MEMBERS', 'Members'), new TextField("Title", $this->fieldLabel('Title')), - $memberList + $parentidfield = Object::create('DropdownField', + 'ParentID', + $this->fieldLabel('Parent'), + DataList::create('Group')->exclude('ID', $this->ID)->map('ID', 'Breadcrumbs') + )->setEmptyString(' ') ), $permissionsTab = new Tab('Permissions', _t('SecurityAdmin.PERMISSIONS', 'Permissions'), - new PermissionCheckboxSetField( + $permissionsField = new PermissionCheckboxSetField( 'Permissions', false, 'Permission', @@ -95,6 +85,24 @@ class Group extends DataObject { ) ); + $parentidfield->setRightTitle('' . _t('Group.GroupReminder', 'If you choose a parent group, this group will take all it\'s roles') . ''); + + // Filter permissions + // TODO SecurityAdmin coupling, not easy to get to the form fields through GridFieldPopupForms + $permissionsField->setHiddenPermissions(SecurityAdmin::$hidden_permissions); + + if($this->ID) { + $config = new GridFieldConfig_RelationEditor(); + $config->addComponents(new GridFieldExporter()); + $config->getComponentByType('GridFieldRelationAdd') + ->setResultsFormat('$Title ($Email)')->setSearchFields(array('FirstName', 'Surname', 'Email')); + $config->getComponentByType('GridFieldPopupForms')->setValidator(new Member_Validator()); + $memberList = Object::create('GridField', 'Members',false, $this->Members(), $config)->addExtraClass('members_grid'); + // @todo Implement permission checking on GridField + //$memberList->setPermissions(array('edit', 'delete', 'export', 'add', 'inlineadd')); + $fields->addFieldToTab('Root.Members', $memberList); + } + // Only add a dropdown for HTML editor configurations if more than one is available. // Otherwise Member->getHtmlEditorConfigForCMS() will default to the 'cms' configuration. $editorConfigMap = HtmlEditorConfig::get_available_configs_map(); @@ -111,7 +119,6 @@ class Group extends DataObject { if(!Permission::check('EDIT_PERMISSIONS')) { $fields->removeFieldFromTab('Root', 'Permissions'); - $fields->removeFieldFromTab('Root', 'IP Addresses'); } // Only show the "Roles" tab if permissions are granted to edit them, @@ -122,29 +129,45 @@ class Group extends DataObject { new LiteralField( "", "

                      " . - _t('SecurityAdmin.ROLESDESCRIPTION', - "This section allows you to add roles to this group. Roles are logical groupings of permissions, which can be editied in the Roles tab" - ) . + _t( + 'SecurityAdmin.ROLESDESCRIPTION', + "Roles are predefined sets of permissions, and can be assigned to groups.
                      They are inherited from parent groups if required." + ) . '
                      ' . + sprintf( + '%s', + singleton('SecurityAdmin')->Link('show/root#Root_Roles'), + // TODO This should include #Root_Roles to switch directly to the tab, + // but tabstrip.js doesn't display tabs when directly adressed through a URL pragma + _t('Group.RolesAddEditLink', 'Manage roles') + ) . "

                      " ) ); // Add roles (and disable all checkboxes for inherited roles) $allRoles = Permission::check('ADMIN') ? DataObject::get('PermissionRole') : DataObject::get('PermissionRole', 'OnlyAdminCanApply = 0'); - $groupRoles = $this->Roles(); - $inheritedRoles = new ArrayList(); - $ancestors = $this->getAncestors(); - foreach($ancestors as $ancestor) { - $ancestorRoles = $ancestor->Roles(); - if($ancestorRoles) $inheritedRoles->merge($ancestorRoles); + if($this->ID) { + $groupRoles = $this->Roles(); + $inheritedRoles = new ArrayList(); + $ancestors = $this->getAncestors(); + foreach($ancestors as $ancestor) { + $ancestorRoles = $ancestor->Roles(); + if($ancestorRoles) $inheritedRoles->merge($ancestorRoles); + } + $groupRoleIDs = $groupRoles->column('ID') + $inheritedRoles->column('ID'); + $inheritedRoleIDs = $inheritedRoles->column('ID'); + } else { + $groupRoleIDs = array(); + $inheritedRoleIDs = array(); } - $fields->findOrMakeTab('Root.Roles', 'Root.' . _t('SecurityAdmin.ROLES', 'Roles')); - $fields->addFieldToTab( - 'Root.Roles', - $rolesField = new CheckboxSetField('Roles', 'Roles', $allRoles) - ); - $rolesField->setDefaultItems($inheritedRoles->column('ID')); - $rolesField->setDisabledItems($inheritedRoles->column('ID')); + + $rolesField = Object::create('ListboxField', 'Roles', false, $allRoles->map()->toArray()) + ->setMultiple(true) + ->setDefaultItems($groupRoleIDs) + ->setAttribute('data-placeholder', _t('Group.AddRole', 'Add a role for this group')) + ->setDisabledItems($inheritedRoleIDs); + if(!$allRoles->Count()) $rolesField->setAttribute('data-placeholder', _t('Group.NoRoles', 'No roles found')); + $fields->addFieldToTab('Root.Roles', $rolesField); } $fields->push($idField = new HiddenField("ID")); @@ -185,27 +208,26 @@ class Group extends DataObject { } /** - * Overloaded getter. - * - * @TODO Where is this used, why is this overloaded? + * Get many-many relation to {@link Member}, + * including all members which are "inherited" from children groups of this record. + * See {@link DirectMembers()} for retrieving members without any inheritance. * - * @param $limit string SQL - * @param $offset int - * @param $filter string SQL - * @param $sort string SQL - * @param $join string SQL - * @return ComponentSet + * @param String + * @return ManyManyList */ public function Members($filter = "", $sort = "", $join = "", $limit = "") { - // Get a DataList of the relevant groups - $groups = DataList::create("Group")->byIDs($this->collateFamilyIDs()); - if($sort || $join || $limit) { Deprecation::notice('3.0', "The sort, join, and limit arguments are deprcated, use sort(), join() and limit() on the resulting DataList instead."); } - // Call the relation method on the DataList to get the members from all the groups - $result = $groups->relation('DirectMembers')->where($filter)->sort($sort)->limit($limit); + // First get direct members as a base result + $result = $this->DirectMembers(); + // Remove the default foreign key filter in prep for re-applying a filter containing all children groups. + // Filters are conjunctive in DataQuery by default, so this filter would otherwise overrule any less specific ones. + $result->dataQuery()->removeFilterOn('Group_Members'); + // Now set all children groups as a new foreign key + $groups = DataList::create("Group")->byIDs($this->collateFamilyIDs()); + $result = $result->forForeignID($groups->column('ID'))->where($filter)->sort($sort)->limit($limit); if($join) $result = $result->join($join); return $result; @@ -421,7 +443,6 @@ class Group extends DataObject { $authorGroup->write(); Permission::grant($authorGroup->ID, 'CMS_ACCESS_CMSMain'); Permission::grant($authorGroup->ID, 'CMS_ACCESS_AssetAdmin'); - Permission::grant($authorGroup->ID, 'CMS_ACCESS_CommentAdmin'); Permission::grant($authorGroup->ID, 'CMS_ACCESS_ReportAdmin'); Permission::grant($authorGroup->ID, 'SITETREE_REORGANISE'); } diff --git a/security/Member.php b/security/Member.php index 14825d8c1..d945bf8d0 100644 --- a/security/Member.php +++ b/security/Member.php @@ -939,20 +939,28 @@ class Member extends DataObject implements TemplateGlobalProvider { /** - * Get a "many-to-many" map that holds for all members their group - * memberships + * Get a "many-to-many" map that holds for all members their group memberships, + * including any parent groups where membership is implied. + * Use {@link DirectGroups()} to only retrieve the group relations without inheritance. * * @todo Push all this logic into Member_GroupSet's getIterator()? */ public function Groups() { $groups = new Member_GroupSet('Group', 'Group_Members', 'GroupID', 'MemberID'); - if($this->ID) $groups->setForeignID($this->ID); + $groups->setForeignID($this->ID); $this->extend('updateGroups', $groups); return $groups; } + /** + * @return ManyManyList + */ + public function DirectGroups() { + return $this->getManyManyComponents('Groups'); + } + /** * Get member SQLMap @@ -1138,9 +1146,8 @@ class Member extends DataObject implements TemplateGlobalProvider { $groupsMap = DataList::create('Group')->map('ID', 'Breadcrumbs')->toArray(); asort($groupsMap); $fields->addFieldToTab('Root.Main', - Object::create('CheckboxSetField', 'Groups', singleton('Group')->i18n_plural_name()) - ->setTemplate('CheckboxSetField_Select') - ->setSource($groupsMap) + Object::create('ListboxField', 'DirectGroups', singleton('Group')->i18n_plural_name()) + ->setMultiple(true)->setSource($groupsMap) ); // Add permission field (readonly to avoid complicated group assignment logic). diff --git a/security/PermissionCheckboxSetField.php b/security/PermissionCheckboxSetField.php index 30a55e746..2095ec087 100644 --- a/security/PermissionCheckboxSetField.php +++ b/security/PermissionCheckboxSetField.php @@ -226,6 +226,9 @@ class PermissionCheckboxSetField extends FormField { } if($fieldname && $record && ($record->has_many($fieldname) || $record->many_many($fieldname))) { + + if(!$record->ID) $record->write(); // We need a record ID to write permissions + $idList = array(); if($this->value) foreach($this->value as $id => $bool) { if($bool) { diff --git a/templates/AssetUploadField.ss b/templates/AssetUploadField.ss index 066173c1e..ab4a43314 100644 --- a/templates/AssetUploadField.ss +++ b/templates/AssetUploadField.ss @@ -10,7 +10,7 @@
                      diff --git a/templates/Includes/GridFieldAction_Edit.ss b/templates/Includes/GridFieldEditAction.ss similarity index 100% rename from templates/Includes/GridFieldAction_Edit.ss rename to templates/Includes/GridFieldEditAction.ss diff --git a/templates/Includes/GridFieldPaginator_Row.ss b/templates/Includes/GridFieldPaginator_Row.ss index eea032019..f21bf1a48 100644 --- a/templates/Includes/GridFieldPaginator_Row.ss +++ b/templates/Includes/GridFieldPaginator_Row.ss @@ -1,7 +1,9 @@ - <% control Fields %> - $Field - <% end_control %> +
                      + $FirstPage $PreviousPage Page of $NumPages $NextPage $LastPage +
                      + + View $FirstShownRecord - $LastShownRecord of $NumRecords \ No newline at end of file diff --git a/templates/Includes/GridFieldTitle.ss b/templates/Includes/GridFieldTitle.ss index f8fb58da9..81f6b4817 100644 --- a/templates/Includes/GridFieldTitle.ss +++ b/templates/Includes/GridFieldTitle.ss @@ -1,3 +1,3 @@ -

                      $Title

                      <% _t('GridField.AddNew', 'Add New') %> +

                      $Title

                      <% if NewEnabled %> <% _t('GridField.AddNew', 'Add New') %><% end_if %> \ No newline at end of file diff --git a/templates/Includes/GridField_Action.ss b/templates/Includes/GridField_Action.ss deleted file mode 100644 index 0d8b4787d..000000000 --- a/templates/Includes/GridField_Action.ss +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/templates/Includes/GridField_FormAction.ss b/templates/Includes/GridField_FormAction.ss new file mode 100644 index 000000000..90e1cf96c --- /dev/null +++ b/templates/Includes/GridField_FormAction.ss @@ -0,0 +1,3 @@ + \ No newline at end of file diff --git a/templates/UploadField.ss b/templates/UploadField.ss index 7cb6a053b..8e09c53aa 100644 --- a/templates/UploadField.ss +++ b/templates/UploadField.ss @@ -45,7 +45,7 @@ <% if not $config.autoUpload %> diff --git a/templates/forms/CheckboxSetField.ss b/templates/forms/CheckboxSetField.ss index d5138c030..ce252b09b 100644 --- a/templates/forms/CheckboxSetField.ss +++ b/templates/forms/CheckboxSetField.ss @@ -1,4 +1,4 @@ -
                        +
                          title="$Description"<% end_if %>> <% if Options.Count %> <% control Options %>
                        • diff --git a/templates/forms/DropdownField.ss b/templates/forms/DropdownField.ss index 406a48e41..a19f46a8e 100644 --- a/templates/forms/DropdownField.ss +++ b/templates/forms/DropdownField.ss @@ -1,5 +1,5 @@ \ No newline at end of file diff --git a/templates/forms/OptionsetField.ss b/templates/forms/OptionsetField.ss index 8d43e93fc..485be8b70 100644 --- a/templates/forms/OptionsetField.ss +++ b/templates/forms/OptionsetField.ss @@ -1,4 +1,4 @@ -
                            +
                              title="$Description"<% end_if %>> <% control Options %>
                            • checked<% end_if %><% if isDisabled %> disabled<% end_if %>> diff --git a/tests/forms/CheckboxSetFieldTest.php b/tests/forms/CheckboxSetFieldTest.php index fef6b6392..69d281e7a 100644 --- a/tests/forms/CheckboxSetFieldTest.php +++ b/tests/forms/CheckboxSetFieldTest.php @@ -65,7 +65,7 @@ class CheckboxSetFieldTest extends SapphireTest { ); } - function testSaveWithAssociativeArrayValueSet() { + function testSaveWithArrayValueSet() { $article = $this->objFromFixture('CheckboxSetFieldTest_Article', 'articlewithouttags'); $articleWithTags = $this->objFromFixture('CheckboxSetFieldTest_Article', 'articlewithtags'); $tag1 = $this->objFromFixture('CheckboxSetFieldTest_Tag', 'tag1'); @@ -98,40 +98,6 @@ class CheckboxSetFieldTest extends SapphireTest { 'Data shold be saved into CheckboxSetField manymany relation table on the "left end"' ); } - - function testSaveWithNumericArrayValueSet() { - $article = $this->objFromFixture('CheckboxSetFieldTest_Article', 'articlewithouttags'); - $articleWithTags = $this->objFromFixture('CheckboxSetFieldTest_Article', 'articlewithtags'); - $tag1 = $this->objFromFixture('CheckboxSetFieldTest_Tag', 'tag1'); - $tag2 = $this->objFromFixture('CheckboxSetFieldTest_Tag', 'tag2'); - - /* Create a CheckboxSetField with 2 items selected. Note that the array is in the format (key) => (selected) */ - $field = new CheckboxSetField("Tags", "Test field", DataObject::get("CheckboxSetFieldTest_Tag")->map()); - $field->setValue(array( - $tag1->ID, - $tag2->ID - )); - - /* Saving should work */ - $field->saveInto($article); - - $this->assertEquals( - array($tag1->ID,$tag2->ID), - DB::query("SELECT \"CheckboxSetFieldTest_TagID\" - FROM \"CheckboxSetFieldTest_Article_Tags\" - WHERE \"CheckboxSetFieldTest_Article_Tags\".\"CheckboxSetFieldTest_ArticleID\" = $article->ID - ")->column(), - 'Data shold be saved into CheckboxSetField manymany relation table on the "right end"' - ); - $this->assertEquals( - array($articleWithTags->ID,$article->ID), - DB::query("SELECT \"CheckboxSetFieldTest_ArticleID\" - FROM \"CheckboxSetFieldTest_Article_Tags\" - WHERE \"CheckboxSetFieldTest_Article_Tags\".\"CheckboxSetFieldTest_TagID\" = $tag1->ID - ")->column(), - 'Data shold be saved into CheckboxSetField manymany relation table on the "left end"' - ); - } function testLoadDataFromObject() { $article = $this->objFromFixture('CheckboxSetFieldTest_Article', 'articlewithouttags'); diff --git a/tests/forms/CheckboxSetFieldTest.yml b/tests/forms/CheckboxSetFieldTest.yml index fafe8f3e9..34ea7f275 100644 --- a/tests/forms/CheckboxSetFieldTest.yml +++ b/tests/forms/CheckboxSetFieldTest.yml @@ -3,8 +3,17 @@ CheckboxSetFieldTest_Tag: Title: Tag 1 tag2: Title: Tag 2 - tag3: - Title: Tag 3 +CheckboxSetFieldTest_Article: + articlewithouttags: + Content: Article 1 + articlewithtags: + Content: Article 2 + Tags: =>CheckboxSetFieldTest_Tag.tag1,=>CheckboxSetFieldTest_Tag.tag2 +CheckboxSetFieldTest_Tag: + tag1: + Title: Tag 1 + tag2: + Title: Tag 2 CheckboxSetFieldTest_Article: articlewithouttags: Content: Article 1 diff --git a/tests/forms/GridFieldTest.php b/tests/forms/GridFieldTest.php index 0e877eddd..e536628f0 100644 --- a/tests/forms/GridFieldTest.php +++ b/tests/forms/GridFieldTest.php @@ -1,5 +1,5 @@ objFromFixture('ListboxFieldTest_Article', 'articlewithtags'); + $tag1 = $this->objFromFixture('ListboxFieldTest_Tag', 'tag1'); + $tag2 = $this->objFromFixture('ListboxFieldTest_Tag', 'tag2'); + $tag3 = $this->objFromFixture('ListboxFieldTest_Tag', 'tag3'); + $field = new ListboxField("Tags", "Test field", DataObject::get("ListboxFieldTest_Tag")->map()->toArray()); + $field->setMultiple(true); + $field->setValue(null, $articleWithTags); + + $p = new CSSContentParser($field->Field()); + $tag1xml = $p->getByXpath('//option[@value=' . $tag1->ID . ']'); + $tag2xml = $p->getByXpath('//option[@value=' . $tag2->ID . ']'); + $tag3xml = $p->getByXpath('//option[@value=' . $tag3->ID . ']'); + $this->assertEquals('selected', (string)$tag1xml[0]['selected']); + $this->assertEquals('selected', (string)$tag2xml[0]['selected']); + $this->assertNull($tag3xml[0]['selected']); + } + + function testFieldWithDisabledItems() { + $articleWithTags = $this->objFromFixture('ListboxFieldTest_Article', 'articlewithtags'); + $tag1 = $this->objFromFixture('ListboxFieldTest_Tag', 'tag1'); + $tag2 = $this->objFromFixture('ListboxFieldTest_Tag', 'tag2'); + $tag3 = $this->objFromFixture('ListboxFieldTest_Tag', 'tag3'); + $field = new ListboxField("Tags", "Test field", DataObject::get("ListboxFieldTest_Tag")->map()->toArray()); + $field->setMultiple(true); + $field->setValue(null, $articleWithTags); + $field->setDisabledItems(array($tag1->ID, $tag3->ID)); + + $p = new CSSContentParser($field->Field()); + $tag1xml = $p->getByXpath('//option[@value=' . $tag1->ID . ']'); + $tag2xml = $p->getByXpath('//option[@value=' . $tag2->ID . ']'); + $tag3xml = $p->getByXpath('//option[@value=' . $tag3->ID . ']'); + $this->assertEquals('selected', (string)$tag1xml[0]['selected']); + $this->assertEquals('disabled', (string)$tag1xml[0]['disabled']); + $this->assertEquals('selected', (string)$tag2xml[0]['selected']); + $this->assertNull($tag2xml[0]['disabled']); + $this->assertNull($tag3xml[0]['selected']); + $this->assertEquals('disabled', (string)$tag3xml[0]['disabled']); + } function testSaveIntoNullValueWithMultipleOff() { $choices = array('a' => 'a value', 'b' => 'b value','c' => 'c value'); @@ -62,6 +104,33 @@ class ListboxFieldTest extends SapphireTest { $field->saveInto($obj2); $this->assertEquals('a,c', $obj2->Choices); } + + function testSaveIntoManyManyRelation() { + $article = $this->objFromFixture('ListboxFieldTest_Article', 'articlewithouttags'); + $articleWithTags = $this->objFromFixture('ListboxFieldTest_Article', 'articlewithtags'); + $tag1 = $this->objFromFixture('ListboxFieldTest_Tag', 'tag1'); + $tag2 = $this->objFromFixture('ListboxFieldTest_Tag', 'tag2'); + $field = new ListboxField("Tags", "Test field", DataObject::get("ListboxFieldTest_Tag")->map()->toArray()); + $field->setMultiple(true); + + // Save new relations + $field->setValue(array($tag1->ID,$tag2->ID)); + $field->saveInto($article); + $article = Dataobject::get_by_id('ListboxFieldTest_Article', $article->ID, false); + $this->assertEquals(array($tag1->ID, $tag2->ID), $article->Tags()->column('ID')); + + // Remove existing relation + $field->setValue(array($tag1->ID)); + $field->saveInto($article); + $article = Dataobject::get_by_id('ListboxFieldTest_Article', $article->ID, false); + $this->assertEquals(array($tag1->ID), $article->Tags()->column('ID')); + + // Set NULL value + $field->setValue(null); + $field->saveInto($article); + $article = Dataobject::get_by_id('ListboxFieldTest_Article', $article->ID, false); + $this->assertEquals(array(), $article->Tags()->column('ID')); + } /** * @expectedException InvalidArgumentException @@ -130,4 +199,21 @@ class ListboxFieldTest_DataObject extends DataObject implements TestOnly { static $db = array( 'Choices' => 'Text' ); +} + +class ListboxFieldTest_Article extends DataObject implements TestOnly { + static $db = array( + "Content" => "Text", + ); + + static $many_many = array( + "Tags" => "ListboxFieldTest_Tag", + ); + +} + +class ListboxFieldTest_Tag extends DataObject implements TestOnly { + static $belongs_many_many = array( + 'Articles' => 'ListboxFieldTest_Article' + ); } \ No newline at end of file diff --git a/tests/forms/ListboxFieldTest.yml b/tests/forms/ListboxFieldTest.yml new file mode 100644 index 000000000..a6ac056fa --- /dev/null +++ b/tests/forms/ListboxFieldTest.yml @@ -0,0 +1,13 @@ +ListboxFieldTest_Tag: + tag1: + Title: Tag 1 + tag2: + Title: Tag 2 + tag3: + Title: Tag 3 +ListboxFieldTest_Article: + articlewithouttags: + Content: Article 1 + articlewithtags: + Content: Article 2 + Tags: =>ListboxFieldTest_Tag.tag1,=>ListboxFieldTest_Tag.tag2 \ No newline at end of file diff --git a/tests/forms/gridfield/GridFieldConfigTest.php b/tests/forms/gridfield/GridFieldConfigTest.php index f80447277..e979f5a2b 100644 --- a/tests/forms/gridfield/GridFieldConfigTest.php +++ b/tests/forms/gridfield/GridFieldConfigTest.php @@ -82,6 +82,37 @@ class GridFieldConfigTest extends SapphireTest { ); } + public function testRemoveComponents() { + $config = GridFieldConfig::create() + ->addComponent($c1 = new GridFieldConfigTest_MyComponent()) + ->addComponent($c2 = new GridFieldConfigTest_MyComponent()) + ->addComponent($c3 = new GridFieldConfigTest_MyOtherComponent()) + ->addComponent($c4 = new GridFieldConfigTest_MyOtherComponent()); + + $this->assertEquals( + 4, + $config->getComponents()->count() + ); + + $config->removeComponent($c1); + $this->assertEquals( + 3, + $config->getComponents()->count() + ); + + $config->removeComponentsByType("GridFieldConfigTest_MyComponent"); + $this->assertEquals( + 2, + $config->getComponents()->count() + ); + + $config->removeComponentsByType("GridFieldConfigTest_MyOtherComponent"); + $this->assertEquals( + 0, + $config->getComponents()->count() + ); + } + } class GridFieldConfigTest_MyComponent implements GridField_URLHandler, TestOnly { diff --git a/tests/forms/gridfield/GridFieldPopupFormsTest.php b/tests/forms/gridfield/GridFieldPopupFormsTest.php new file mode 100644 index 000000000..b3dd04dad --- /dev/null +++ b/tests/forms/gridfield/GridFieldPopupFormsTest.php @@ -0,0 +1,121 @@ +filter('Name', 'My Group') + ->First(); + $count = $group->People()->Count(); + + $response = $this->get('GridFieldPopupFormsTest_Controller'); + $this->assertFalse($response->isError()); + $parser = new CSSContentParser($response->getBody()); + $addlinkitem = $parser->getBySelector('.ss-gridfield .new-link'); + $addlink = (string) $addlinkitem[0]['href']; + + $response = $this->get($addlink); + $this->assertFalse($response->isError()); + + $parser = new CSSContentParser($response->getBody()); + $addform = $parser->getBySelector('#Form_ItemEditForm'); + $addformurl = (string) $addform[0]['action']; + + $response = $this->post( + $addformurl, + array( + 'FirstName' => 'Jeremiah', + 'Surname' => 'BullFrog', + 'action_doSave' => 1 + ) + ); + $this->assertFalse($response->isError()); + + $group = DataList::create('GridFieldPopupFormsTest_PeopleGroup') + ->filter('Name', 'My Group') + ->First(); + $this->assertEquals($count + 1, $group->People()->Count()); + } + + function testEditForm() { + $group = DataList::create('GridFieldPopupFormsTest_PeopleGroup') + ->filter('Name', 'My Group') + ->First(); + $firstperson = $group->People()->First(); + $this->assertTrue($firstperson->Surname != 'Baggins'); + + $response = $this->get('GridFieldPopupFormsTest_Controller'); + $this->assertFalse($response->isError()); + $parser = new CSSContentParser($response->getBody()); + $editlinkitem = $parser->getBySelector('.ss-gridfield-items .first .edit-link'); + $editlink = (string) $editlinkitem[0]['href']; + + $response = $this->get($editlink); + $this->assertFalse($response->isError()); + + $parser = new CSSContentParser($response->getBody()); + $editform = $parser->getBySelector('#Form_ItemEditForm'); + $editformurl = (string) $editform[0]['action']; + + $response = $this->post( + $editformurl, + array( + 'FirstName' => 'Bilbo', + 'Surname' => 'Baggins', + 'action_doSave' => 1 + ) + ); + $this->assertFalse($response->isError()); + + $group = DataList::create('GridFieldPopupFormsTest_PeopleGroup') + ->filter('Name', 'My Group') + ->First(); + $firstperson = $group->People()->First(); + $this->assertEquals($firstperson->Surname, 'Baggins'); + } +} + +class GridFieldPopupFormsTest_Person extends DataObject implements TestOnly { + static $db = array( + 'FirstName' => 'Varchar', + 'Surname' => 'Varchar' + ); + + static $has_one = array( + 'Group' => 'GridFieldPopupFormsTest_PeopleGroup' + ); +} + +class GridFieldPopupFormsTest_PeopleGroup extends DataObject implements TestOnly { + static $db = array( + 'Name' => 'Varchar' + ); + + static $has_many = array( + 'People' => 'GridFieldPopupFormsTest_Person' + ); +} + +class GridFieldPopupFormsTest_Controller extends Controller implements TestOnly { + protected $template = 'BlankPage'; + + function Form() { + $group = DataList::create('GridFieldPopupFormsTest_PeopleGroup') + ->filter('Name', 'My Group') + ->First(); + + $field = new GridField('testfield', 'testfield', $group->People()); + $field->getConfig()->addComponent($gridFieldForm = new GridFieldPopupForms($this, 'Form')); + $field->getConfig()->addComponent(new GridFieldEditAction()); + return new Form($this, 'Form', new FieldList($field), new FieldList()); + } +} + +?> \ No newline at end of file diff --git a/tests/forms/gridfield/GridFieldPopupFormsTest.yml b/tests/forms/gridfield/GridFieldPopupFormsTest.yml new file mode 100644 index 000000000..9090d706b --- /dev/null +++ b/tests/forms/gridfield/GridFieldPopupFormsTest.yml @@ -0,0 +1,12 @@ +GridFieldPopupFormsTest_Person: + joe: + FirstName: Joe + Surname: Bloggs + jane: + FirstName: Jane + Surname: Doe + +GridFieldPopupFormsTest_PeopleGroup: + group: + Name: My Group + People: =>GridFieldPopupFormsTest_Person.joe,=>GridFieldPopupFormsTest_Person.jane diff --git a/tests/forms/gridfield/GridFieldTitleTest.php b/tests/forms/gridfield/GridFieldTitleTest.php new file mode 100644 index 000000000..bf9015ee9 --- /dev/null +++ b/tests/forms/gridfield/GridFieldTitleTest.php @@ -0,0 +1,33 @@ +addComponent($titleField = new GridFieldTitle()); + $actions = new FieldList(); + $grid = new GridField('TestField', 'Test Field', new DataList('Company'),$config); + $fields = new FieldList($rootTab = new TabSet("Root",$tabMain = new Tab('Main',$grid))); + $form = new Form(Controller::curr(), "TestForm", $fields, $actions); + + $titleField->setNewEnabled(true); + $html = $form->forTemplate(); + $this->assertContains('data-icon="add"', $html,"HTML contains the 'add new' button"); + } + + public function testGridTitleAddNewDisabled() { + //construct a fake form field to render out the grid field within it + $config = new GridFieldConfig(); + $config->addComponent($titleField = new GridFieldTitle()); + $actions = new FieldList(); + $grid = new GridField('TestField', 'Test Field', new DataList('Company'),$config); + $fields = new FieldList($rootTab = new TabSet("Root",$tabMain = new Tab('Main',$grid))); + $form = new Form(Controller::curr(), "TestForm", $fields, $actions); + + $titleField->setNewEnabled(false); + $html = $form->forTemplate(); + $this->assertNotContains('data-icon="add"', $html,"HTML does not contain the 'add new' button"); + } +} +?> \ No newline at end of file diff --git a/tests/forms/gridfield/GridField_URLHandlerTest.php b/tests/forms/gridfield/GridField_URLHandlerTest.php index 48569c8e9..aa1e28f5f 100644 --- a/tests/forms/gridfield/GridField_URLHandlerTest.php +++ b/tests/forms/gridfield/GridField_URLHandlerTest.php @@ -1,4 +1,4 @@ - assertEquals(array(), $newTeam->Comments()->column('ID')); + } + +} \ No newline at end of file diff --git a/tests/model/ManyManyListTest.php b/tests/model/ManyManyListTest.php index f9240eb02..b16f741a7 100644 --- a/tests/model/ManyManyListTest.php +++ b/tests/model/ManyManyListTest.php @@ -15,6 +15,12 @@ class ManyManyListTest extends SapphireTest { $list = ManyManyList::create('DataObjectTest_Team','DataObjectTest_Team_Players', 'DataObjectTest_TeamID', 'DataObjectTest_PlayerID'); $this->assertEquals(2, $list->count()); } + + public function testRelationshipEmptyOnNewRecords() { + // Relies on the fact that (unrelated) teams exist in the fixture file already + $newPlayer = new DataObjectTest_Player(); // many_many Teams + $this->assertEquals(array(), $newPlayer->Teams()->column('ID')); + } public function testAddingSingleDataObjectByReference() { $player1 = $this->objFromFixture('DataObjectTest_Player', 'player1'); @@ -27,7 +33,7 @@ class ManyManyListTest extends SapphireTest { $compareTeams->byID($team1->ID); $this->assertEquals($player1->Teams()->column('ID'),$compareTeams->column('ID'),"Adding single record as DataObject to many_many"); } - + public function testRemovingSingleDataObjectByReference() { $player1 = $this->objFromFixture('DataObjectTest_Player', 'player1'); $team1 = $this->objFromFixture('DataObjectTest_Team', 'team1'); @@ -72,6 +78,20 @@ class ManyManyListTest extends SapphireTest { $player1->Teams()->setByIdList(array($team2->ID)); $this->assertEquals(array($team2->ID), $player1->Teams()->column()); } + + public function testAddingWithMultipleForeignKeys() { + $newPlayer = new DataObjectTest_Player(); + $newPlayer->write(); + $team1 = $this->objFromFixture('DataObjectTest_Team', 'team1'); + $team2 = $this->objFromFixture('DataObjectTest_Team', 'team2'); + + $playersTeam1Team2 = DataList::create('DataObjectTest_Team')->relation('Players')->setForeignID(array($team1->ID, $team2->ID)); + $playersTeam1Team2->add($newPlayer); + $this->assertEquals( + array($team1->ID, $team2->ID), + $newPlayer->Teams()->column('ID') + ); + } public function testSubtractOnAManyManyList() { $allList = ManyManyList::create('DataObjectTest_Player', 'DataObjectTest_Team_Players','DataObjectTest_PlayerID', 'DataObjectTest_TeamID');