Merge branch 'integration'
Conflicts: forms/gridfield/GridField.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');
|
||||
|
@ -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();
|
||||
|
@ -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,13 +77,21 @@ 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_<class>" if no permissions are defined here.
|
||||
* See {@link canView()} for more details on permission checks.
|
||||
*/
|
||||
static $required_permission_codes;
|
||||
|
||||
/**
|
||||
* Register additional requirements through the {@link Requirements} class.
|
||||
* Used mainly to work around the missing "lazy loading" functionality
|
||||
@ -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;
|
||||
@ -116,11 +121,17 @@ class LeftAndMain extends Controller {
|
||||
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
|
||||
@ -1311,6 +1315,37 @@ class LeftAndMain extends Controller {
|
||||
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.
|
||||
* Filenames should be relative to the base, eg, SAPPHIRE_DIR . '/javascript/loader.js'
|
||||
|
@ -1,370 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Enhances {ComplexTableField} with the ability to list groups and given members.
|
||||
* It is based around groups, so it deletes Members from a Group rather than from the entire system.
|
||||
*
|
||||
* In contrast to the original implementation, the URL-parameters "ParentClass" and "ParentID" are used
|
||||
* to specify "Group" (hardcoded) and the GroupID-relation.
|
||||
*
|
||||
* @todo write a better description about what this field does.
|
||||
*
|
||||
* Returns either:
|
||||
* - provided members
|
||||
* - members of a provided group
|
||||
* - all members
|
||||
* - members based on a search-query
|
||||
*
|
||||
* @package cms
|
||||
* @subpackage security
|
||||
*/
|
||||
class MemberTableField extends ComplexTableField {
|
||||
|
||||
protected $members;
|
||||
|
||||
protected $hidePassword;
|
||||
|
||||
protected $detailFormValidator;
|
||||
|
||||
protected $group;
|
||||
|
||||
protected $template = 'MemberTableField';
|
||||
|
||||
public $popupClass = 'MemberTableField_Popup';
|
||||
|
||||
public $itemClass = 'MemberTableField_Item';
|
||||
|
||||
/**
|
||||
* Set the page size for this table.
|
||||
* @var int
|
||||
*/
|
||||
public static $page_size = 20;
|
||||
|
||||
protected $permissions = array(
|
||||
"add",
|
||||
"edit",
|
||||
"show",
|
||||
"delete",
|
||||
'inlineadd'
|
||||
//"export",
|
||||
);
|
||||
|
||||
/**
|
||||
* Constructor method for MemberTableField.
|
||||
*
|
||||
* @param Controller $controller Controller class which created this field
|
||||
* @param string $name Name of the field (e.g. "Members")
|
||||
* @param mixed $group Can be the ID of a Group instance, or a Group instance itself
|
||||
* @param SS_List $members Optional set of Members to set as the source items for this field
|
||||
* @param boolean $hidePassword Hide the password field or not in the summary?
|
||||
*/
|
||||
function __construct($controller, $name, $group = null, $members = null, $hidePassword = true) {
|
||||
|
||||
if(!$members) {
|
||||
if($group) {
|
||||
if(is_numeric($group)) $group = DataObject::get_by_id('Group', $group);
|
||||
$this->group = $group;
|
||||
$members = $group->Members();
|
||||
|
||||
} elseif(isset($_REQUEST['ctf'][$this->getName()]["ID"]) && is_numeric($_REQUEST['ctf'][$this->getName()]["ID"])) {
|
||||
throw new Exception("Is this still being used? It's a hack and we should remove it.");
|
||||
$group = DataObject::get_by_id('Group', $_REQUEST['ctf'][$this->getName()]["ID"]);
|
||||
$this->group = $group;
|
||||
$members = $group->Members();
|
||||
} else {
|
||||
$members = DataObject::get("Member");
|
||||
}
|
||||
}
|
||||
|
||||
$SNG_member = singleton('Member');
|
||||
$fieldList = $SNG_member->summaryFields();
|
||||
$memberDbFields = $SNG_member->db();
|
||||
$csvFieldList = array();
|
||||
|
||||
foreach($memberDbFields as $field => $dbFieldType) {
|
||||
$csvFieldList[$field] = $field;
|
||||
}
|
||||
|
||||
if(!$hidePassword) {
|
||||
$fieldList["SetPassword"] = "Password";
|
||||
}
|
||||
|
||||
$this->hidePassword = $hidePassword;
|
||||
|
||||
// Add a search filter
|
||||
$SQL_search = isset($_REQUEST['MemberSearch']) ? Convert::raw2sql($_REQUEST['MemberSearch']) : null;
|
||||
if(!empty($_REQUEST['MemberSearch'])) {
|
||||
$searchFilters = array();
|
||||
foreach($SNG_member->searchableFields() as $fieldName => $fieldSpec) {
|
||||
if(strpos($fieldName, '.') === false) $searchFilters[] = "\"$fieldName\" LIKE '%{$SQL_search}%'";
|
||||
}
|
||||
$members = $members->where('(' . implode(' OR ', $searchFilters) . ')');
|
||||
}
|
||||
|
||||
parent::__construct($controller, $name, $members, $fieldList);
|
||||
|
||||
$this->setFieldListCsv($csvFieldList);
|
||||
$this->setPageSize($this->stat('page_size'));
|
||||
}
|
||||
|
||||
function FieldHolder() {
|
||||
$ret = parent::FieldHolder();
|
||||
|
||||
Requirements::javascript(SAPPHIRE_DIR . "/thirdparty/scriptaculous/controls.js");
|
||||
Requirements::javascript(SAPPHIRE_ADMIN_DIR . '/javascript/MemberTableField.js');
|
||||
Requirements::javascript(SAPPHIRE_ADMIN_DIR . "/javascript/MemberTableField_popup.js");
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
function SearchForm() {
|
||||
$groupID = (isset($this->group)) ? $this->group->ID : 0;
|
||||
$query = isset($_GET['MemberSearch']) ? $_GET['MemberSearch'] : null;
|
||||
|
||||
$searchFields = new FieldGroup(
|
||||
new TextField('MemberSearch', _t('MemberTableField.SEARCH', 'Search'), $query),
|
||||
new HiddenField("ctf[ID]", '', $groupID),
|
||||
new HiddenField('MemberFieldName', '', $this->name),
|
||||
new HiddenField('MemberDontShowPassword', '', $this->hidePassword)
|
||||
);
|
||||
|
||||
$actionFields = new LiteralField('MemberFilterButton','<input type="submit" class="action" name="MemberFilterButton" value="'._t('MemberTableField.FILTER', 'Filter').'" id="MemberFilterButton"/>');
|
||||
|
||||
$fieldContainer = new FieldGroup(
|
||||
$searchFields,
|
||||
$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(
|
||||
'<small><a href="' . $_SERVER['HTTP_REFERER'] . '" onclick="javascript:window.top.GB_hide(); return false;">(%s)</a></small>',
|
||||
_t('ComplexTableField.CLOSEPOPUP', 'Close Popup')
|
||||
);
|
||||
$message = sprintf(
|
||||
_t('ComplexTableField.SUCCESSADD', 'Added %s %s %s'),
|
||||
$childData->singular_name(),
|
||||
'<a href="' . $this->Link() . '">' . htmlspecialchars($childData->Title, ENT_QUOTES, 'UTF-8') . '</a>',
|
||||
$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;
|
||||
}
|
||||
}
|
||||
|
@ -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,36 +698,20 @@ 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
|
||||
);
|
||||
|
||||
$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 = '<a href=\"' . $this->Link() . '/$ID/edit\">$value</a>';
|
||||
if(count($summaryFields)) {
|
||||
$tf->setFieldFormatting(array_combine(
|
||||
array_keys($summaryFields),
|
||||
array_fill(0,count($summaryFields), $url)
|
||||
));
|
||||
}
|
||||
false,
|
||||
$datalist,
|
||||
$fieldConfig = GridFieldConfig_RecordEditor::create($numItemsPerPage)
|
||||
->addComponent(new GridFieldExporter())->removeComponentsByType('GridFieldFilter')
|
||||
)->setDisplayFields($this->getResultColumns($searchCriteria));
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
$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());
|
||||
|
||||
$fields = $form->Fields();
|
||||
if($fields->hasTabSet() && $record->canEdit()) {
|
||||
$fields->findOrMakeTab('Root.Import',_t('Group.IMPORTTABTITLE', 'Import'));
|
||||
$fields->addFieldToTab('Root.Import',
|
||||
new LiteralField(
|
||||
'MemberImportFormIframe',
|
||||
sprintf(
|
||||
'<iframe src="%s" id="MemberImportFormIframe" width="100%%" height="400px" border="0"></iframe>',
|
||||
$this->Link('memberimport')
|
||||
)
|
||||
)
|
||||
);
|
||||
if(Permission::check('APPLY_ROLES')) {
|
||||
$fields->addFieldToTab(
|
||||
'Root.Roles',
|
||||
new LiteralField(
|
||||
'RolesAddEditLink',
|
||||
sprintf(
|
||||
'<p class="add-role"><a href="%s">%s</a></p>',
|
||||
$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')
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
$groupList = Object::create('GridField',
|
||||
'Groups',
|
||||
false,
|
||||
DataList::create('Group'),
|
||||
GridFieldConfig_RecordEditor::create()
|
||||
)->setDisplayFields(array(
|
||||
'Breadcrumbs' => singleton('Group')->fieldLabel('Title')
|
||||
));
|
||||
|
||||
// Filter permissions
|
||||
$permissionField = $form->Fields()->dataFieldByName('Permissions');
|
||||
if($permissionField) $permissionField->setHiddenPermissions(self::$hidden_permissions);
|
||||
}
|
||||
|
||||
$this->extend('updateEditForm', $form);
|
||||
} else {
|
||||
$form = $this->RootForm();
|
||||
}
|
||||
|
||||
$form->setTemplate($this->getTemplatesWithSuffix('_EditForm'));
|
||||
if($form->Fields()->hasTabset()) $form->Fields()->findOrMakeTab('Root')->setTemplate('CMSTabSet');
|
||||
$form->addExtraClass('center ss-tabset ' . $this->BaseCSSClasses());
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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('<p class="caution-remove"><strong>%s</strong></p>',
|
||||
@ -122,14 +76,8 @@ class SecurityAdmin extends LeftAndMain implements PermissionProvider {
|
||||
)
|
||||
)
|
||||
),
|
||||
new Tab('Import', _t('SecurityAdmin.TABIMPORT', 'Import'),
|
||||
new LiteralField(
|
||||
'GroupImportFormIframe',
|
||||
sprintf(
|
||||
'<iframe src="%s" id="GroupImportFormIframe" width="100%%" height="400px" border="0"></iframe>',
|
||||
$this->Link('groupimport')
|
||||
)
|
||||
)
|
||||
new Tab('Groups', singleton('Group')->plural_name(),
|
||||
$groupList
|
||||
)
|
||||
),
|
||||
// necessary for tree node selection in LeftAndMain.EditForm.js
|
||||
@ -140,24 +88,34 @@ 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);
|
||||
}
|
||||
|
||||
$actions = new FieldList();
|
||||
$fields->findOrMakeTab('Root.Import', _t('SecurityAdmin.TABIMPORT', 'Import'));
|
||||
$fields->addFieldToTab('Root.Import',
|
||||
new LiteralField(
|
||||
'GroupImportFormIframe',
|
||||
sprintf(
|
||||
'<iframe src="%s" id="GroupImportFormIframe" width="100%%" height="400px" border="0"></iframe>',
|
||||
$this->Link('groupimport')
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$this->extend('updateRootFormFields', $fields, $actions);
|
||||
$actions = new FieldList();
|
||||
|
||||
$form = new Form(
|
||||
$this,
|
||||
@ -166,13 +124,11 @@ class SecurityAdmin extends LeftAndMain implements PermissionProvider {
|
||||
$actions
|
||||
);
|
||||
$form->addExtraClass('cms-edit-form');
|
||||
$form->setTemplate($this->getTemplatesWithSuffix('_EditForm'));
|
||||
if($form->Fields()->hasTabset()) $form->Fields()->findOrMakeTab('Root')->setTemplate('CMSTabSet');
|
||||
$form->addExtraClass('center ss-tabset ' . $this->BaseCSSClasses());
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
function AddForm() {
|
||||
$form = parent::AddForm();
|
||||
$form->Actions()->fieldByName('action_doAdd')->setTitle(_t('SecurityAdmin.ActionAdd', 'Add group'));
|
||||
$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);
|
||||
|
||||
// Name root breadcrumb based on which record is edited,
|
||||
// which can only be determined by looking for the fieldname of the GridField.
|
||||
// Note: Titles should be same titles as tabs in RootForm().
|
||||
$params = $this->request->allParams();
|
||||
if(isset($params['FieldName'])) {
|
||||
if($params['FieldName'] == 'Groups') {
|
||||
$crumbs->First()->Title = singleton('Group')->plural_name();
|
||||
} elseif($params['FieldName'] == 'Users') {
|
||||
$crumbs->First()->Title = _t('SecurityAdmin.Users', 'Users');
|
||||
} elseif($params['FieldName'] == 'Roles') {
|
||||
$crumbs->First()->Title = _t('SecurityAdmin.TABROLES', 'Roles');
|
||||
}
|
||||
} else {
|
||||
// Avoid writing "Users" (the controller menu title) as a breadcrumb
|
||||
// because its confusing and inaccurate.
|
||||
$crumbs = new ArrayList();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 .= "<ul>";
|
||||
foreach($matches as $match) {
|
||||
// If the current user doesnt have permissions on the target user,
|
||||
// he's not allowed to add it to a group either: Don't include it in the suggestions.
|
||||
if(!$match->canView() || !$match->canEdit()) continue;
|
||||
|
||||
$data = array();
|
||||
foreach($match->summaryFields() as $k => $v) {
|
||||
$data[$k] = $match->$k;
|
||||
}
|
||||
$result .= sprintf(
|
||||
'<li data-fields="%s">%s <span class="informal">(%s)</span></li>',
|
||||
Convert::raw2att(Convert::raw2json($data)),
|
||||
$match->$fieldName,
|
||||
implode(',', array_values($data))
|
||||
);
|
||||
}
|
||||
$result .= "</ul>";
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
)
|
||||
);
|
||||
@ -340,36 +276,3 @@ class SecurityAdmin extends LeftAndMain implements PermissionProvider {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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; }
|
||||
|
@ -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; }
|
||||
|
@ -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); }
|
||||
|
Before Width: | Height: | Size: 15 KiB |
BIN
admin/images/btn-icon-sb5d07676ff.png
Normal file
After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 742 B |
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 673 B |
BIN
admin/images/btn-icon/chain--arrow.png
Executable file
After Width: | Height: | Size: 584 B |
BIN
admin/images/btn-icon/chain--exclamation.png
Executable file
After Width: | Height: | Size: 707 B |
BIN
admin/images/btn-icon/chain--minus.png
Executable file
After Width: | Height: | Size: 483 B |
BIN
admin/images/btn-icon/chain--pencil.png
Executable file
After Width: | Height: | Size: 620 B |
BIN
admin/images/btn-icon/chain--plus.png
Executable file
After Width: | Height: | Size: 586 B |
BIN
admin/images/btn-icon/chain-small.png
Executable file
After Width: | Height: | Size: 354 B |
BIN
admin/images/btn-icon/chain-unchain.png
Executable file
After Width: | Height: | Size: 722 B |
BIN
admin/images/btn-icon/chain.png
Executable file
After Width: | Height: | Size: 430 B |
BIN
admin/images/btn-icon/download-csv.png
Normal file
After Width: | Height: | Size: 683 B |
BIN
admin/images/filter-icons.png
Normal file
After Width: | Height: | Size: 2.0 KiB |
@ -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) {
|
||||
@ -223,55 +227,41 @@
|
||||
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);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -159,16 +159,22 @@
|
||||
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);
|
@ -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;
|
||||
}
|
||||
});
|
||||
|
@ -13,6 +13,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,19 +260,19 @@
|
||||
}
|
||||
}
|
||||
|
||||
},
|
||||
onunmatch: function() {
|
||||
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('.cms-tree.multiple').entwine({
|
||||
onmatch: function() {
|
||||
this._super();
|
||||
|
||||
this.jstree('show_checkboxes');
|
||||
},
|
||||
onunmatch: function() {
|
||||
this._super();
|
||||
|
||||
this.jstree('uncheck_all');
|
||||
this.jstree('hide_checkboxes');
|
||||
},
|
||||
@ -321,8 +327,10 @@
|
||||
this._super();
|
||||
},
|
||||
onclick: function(e) {
|
||||
$('.cms-tree').toggleClass('draggable', $(e.target).val() == 'draggable');
|
||||
$('.cms-tree')
|
||||
.toggleClass('draggable', $(e.target).val() == 'draggable')
|
||||
.toggleClass('multiple', $(e.target).val() == 'multiselect');
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
}(jQuery));
|
@ -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) {
|
||||
|
@ -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 = '<a class="deletelink" href="admin/security/removememberfromgroup/' + groupId + '/' + id + '"><img src="sapphire/images/delete.gif" alt="delete" /></a>';
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
@ -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');
|
@ -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.
|
||||
*/
|
||||
$('#Permissions .checkbox[value=ADMIN]').entwine({
|
||||
onmatch: function() {
|
||||
this.toggleCheckboxes();
|
||||
|
||||
this._super();
|
||||
},
|
||||
/**
|
||||
* Function: onclick
|
||||
*/
|
||||
$('.cms-edit-form .Actions #Form_EditForm_action_addmember').entwine({
|
||||
// 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'));
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -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 {
|
||||
.cms {
|
||||
.cms-panel-padded {
|
||||
width: ($grid-x * 22);
|
||||
padding: $grid-y*2 $grid-x*2;
|
||||
overflow-x: hidden;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
|
||||
/** ------------------------------------------------------------------
|
||||
@ -1296,3 +1341,22 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -380,6 +380,17 @@
|
||||
.jstree li {
|
||||
line-height: 25px;
|
||||
}
|
||||
|
||||
// Hide drag icons by default. Actual page icons
|
||||
// are in nested <span>, 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -53,16 +53,116 @@ html {
|
||||
text-indent: 0px !important;
|
||||
}
|
||||
|
||||
.cms {
|
||||
table.ss-gridfield-table {
|
||||
tbody {
|
||||
//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;
|
||||
}
|
||||
}
|
||||
}
|
||||
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 {
|
||||
span.ui-button-text {
|
||||
zoom:1;
|
||||
}
|
||||
&.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;
|
||||
}
|
||||
}
|
@ -28,3 +28,53 @@
|
||||
.ui-widget-header .ui-state-default {
|
||||
background-image:none;
|
||||
}
|
||||
|
||||
//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;
|
||||
}
|
||||
|
@ -20,7 +20,7 @@
|
||||
<div class="cms-content-header-tabs">
|
||||
<ul>
|
||||
<% control Tabs %>
|
||||
<li><a href="#$id">$Title</a></li>
|
||||
<li><a href="#$id"<% if extraClass %> class="$extraClass"<% end_if %>>$Title</a></li>
|
||||
<% end_control %>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -1,62 +0,0 @@
|
||||
<div id="$id" class="$CSSClasses $extraClass field" href="$CurrentLink">
|
||||
<div class="MemberFilter filterBox">
|
||||
$SearchForm
|
||||
</div>
|
||||
<div id="MemberList">
|
||||
<% if Markable %>
|
||||
<% include TableListField_SelectOptions %>
|
||||
<% end_if %>
|
||||
<% include TableListField_PageControls %>
|
||||
<table class="data">
|
||||
<thead>
|
||||
<tr>
|
||||
<% if Markable %><th width="18"> </th><% end_if %>
|
||||
<% control Headings %>
|
||||
<th class="$Name">$Title</th>
|
||||
<% end_control %>
|
||||
<% if Can(show) %><th width="18"> </th><% end_if %>
|
||||
<% if Can(edit) %><th width="18"> </th><% end_if %>
|
||||
<% if Can(delete) %><th width="18"> </th><% end_if %>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<% if Can(inlineadd) %>
|
||||
<tr class="addtogrouprow">
|
||||
<% if Markable %><td width="18"> </dh><% end_if %>
|
||||
$AddRecordForm.CellFields
|
||||
<td class="actions" colspan="3">$AddRecordForm.CellActions</td>
|
||||
</tr>
|
||||
<% end_if %>
|
||||
<tr style="display: none;">
|
||||
<% if Markable %><td width="18"> </td><% end_if %>
|
||||
<td colspan="$ItemCount">
|
||||
<input type="hidden" id="{$id}_PopupHeight" value="$PopupHeight" disabled="disabled"/>
|
||||
<input type="hidden" id="{$id}_PopupWidth" value="$PopupWidth" disabled="disabled"/>
|
||||
<a class="popuplink addlink" href="$AddLink" alt="add"><img src="sapphire/images/add.gif" alt="add" /></a><a class="popuplink addlink" href="$AddLink" alt="add"><% _t('ADDNEW','Add new',50,'Followed by a member type') %> $Title</a>
|
||||
</td>
|
||||
<% if Can(show) %><td width="18"> </td><% end_if %>
|
||||
<% if Can(edit) %><td width="18"> </td><% end_if %>
|
||||
<% if Can(delete) %><td width="18"> </td><% end_if %>
|
||||
</tr>
|
||||
</tfoot>
|
||||
<tbody>
|
||||
<% if Items %>
|
||||
<% control Items %>
|
||||
<% include TableListField_Item %>
|
||||
<% end_control %>
|
||||
<% else %>
|
||||
<tr class="notfound">
|
||||
<% if Markable %><th width="18"> </th><% end_if %>
|
||||
<td colspan="$Headings.Count"><i><% _t('NOITEMSFOUND', 'No items found') %></i></td>
|
||||
<% control Actions %><td width="18"> </td><% end_control %>
|
||||
</tr>
|
||||
<% end_if %>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="utility">
|
||||
<% control Utility %>
|
||||
<span class="item"><a href="$Link" target="_blank">$Title</a></span>
|
||||
<% end_control %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -1,9 +1,13 @@
|
||||
<div class="cms-content center $BaseCSSClasses" data-layout-type="border">
|
||||
|
||||
<div class="cms-content-header north">
|
||||
<div>
|
||||
<h2><% _t('ModelAdmin.Title', 'My Model') %></h2>
|
||||
</div>
|
||||
<div><h2>
|
||||
<% if SectionTitle %>
|
||||
$SectionTitle
|
||||
<% else %>
|
||||
<% _t('ModelAdmin.Title', 'Data Models') %>
|
||||
<% end_if %>
|
||||
</h2></div>
|
||||
</div>
|
||||
|
||||
$Tools
|
||||
|
@ -6,7 +6,7 @@
|
||||
<% if SearchClassSelector = tabs %>
|
||||
<ul>
|
||||
<% control ModelForms %>
|
||||
<li class="$FirstLast"><a id="tab-ModelAdmin_$Title.HTMLATT" href="#{$Form.Name}_$ClassName">$Title</a></li>
|
||||
<li class="$FirstLast"><a id="tab-ModelAdmin_$Title.HTMLATT" href="#Form_$ClassName">$Title</a></li>
|
||||
<% end_control %>
|
||||
</ul>
|
||||
<% end_if %>
|
||||
@ -16,14 +16,14 @@
|
||||
Search for:
|
||||
<select>
|
||||
<% control ModelForms %>
|
||||
<option value="{$Form.Name}_$ClassName">$Title</option>
|
||||
<option value="Form_$ClassName">$Title</option>
|
||||
<% end_control %>
|
||||
</select>
|
||||
</div>
|
||||
<% end_if %>
|
||||
|
||||
<% control ModelForms %>
|
||||
<div class="tab" id="{$Form.Name}_$ClassName">
|
||||
<div class="tab" id="Form_$ClassName">
|
||||
$Content
|
||||
</div>
|
||||
<% end_control %>
|
||||
|
@ -1,21 +0,0 @@
|
||||
<div class="cms-content center $BaseCSSClasses" data-layout-type="border">
|
||||
<div class="cms-content-tools west">
|
||||
<div class="cms-content-header north">
|
||||
<div>
|
||||
<h2>
|
||||
<% include CMSBreadcrumbs %>
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
$AddForm
|
||||
|
||||
<div data-url-tree="$Link(getsubtree)" data-url-savetreenode="$Link(savetreenode)" class="cms-tree draggable jstree jstree-apple">
|
||||
$SiteTreeAsUL
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
$EditForm
|
||||
|
||||
</div>
|
@ -1,7 +1,3 @@
|
||||
<% if CreateForm %>
|
||||
$CreateForm
|
||||
<% end_if %>
|
||||
|
||||
<h3><% _t('SEARCHLISTINGS','Search') %></h3>
|
||||
$SearchForm
|
||||
|
||||
|
@ -1,139 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* @package cms
|
||||
* @subpackage tests
|
||||
*/
|
||||
|
||||
class MemberTableFieldTest extends FunctionalTest {
|
||||
|
||||
static $fixture_file = 'sapphire/admin/tests/MemberTableFieldTest.yml';
|
||||
|
||||
|
||||
function testLimitsToMembersInGroup() {
|
||||
$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",
|
||||
$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'))
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -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
|
@ -9,39 +9,41 @@ class SecurityAdminTest extends FunctionalTest {
|
||||
|
||||
protected $extraDataObjects = array('LeftAndMainTest_Object');
|
||||
|
||||
function testGroupExport() {
|
||||
$this->session()->inst_set('loggedInAs', $this->idFromFixture('Member', 'admin'));
|
||||
// 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']);
|
||||
// /* 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());
|
||||
// /* 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");
|
||||
}
|
||||
// $this->assertEquals(count($lines), 3, "Export with members has one content row");
|
||||
// $this->assertRegExp('/"","","admin@example.com"/', $lines[1], "Member values are correctly exported");
|
||||
// }
|
||||
|
||||
function testEmptyGroupExport() {
|
||||
$this->session()->inst_set('loggedInAs', $this->idFromFixture('Member', 'admin'));
|
||||
// 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',
|
||||
|
12
admin/thirdparty/chosen/Cakefile
vendored
@ -77,6 +77,7 @@ 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
|
||||
)
|
||||
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
|
||||
|
18
admin/thirdparty/chosen/README.md
vendored
@ -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: <code>npm -g install uglify-js</code>
|
||||
3. Verify that your $NODE_PATH is properly configured using <code>echo $NODE_PATH</code>
|
||||
```
|
||||
npm install -d
|
||||
```
|
||||
|
||||
This will install `coffee-script` and `uglifyjs`.
|
||||
|
||||
Once you're configured, building the JavasScript from the command line is easy:
|
||||
|
||||
@ -44,3 +47,4 @@ If you're interested, you can find the recipes in Cakefile.
|
||||
|
||||
- [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.
|
||||
- [Chosen CakePHP Plugin](https://github.com/paulredmond/chosen-cakephp), by Paul Redmond
|
||||
|
2
admin/thirdparty/chosen/VERSION
vendored
@ -1 +1 @@
|
||||
0.9.5
|
||||
0.9.7
|
||||
|
BIN
admin/thirdparty/chosen/chosen/chosen-sprite.png
vendored
Before Width: | Height: | Size: 396 B After Width: | Height: | Size: 1.5 KiB |
196
admin/thirdparty/chosen/chosen/chosen.css
vendored
@ -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 */
|
||||
|
350
admin/thirdparty/chosen/chosen/chosen.jquery.js
vendored
@ -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 '<li id="' + option.dom_id + '" class="' + classes.join(' ') + '"' + style + '>' + option.html + '</li>';
|
||||
} 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('<li class="search-choice" id="' + choice_id + '"><span>' + item.html + '</span><a href="javascript:void(0)" class="search-choice-close" rel="' + item.array_index + '"></a></li>');
|
||||
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("<abbr class=\"search-choice-close\"></abbr>");
|
||||
}
|
||||
};
|
||||
|
||||
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 = $('<li class="no-results">' + this.results_none_found + ' "<span></span>"</li>');
|
||||
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);
|
||||
|
@ -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<e;d++)c=f[d],g.push(this.add_option(c,b,a.disabled));return g},a.prototype.add_option=function(a,b,c){if(a.nodeName==="OPTION")return a.text!==""?(b!=null&&(this.parsed[b].children+=1),this.parsed.push({array_index:this.parsed.length,options_index:this.options_index,value:a.value,text:a.text,html:a.innerHTML,selected:a.selected,disabled:c===!0?c:a.disabled,group_array_index:b,classes:a.className,style:a.style.cssText})):this.parsed.push({array_index:this.parsed.length,options_index:this.options_index,empty:!0}),this.options_index+=1},a}(),a.select_to_array=function(b){var c,d,e,f,g;d=new a,g=b.childNodes;for(e=0,f=g.length;e<f;e++)c=g[e],d.add_node(c);return d.parsed},this.SelectParser=a}).call(this),function(){var a,b,c=function(a,b){return function(){return a.apply(b,arguments)}};b=this,a=function(){function a(a,b){this.form_field=a,this.options=b!=null?b:{},this.set_default_values(),this.is_multiple=this.form_field.multiple,this.default_text_default=this.is_multiple?"Select Some Options":"Select an Option",this.setup(),this.set_up_html(),this.register_observers(),this.finish_setup()}return a.prototype.set_default_values=function(){return this.click_test_action=c(function(a){return this.test_active_click(a)},this),this.activate_action=c(function(a){return this.activate_field(a)},this),this.active_field=!1,this.mouse_on_container=!1,this.results_showing=!1,this.result_highlighted=null,this.result_single_selected=null,this.allow_single_deselect=this.options.allow_single_deselect!=null&&this.form_field.options[0]!=null&&this.form_field.options[0].text===""?this.options.allow_single_deselect:!1,this.disable_search_threshold=this.options.disable_search_threshold||0,this.choices=0,this.results_none_found=this.options.no_results_text||"No results match"},a.prototype.mouse_enter=function(){return this.mouse_on_container=!0},a.prototype.mouse_leave=function(){return this.mouse_on_container=!1},a.prototype.input_focus=function(a){if(!this.active_field)return setTimeout(c(function(){return this.container_mousedown()},this),50)},a.prototype.input_blur=function(a){if(!this.mouse_on_container)return this.active_field=!1,setTimeout(c(function(){return this.blur_test()},this),100)},a.prototype.result_add_option=function(a){var b,c;return a.disabled?"":(a.dom_id=this.container_id+"_o_"+a.array_index,b=a.selected&&this.is_multiple?[]:["active-result"],a.selected&&b.push("result-selected"),a.group_array_index!=null&&b.push("group-option"),a.classes!==""&&b.push(a.classes),c=a.style.cssText!==""?' style="'+a.style+'"':"",'<li id="'+a.dom_id+'" class="'+b.join(" ")+'"'+c+">"+a.html+"</li>")},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("<div />",{id:this.container_id,"class":"chzn-container"+(this.is_rtl?" chzn-rtl":""),style:"width: "+this.f_width+"px;"}),this.is_multiple?b.html('<ul class="chzn-choices"><li class="search-field"><input type="text" value="'+this.default_text+'" class="default" autocomplete="off" style="width:25px;" /></li></ul><div class="chzn-drop" style="left:-9000px;"><ul class="chzn-results"></ul></div>'):b.html('<a href="javascript:void(0)" class="chzn-single"><span>'+this.default_text+'</span><div><b></b></div></a><div class="chzn-drop" style="left:-9000px;"><div class="chzn-search"><input type="text" autocomplete="off" /></div><ul class="chzn-results"></ul></div>'),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<e;c++)b=f[c],b.group?a+=this.result_add_group(b):b.empty||(a+=this.result_add_option(b),b.selected&&this.is_multiple?this.choice_build(b):b.selected&&!this.is_multiple&&(this.selected_item.find("span").text(b.text),this.allow_single_deselect&&this.single_deselect_control_build()));return this.search_field_disabled(),this.show_search_field_default(),this.search_field_scale(),this.search_results.html(a),this.parsing=!1},b.prototype.result_add_group=function(b){return b.disabled?"":(b.dom_id=this.container_id+"_g_"+b.array_index,'<li id="'+b.dom_id+'" class="group-result">'+a("<div />").text(b.label).html()+"</li>")},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<f)return this.search_results.scrollTop(c)}},b.prototype.result_clear_highlight=function(){return this.result_highlight&&this.result_highlight.removeClass("highlighted"),this.result_highlight=null},b.prototype.results_show=function(){var a;return this.is_multiple||(this.selected_item.addClass("chzn-single-with-drop"),this.result_single_selected&&this.result_do_highlight(this.result_single_selected)),a=this.is_multiple?this.container.height():this.container.height()-1,this.dropdown.css({top:a+"px",left:0}),this.results_showing=!0,this.search_field.focus(),this.search_field.val(this.search_field.val()),this.winnow_results()},b.prototype.results_hide=function(){return this.is_multiple||this.selected_item.removeClass("chzn-single-with-drop"),this.result_clear_highlight(),this.dropdown.css({left:"-9000px"}),this.results_showing=!1},b.prototype.set_tab_index=function(a){var b;if(this.form_field_jq.attr("tabindex"))return b=this.form_field_jq.attr("tabindex"),this.form_field_jq.attr("tabindex",-1),this.is_multiple?this.search_field.attr("tabindex",b):(this.selected_item.attr("tabindex",b),this.search_field.attr("tabindex",-1))},b.prototype.show_search_field_default=function(){return this.is_multiple&&this.choices<1&&!this.active_field?(this.search_field.val(this.default_text),this.search_field.addClass("default")):(this.search_field.val(""),this.search_field.removeClass("default"))},b.prototype.search_results_mouseup=function(b){var c;c=a(b.target).hasClass("active-result")?a(b.target):a(b.target).parents(".active-result").first();if(c.length)return this.result_highlight=c,this.result_select(b)},b.prototype.search_results_mouseover=function(b){var c;c=a(b.target).hasClass("active-result")?a(b.target):a(b.target).parents(".active-result").first();if(c)return this.result_do_highlight(c)},b.prototype.search_results_mouseout=function(b){if(a(b.target).hasClass("active-result"))return this.result_clear_highlight()},b.prototype.choices_click=function(b){b.preventDefault();if(this.active_field&&!a(b.target).hasClass("search-choice")&&!this.results_showing)return this.results_show()},b.prototype.choice_build=function(b){var c,d;return c=this.container_id+"_c_"+b.array_index,this.choices+=1,this.search_container.before('<li class="search-choice" id="'+c+'"><span>'+b.html+'</span><a href="javascript:void(0)" class="search-choice-close" rel="'+b.array_index+'"></a></li>'),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('<abbr class="search-choice-close"></abbr>')},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("<div/>").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<p;n++){c=r[n];if(!c.disabled&&!c.empty)if(c.group)a("#"+c.dom_id).css("display","none");else if(!this.is_multiple||!c.selected){b=!1,h=c.dom_id,g=a("#"+h);if(f.test(c.html))b=!0,i+=1;else if(c.html.indexOf(" ")>=0||c.html.indexOf("[")===0){e=c.html.replace(/\[|\]/g,"").split(" ");if(e.length)for(o=0,q=e.length;o<q;o++)d=e[o],f.test(d)&&(b=!0,i+=1)}b?(j.length?(k=c.html.search(m),l=c.html.substr(0,k+j.length)+"</em>"+c.html.substr(k+j.length),l=l.substr(0,k)+"<em>"+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<e;d++)b=c[d],b=a(b),f.push(b.hasClass("group-result")?b.css("display","auto"):!this.is_multiple||!b.hasClass("result-selected")?this.result_activate(b):void 0);return f},b.prototype.winnow_results_set_highlight=function(){var a,b;if(!this.result_highlight){b=this.is_multiple?[]:this.search_results.find(".result-selected.active-result"),a=b.length?b.first():this.search_results.find(".active-result").first();if(a!=null)return this.result_do_highlight(a)}},b.prototype.no_results=function(b){var c;return c=a('<li class="no-results">'+this.results_none_found+' "<span></span>"</li>'),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<j;i++)e=g[i],f+=e+":"+this.search_field.css(e)+";";return c=a("<div />",{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)
|
||||
((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<e;d++)c=f[d],g.push(this.add_option(c,b,a.disabled));return g},a.prototype.add_option=function(a,b,c){if(a.nodeName==="OPTION")return a.text!==""?(b!=null&&(this.parsed[b].children+=1),this.parsed.push({array_index:this.parsed.length,options_index:this.options_index,value:a.value,text:a.text,html:a.innerHTML,selected:a.selected,disabled:c===!0?c:a.disabled,group_array_index:b,classes:a.className,style:a.style.cssText})):this.parsed.push({array_index:this.parsed.length,options_index:this.options_index,empty:!0}),this.options_index+=1},a}(),a.select_to_array=function(b){var c,d,e,f,g;d=new a,g=b.childNodes;for(e=0,f=g.length;e<f;e++)c=g[e],d.add_node(c);return d.parsed},this.SelectParser=a})).call(this),function(){var a,b;b=this,a=function(){function a(a,b){this.form_field=a,this.options=b!=null?b:{},this.set_default_values(),this.is_multiple=this.form_field.multiple,this.default_text_default=this.is_multiple?"Select Some Options":"Select an Option",this.setup(),this.set_up_html(),this.register_observers(),this.finish_setup()}return a.prototype.set_default_values=function(){var a=this;return this.click_test_action=function(b){return a.test_active_click(b)},this.activate_action=function(b){return a.activate_field(b)},this.active_field=!1,this.mouse_on_container=!1,this.results_showing=!1,this.result_highlighted=null,this.result_single_selected=null,this.allow_single_deselect=this.options.allow_single_deselect!=null&&this.form_field.options[0]!=null&&this.form_field.options[0].text===""?this.options.allow_single_deselect:!1,this.disable_search_threshold=this.options.disable_search_threshold||0,this.choices=0,this.results_none_found=this.options.no_results_text||"No results match"},a.prototype.mouse_enter=function(){return this.mouse_on_container=!0},a.prototype.mouse_leave=function(){return this.mouse_on_container=!1},a.prototype.input_focus=function(a){var b=this;if(!this.active_field)return setTimeout(function(){return b.container_mousedown()},50)},a.prototype.input_blur=function(a){var b=this;if(!this.mouse_on_container)return this.active_field=!1,setTimeout(function(){return b.blur_test()},100)},a.prototype.result_add_option=function(a){var b,c;return a.disabled?"":(a.dom_id=this.container_id+"_o_"+a.array_index,b=a.selected&&this.is_multiple?[]:["active-result"],a.selected&&b.push("result-selected"),a.group_array_index!=null&&b.push("group-option"),a.classes!==""&&b.push(a.classes),c=a.style.cssText!==""?' style="'+a.style+'"':"",'<li id="'+a.dom_id+'" class="'+b.join(" ")+'"'+c+">"+a.html+"</li>")},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("<div />",{id:this.container_id,"class":"chzn-container"+(this.is_rtl?" chzn-rtl":""),style:"width: "+this.f_width+"px;"}),this.is_multiple?b.html('<ul class="chzn-choices"><li class="search-field"><input type="text" value="'+this.default_text+'" class="default" autocomplete="off" style="width:25px;" /></li></ul><div class="chzn-drop" style="left:-9000px;"><ul class="chzn-results"></ul></div>'):b.html('<a href="javascript:void(0)" class="chzn-single"><span>'+this.default_text+'</span><div><b></b></div></a><div class="chzn-drop" style="left:-9000px;"><div class="chzn-search"><input type="text" autocomplete="off" /></div><ul class="chzn-results"></ul></div>'),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<e;c++)b=f[c],b.group?a+=this.result_add_group(b):b.empty||(a+=this.result_add_option(b),b.selected&&this.is_multiple?this.choice_build(b):b.selected&&!this.is_multiple&&(this.selected_item.find("span").text(b.text),this.allow_single_deselect&&this.single_deselect_control_build()));return this.search_field_disabled(),this.show_search_field_default(),this.search_field_scale(),this.search_results.html(a),this.parsing=!1},e.prototype.result_add_group=function(b){return b.disabled?"":(b.dom_id=this.container_id+"_g_"+b.array_index,'<li id="'+b.dom_id+'" class="group-result">'+a("<div />").text(b.label).html()+"</li>")},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<f)return this.search_results.scrollTop(c)}},e.prototype.result_clear_highlight=function(){return this.result_highlight&&this.result_highlight.removeClass("highlighted"),this.result_highlight=null},e.prototype.results_show=function(){var a;return this.is_multiple||(this.selected_item.addClass("chzn-single-with-drop"),this.result_single_selected&&this.result_do_highlight(this.result_single_selected)),a=this.is_multiple?this.container.height():this.container.height()-1,this.dropdown.css({top:a+"px",left:0}),this.results_showing=!0,this.search_field.focus(),this.search_field.val(this.search_field.val()),this.winnow_results()},e.prototype.results_hide=function(){return this.is_multiple||this.selected_item.removeClass("chzn-single-with-drop"),this.result_clear_highlight(),this.dropdown.css({left:"-9000px"}),this.results_showing=!1},e.prototype.set_tab_index=function(a){var b;if(this.form_field_jq.attr("tabindex"))return b=this.form_field_jq.attr("tabindex"),this.form_field_jq.attr("tabindex",-1),this.is_multiple?this.search_field.attr("tabindex",b):(this.selected_item.attr("tabindex",b),this.search_field.attr("tabindex",-1))},e.prototype.show_search_field_default=function(){return this.is_multiple&&this.choices<1&&!this.active_field?(this.search_field.val(this.default_text),this.search_field.addClass("default")):(this.search_field.val(""),this.search_field.removeClass("default"))},e.prototype.search_results_mouseup=function(b){var c;c=a(b.target).hasClass("active-result")?a(b.target):a(b.target).parents(".active-result").first();if(c.length)return this.result_highlight=c,this.result_select(b)},e.prototype.search_results_mouseover=function(b){var c;c=a(b.target).hasClass("active-result")?a(b.target):a(b.target).parents(".active-result").first();if(c)return this.result_do_highlight(c)},e.prototype.search_results_mouseout=function(b){if(a(b.target).hasClass("active-result"))return this.result_clear_highlight()},e.prototype.choices_click=function(b){b.preventDefault();if(this.active_field&&!a(b.target).hasClass("search-choice")&&!this.results_showing)return this.results_show()},e.prototype.choice_build=function(b){var c,d,e=this;return c=this.container_id+"_c_"+b.array_index,this.choices+=1,this.search_container.before('<li class="search-choice" id="'+c+'"><span>'+b.html+'</span><a href="javascript:void(0)" class="search-choice-close" rel="'+b.array_index+'"></a></li>'),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('<abbr class="search-choice-close"></abbr>')},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("<div/>").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<p;n++){c=r[n];if(!c.disabled&&!c.empty)if(c.group)a("#"+c.dom_id).css("display","none");else if(!this.is_multiple||!c.selected){b=!1,h=c.dom_id,g=a("#"+h);if(f.test(c.html))b=!0,i+=1;else if(c.html.indexOf(" ")>=0||c.html.indexOf("[")===0){e=c.html.replace(/\[|\]/g,"").split(" ");if(e.length)for(o=0,q=e.length;o<q;o++)d=e[o],f.test(d)&&(b=!0,i+=1)}b?(j.length?(k=c.html.search(m),l=c.html.substr(0,k+j.length)+"</em>"+c.html.substr(k+j.length),l=l.substr(0,k)+"<em>"+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<e;d++)b=c[d],b=a(b),b.hasClass("group-result")?f.push(b.css("display","auto")):!this.is_multiple||!b.hasClass("result-selected")?f.push(this.result_activate(b)):f.push(void 0);return f},e.prototype.winnow_results_set_highlight=function(){var a,b;if(!this.result_highlight){b=this.is_multiple?[]:this.search_results.find(".result-selected.active-result"),a=b.length?b.first():this.search_results.find(".active-result").first();if(a!=null)return this.result_do_highlight(a)}},e.prototype.no_results=function(b){var c;return c=a('<li class="no-results">'+this.results_none_found+' "<span></span>"</li>'),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<j;i++)e=g[i],f+=e+":"+this.search_field.css(e)+";";return c=a("<div />",{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)
|
350
admin/thirdparty/chosen/chosen/chosen.proto.js
vendored
@ -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 '<li id="' + option.dom_id + '" class="' + classes.join(' ') + '"' + style + '>' + option.html + '</li>';
|
||||
} 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('<a href="javascript:void(0)" class="chzn-single"><span>#{default}</span><div><b></b></div></a><div class="chzn-drop" style="left:-9000px;"><div class="chzn-search"><input type="text" autocomplete="off" /></div><ul class="chzn-results"></ul></div>');
|
||||
@ -262,6 +286,7 @@
|
||||
this.choice_temp = new Template('<li class="search-choice" id="#{id}"><span>#{choice}</span><a href="javascript:void(0)" class="search-choice-close" rel="#{position}"></a></li>');
|
||||
return this.no_results_temp = new Template('<li class="no-results">' + this.results_none_found + ' "<span>#{terms}</span>"</li>');
|
||||
};
|
||||
|
||||
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);
|
||||
|
@ -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<e;d++)c=f[d],g.push(this.add_option(c,b,a.disabled));return g},a.prototype.add_option=function(a,b,c){if(a.nodeName==="OPTION")return a.text!==""?(b!=null&&(this.parsed[b].children+=1),this.parsed.push({array_index:this.parsed.length,options_index:this.options_index,value:a.value,text:a.text,html:a.innerHTML,selected:a.selected,disabled:c===!0?c:a.disabled,group_array_index:b,classes:a.className,style:a.style.cssText})):this.parsed.push({array_index:this.parsed.length,options_index:this.options_index,empty:!0}),this.options_index+=1},a}(),a.select_to_array=function(b){var c,d,e,f,g;d=new a,g=b.childNodes;for(e=0,f=g.length;e<f;e++)c=g[e],d.add_node(c);return d.parsed},this.SelectParser=a}).call(this),function(){var a,b,c=function(a,b){return function(){return a.apply(b,arguments)}};b=this,a=function(){function a(a,b){this.form_field=a,this.options=b!=null?b:{},this.set_default_values(),this.is_multiple=this.form_field.multiple,this.default_text_default=this.is_multiple?"Select Some Options":"Select an Option",this.setup(),this.set_up_html(),this.register_observers(),this.finish_setup()}return a.prototype.set_default_values=function(){return this.click_test_action=c(function(a){return this.test_active_click(a)},this),this.activate_action=c(function(a){return this.activate_field(a)},this),this.active_field=!1,this.mouse_on_container=!1,this.results_showing=!1,this.result_highlighted=null,this.result_single_selected=null,this.allow_single_deselect=this.options.allow_single_deselect!=null&&this.form_field.options[0]!=null&&this.form_field.options[0].text===""?this.options.allow_single_deselect:!1,this.disable_search_threshold=this.options.disable_search_threshold||0,this.choices=0,this.results_none_found=this.options.no_results_text||"No results match"},a.prototype.mouse_enter=function(){return this.mouse_on_container=!0},a.prototype.mouse_leave=function(){return this.mouse_on_container=!1},a.prototype.input_focus=function(a){if(!this.active_field)return setTimeout(c(function(){return this.container_mousedown()},this),50)},a.prototype.input_blur=function(a){if(!this.mouse_on_container)return this.active_field=!1,setTimeout(c(function(){return this.blur_test()},this),100)},a.prototype.result_add_option=function(a){var b,c;return a.disabled?"":(a.dom_id=this.container_id+"_o_"+a.array_index,b=a.selected&&this.is_multiple?[]:["active-result"],a.selected&&b.push("result-selected"),a.group_array_index!=null&&b.push("group-option"),a.classes!==""&&b.push(a.classes),c=a.style.cssText!==""?' style="'+a.style+'"':"",'<li id="'+a.dom_id+'" class="'+b.join(" ")+'"'+c+">"+a.html+"</li>")},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('<a href="javascript:void(0)" class="chzn-single"><span>#{default}</span><div><b></b></div></a><div class="chzn-drop" style="left:-9000px;"><div class="chzn-search"><input type="text" autocomplete="off" /></div><ul class="chzn-results"></ul></div>'),this.multi_temp=new Template('<ul class="chzn-choices"><li class="search-field"><input type="text" value="#{default}" class="default" autocomplete="off" style="width:25px;" /></li></ul><div class="chzn-drop" style="left:-9000px;"><ul class="chzn-results"></ul></div>'),this.choice_temp=new Template('<li class="search-choice" id="#{id}"><span>#{choice}</span><a href="javascript:void(0)" class="search-choice-close" rel="#{position}"></a></li>'),this.no_results_temp=new Template('<li class="no-results">'+this.results_none_found+' "<span>#{terms}</span>"</li>')},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<e;d++)b=f[d],b.group?a+=this.result_add_group(b):b.empty||(a+=this.result_add_option(b),b.selected&&this.is_multiple?this.choice_build(b):b.selected&&!this.is_multiple&&(this.selected_item.down("span").update(b.html),this.allow_single_deselect&&this.single_deselect_control_build()));return this.search_field_disabled(),this.show_search_field_default(),this.search_field_scale(),this.search_results.update(a),this.parsing=!1},a.prototype.result_add_group=function(a){return a.disabled?"":(a.dom_id=this.container_id+"_g_"+a.array_index,'<li id="'+a.dom_id+'" class="group-result">'+a.label.escapeHTML()+"</li>")},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(c<f)return this.search_results.scrollTop=c},a.prototype.result_clear_highlight=function(){return this.result_highlight&&this.result_highlight.removeClassName("highlighted"),this.result_highlight=null},a.prototype.results_show=function(){var a;return this.is_multiple||(this.selected_item.addClassName("chzn-single-with-drop"),this.result_single_selected&&this.result_do_highlight(this.result_single_selected)),a=this.is_multiple?this.container.getHeight():this.container.getHeight()-1,this.dropdown.setStyle({top:a+"px",left:0}),this.results_showing=!0,this.search_field.focus(),this.search_field.value=this.search_field.value,this.winnow_results()},a.prototype.results_hide=function(){return this.is_multiple||this.selected_item.removeClassName("chzn-single-with-drop"),this.result_clear_highlight(),this.dropdown.setStyle({left:"-9000px"}),this.results_showing=!1},a.prototype.set_tab_index=function(a){var b;if(this.form_field.tabIndex)return b=this.form_field.tabIndex,this.form_field.tabIndex=-1,this.is_multiple?this.search_field.tabIndex=b:(this.selected_item.tabIndex=b,this.search_field.tabIndex=-1)},a.prototype.show_search_field_default=function(){return this.is_multiple&&this.choices<1&&!this.active_field?(this.search_field.value=this.default_text,this.search_field.addClassName("default")):(this.search_field.value="",this.search_field.removeClassName("default"))},a.prototype.search_results_mouseup=function(a){var b;b=a.target.hasClassName("active-result")?a.target:a.target.up(".active-result");if(b)return this.result_highlight=b,this.result_select(a)},a.prototype.search_results_mouseover=function(a){var b;b=a.target.hasClassName("active-result")?a.target:a.target.up(".active-result");if(b)return this.result_do_highlight(b)},a.prototype.search_results_mouseout=function(a){if(a.target.hasClassName("active-result")||a.target.up(".active-result"))return this.result_clear_highlight()},a.prototype.choices_click=function(a){a.preventDefault();if(this.active_field&&!a.target.hasClassName("search-choice")&&!a.target.up(".search-choice")&&!this.results_showing)return this.results_show()},a.prototype.choice_build=function(a){var b,c;return b=this.container_id+"_c_"+a.array_index,this.choices+=1,this.search_container.insert({before:this.choice_temp.evaluate({id:b,choice:a.html,position:a.array_index})}),c=$(b).down("a"),c.observe("click",f(function(a){return this.choice_destroy_link_click(a)},this))},a.prototype.choice_destroy_link_click=function(a){a.preventDefault();if(!this.is_disabled)return this.pending_destroy_click=!0,this.choice_destroy(a.target)},a.prototype.choice_destroy=function(a){return this.choices-=1,this.show_search_field_default(),this.is_multiple&&this.choices>0&&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:'<abbr class="search-choice-close"></abbr>'})},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<n;l++){b=p[l];if(!b.disabled&&!b.empty)if(b.group)$(b.dom_id).hide();else if(!this.is_multiple||!b.selected){a=!1,f=b.dom_id;if(e.test(b.html))a=!0,g+=1;else if(b.html.indexOf(" ")>=0||b.html.indexOf("[")===0){d=b.html.replace(/\[|\]/g,"").split(" ");if(d.length)for(m=0,o=d.length;m<o;m++)c=d[m],e.test(c)&&(a=!0,g+=1)}a?(h.length?(i=b.html.search(k),j=b.html.substr(0,i+h.length)+"</em>"+b.html.substr(i+h.length),j=j.substr(0,i)+"<em>"+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;c<d;c++)a=b[c],e.push(a.hasClassName("group-result")?a.show():!this.is_multiple||!a.hasClassName("result-selected")?this.result_activate(a):void 0);return e},a.prototype.winnow_results_set_highlight=function(){var a;if(!this.result_highlight){this.is_multiple||(a=this.search_results.down(".result-selected.active-result")),a==null&&(a=this.search_results.down(".active-result"));if(a!=null)return this.result_do_highlight(a)}},a.prototype.no_results=function(a){return this.search_results.insert(this.no_results_temp.evaluate({terms:a}))},a.prototype.no_results_clear=function(){var a,b;a=null,b=[];while(a=this.search_results.down(".no-results"))b.push(a.remove());return b},a.prototype.keydown_arrow=function(){var a,b,c;a=this.search_results.select("li.active-result");if(a.length){this.result_highlight?this.results_showing&&(c=this.result_highlight.nextSiblings(),b=c.intersect(a),b.length&&this.result_do_highlight(b.first())):this.result_do_highlight(a.first());if(!this.results_showing)return this.results_show()}},a.prototype.keyup_arrow=function(){var a,b,c;if(!this.results_showing&&!this.is_multiple)return this.results_show();if(this.result_highlight)return c=this.result_highlight.previousSiblings(),a=this.search_results.select("li.active-result"),b=c.intersect(a),b.length?this.result_do_highlight(b.first()):(this.choices>0&&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;h<i;h++)d=f[h],e+=d+":"+this.search_field.getStyle(d)+";";return b=(new Element("div",{style:e})).update(this.search_field.value.escapeHTML()),document.body.appendChild(b),g=Element.measure(b,"width")+25,b.remove(),g>this.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)
|
||||
((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<e;d++)c=f[d],g.push(this.add_option(c,b,a.disabled));return g},a.prototype.add_option=function(a,b,c){if(a.nodeName==="OPTION")return a.text!==""?(b!=null&&(this.parsed[b].children+=1),this.parsed.push({array_index:this.parsed.length,options_index:this.options_index,value:a.value,text:a.text,html:a.innerHTML,selected:a.selected,disabled:c===!0?c:a.disabled,group_array_index:b,classes:a.className,style:a.style.cssText})):this.parsed.push({array_index:this.parsed.length,options_index:this.options_index,empty:!0}),this.options_index+=1},a}(),a.select_to_array=function(b){var c,d,e,f,g;d=new a,g=b.childNodes;for(e=0,f=g.length;e<f;e++)c=g[e],d.add_node(c);return d.parsed},this.SelectParser=a})).call(this),function(){var a,b;b=this,a=function(){function a(a,b){this.form_field=a,this.options=b!=null?b:{},this.set_default_values(),this.is_multiple=this.form_field.multiple,this.default_text_default=this.is_multiple?"Select Some Options":"Select an Option",this.setup(),this.set_up_html(),this.register_observers(),this.finish_setup()}return a.prototype.set_default_values=function(){var a=this;return this.click_test_action=function(b){return a.test_active_click(b)},this.activate_action=function(b){return a.activate_field(b)},this.active_field=!1,this.mouse_on_container=!1,this.results_showing=!1,this.result_highlighted=null,this.result_single_selected=null,this.allow_single_deselect=this.options.allow_single_deselect!=null&&this.form_field.options[0]!=null&&this.form_field.options[0].text===""?this.options.allow_single_deselect:!1,this.disable_search_threshold=this.options.disable_search_threshold||0,this.choices=0,this.results_none_found=this.options.no_results_text||"No results match"},a.prototype.mouse_enter=function(){return this.mouse_on_container=!0},a.prototype.mouse_leave=function(){return this.mouse_on_container=!1},a.prototype.input_focus=function(a){var b=this;if(!this.active_field)return setTimeout(function(){return b.container_mousedown()},50)},a.prototype.input_blur=function(a){var b=this;if(!this.mouse_on_container)return this.active_field=!1,setTimeout(function(){return b.blur_test()},100)},a.prototype.result_add_option=function(a){var b,c;return a.disabled?"":(a.dom_id=this.container_id+"_o_"+a.array_index,b=a.selected&&this.is_multiple?[]:["active-result"],a.selected&&b.push("result-selected"),a.group_array_index!=null&&b.push("group-option"),a.classes!==""&&b.push(a.classes),c=a.style.cssText!==""?' style="'+a.style+'"':"",'<li id="'+a.dom_id+'" class="'+b.join(" ")+'"'+c+">"+a.html+"</li>")},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('<a href="javascript:void(0)" class="chzn-single"><span>#{default}</span><div><b></b></div></a><div class="chzn-drop" style="left:-9000px;"><div class="chzn-search"><input type="text" autocomplete="off" /></div><ul class="chzn-results"></ul></div>'),this.multi_temp=new Template('<ul class="chzn-choices"><li class="search-field"><input type="text" value="#{default}" class="default" autocomplete="off" style="width:25px;" /></li></ul><div class="chzn-drop" style="left:-9000px;"><ul class="chzn-results"></ul></div>'),this.choice_temp=new Template('<li class="search-choice" id="#{id}"><span>#{choice}</span><a href="javascript:void(0)" class="search-choice-close" rel="#{position}"></a></li>'),this.no_results_temp=new Template('<li class="no-results">'+this.results_none_found+' "<span>#{terms}</span>"</li>')},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<e;d++)b=f[d],b.group?a+=this.result_add_group(b):b.empty||(a+=this.result_add_option(b),b.selected&&this.is_multiple?this.choice_build(b):b.selected&&!this.is_multiple&&(this.selected_item.down("span").update(b.html),this.allow_single_deselect&&this.single_deselect_control_build()));return this.search_field_disabled(),this.show_search_field_default(),this.search_field_scale(),this.search_results.update(a),this.parsing=!1},d.prototype.result_add_group=function(a){return a.disabled?"":(a.dom_id=this.container_id+"_g_"+a.array_index,'<li id="'+a.dom_id+'" class="group-result">'+a.label.escapeHTML()+"</li>")},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(c<f)return this.search_results.scrollTop=c},d.prototype.result_clear_highlight=function(){return this.result_highlight&&this.result_highlight.removeClassName("highlighted"),this.result_highlight=null},d.prototype.results_show=function(){var a;return this.is_multiple||(this.selected_item.addClassName("chzn-single-with-drop"),this.result_single_selected&&this.result_do_highlight(this.result_single_selected)),a=this.is_multiple?this.container.getHeight():this.container.getHeight()-1,this.dropdown.setStyle({top:a+"px",left:0}),this.results_showing=!0,this.search_field.focus(),this.search_field.value=this.search_field.value,this.winnow_results()},d.prototype.results_hide=function(){return this.is_multiple||this.selected_item.removeClassName("chzn-single-with-drop"),this.result_clear_highlight(),this.dropdown.setStyle({left:"-9000px"}),this.results_showing=!1},d.prototype.set_tab_index=function(a){var b;if(this.form_field.tabIndex)return b=this.form_field.tabIndex,this.form_field.tabIndex=-1,this.is_multiple?this.search_field.tabIndex=b:(this.selected_item.tabIndex=b,this.search_field.tabIndex=-1)},d.prototype.show_search_field_default=function(){return this.is_multiple&&this.choices<1&&!this.active_field?(this.search_field.value=this.default_text,this.search_field.addClassName("default")):(this.search_field.value="",this.search_field.removeClassName("default"))},d.prototype.search_results_mouseup=function(a){var b;b=a.target.hasClassName("active-result")?a.target:a.target.up(".active-result");if(b)return this.result_highlight=b,this.result_select(a)},d.prototype.search_results_mouseover=function(a){var b;b=a.target.hasClassName("active-result")?a.target:a.target.up(".active-result");if(b)return this.result_do_highlight(b)},d.prototype.search_results_mouseout=function(a){if(a.target.hasClassName("active-result")||a.target.up(".active-result"))return this.result_clear_highlight()},d.prototype.choices_click=function(a){a.preventDefault();if(this.active_field&&!a.target.hasClassName("search-choice")&&!a.target.up(".search-choice")&&!this.results_showing)return this.results_show()},d.prototype.choice_build=function(a){var b,c,d=this;return b=this.container_id+"_c_"+a.array_index,this.choices+=1,this.search_container.insert({before:this.choice_temp.evaluate({id:b,choice:a.html,position:a.array_index})}),c=$(b).down("a"),c.observe("click",function(a){return d.choice_destroy_link_click(a)})},d.prototype.choice_destroy_link_click=function(a){a.preventDefault();if(!this.is_disabled)return this.pending_destroy_click=!0,this.choice_destroy(a.target)},d.prototype.choice_destroy=function(a){return this.choices-=1,this.show_search_field_default(),this.is_multiple&&this.choices>0&&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:'<abbr class="search-choice-close"></abbr>'})},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<n;l++){b=p[l];if(!b.disabled&&!b.empty)if(b.group)$(b.dom_id).hide();else if(!this.is_multiple||!b.selected){a=!1,f=b.dom_id;if(e.test(b.html))a=!0,g+=1;else if(b.html.indexOf(" ")>=0||b.html.indexOf("[")===0){d=b.html.replace(/\[|\]/g,"").split(" ");if(d.length)for(m=0,o=d.length;m<o;m++)c=d[m],e.test(c)&&(a=!0,g+=1)}a?(h.length?(i=b.html.search(k),j=b.html.substr(0,i+h.length)+"</em>"+b.html.substr(i+h.length),j=j.substr(0,i)+"<em>"+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;c<d;c++)a=b[c],a.hasClassName("group-result")?e.push(a.show()):!this.is_multiple||!a.hasClassName("result-selected")?e.push(this.result_activate(a)):e.push(void 0);return e},d.prototype.winnow_results_set_highlight=function(){var a;if(!this.result_highlight){this.is_multiple||(a=this.search_results.down(".result-selected.active-result")),a==null&&(a=this.search_results.down(".active-result"));if(a!=null)return this.result_do_highlight(a)}},d.prototype.no_results=function(a){return this.search_results.insert(this.no_results_temp.evaluate({terms:a}))},d.prototype.no_results_clear=function(){var a,b;a=null,b=[];while(a=this.search_results.down(".no-results"))b.push(a.remove());return b},d.prototype.keydown_arrow=function(){var a,b,c;a=this.search_results.select("li.active-result");if(a.length){this.result_highlight?this.results_showing&&(c=this.result_highlight.nextSiblings(),b=c.intersect(a),b.length&&this.result_do_highlight(b.first())):this.result_do_highlight(a.first());if(!this.results_showing)return this.results_show()}},d.prototype.keyup_arrow=function(){var a,b,c;if(!this.results_showing&&!this.is_multiple)return this.results_show();if(this.result_highlight)return c=this.result_highlight.previousSiblings(),a=this.search_results.select("li.active-result"),b=c.intersect(a),b.length?this.result_do_highlight(b.first()):(this.choices>0&&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;h<i;h++)d=f[h],e+=d+":"+this.search_field.getStyle(d)+";";return b=(new Element("div",{style:e})).update(this.search_field.value.escapeHTML()),document.body.appendChild(b),g=Element.measure(b,"width")+25,b.remove(),g>this.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)
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
|
476
admin/thirdparty/chosen/example.proto.html
vendored
@ -54,13 +54,12 @@
|
||||
<h1>Chosen</h1>
|
||||
<p>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 <a href="http://harvesthq.github.com/chosen/">online documentation</a>.</p>
|
||||
|
||||
<h2>Standard Select</h2>
|
||||
<h2>Multiple Select</h2>
|
||||
<div class="side-by-side clearfix">
|
||||
<div>
|
||||
<em>Turns This</em>
|
||||
<select data-placeholder="Choose a Country..." style="width:350px;" tabindex="1">
|
||||
<option value=""></option>
|
||||
<option value="United States">United States</option>
|
||||
<select data-placeholder="Choose a Country..." style="width:350px;" multiple tabindex="3">
|
||||
<option value="United States" disabled="disabled" selected="selected">United States</option>
|
||||
<option value="United Kingdom">United Kingdom</option>
|
||||
<option value="Afghanistan">Afghanistan</option>
|
||||
<option value="Albania">Albania</option>
|
||||
@ -307,11 +306,11 @@
|
||||
</div>
|
||||
<div>
|
||||
<em>Into This</em>
|
||||
<select data-placeholder="Choose a Country..." class="chzn-select" style="width:350px;" tabindex="2">
|
||||
<select data-placeholder="Choose a Country..." class="chzn-select" multiple style="width:350px;" tabindex="4">
|
||||
<option value=""></option>
|
||||
<option value="United States">United States</option>
|
||||
<option value="United States" disabled="disabled" selected="selected">United States</option>
|
||||
<option value="United Kingdom">United Kingdom</option>
|
||||
<option value="Afghanistan">Afghanistan</option>
|
||||
<option value="Afghanistan" disabled="disabled">Afghanistan</option>
|
||||
<option value="Albania">Albania</option>
|
||||
<option value="Algeria">Algeria</option>
|
||||
<option value="American Samoa">American Samoa</option>
|
||||
@ -556,212 +555,267 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Multiple Select</h2>
|
||||
<h2><optgroup> Support</h2>
|
||||
<div class="side-by-side clearfix">
|
||||
<div>
|
||||
<em>Turns This</em>
|
||||
<select data-placeholder="Choose a Country..." style="width:350px;" multiple tabindex="3">
|
||||
<option value="United States">United States</option>
|
||||
<option value="United Kingdom">United Kingdom</option>
|
||||
<option value="Afghanistan">Afghanistan</option>
|
||||
<option value="Albania">Albania</option>
|
||||
<option value="Algeria">Algeria</option>
|
||||
<option value="American Samoa">American Samoa</option>
|
||||
<option value="Andorra">Andorra</option>
|
||||
<option value="Angola">Angola</option>
|
||||
<option value="Anguilla">Anguilla</option>
|
||||
<option value="Antarctica">Antarctica</option>
|
||||
<option value="Antigua and Barbuda">Antigua and Barbuda</option>
|
||||
<option value="Argentina">Argentina</option>
|
||||
<option value="Armenia">Armenia</option>
|
||||
<option value="Aruba">Aruba</option>
|
||||
<option value="Australia">Australia</option>
|
||||
<option value="Austria">Austria</option>
|
||||
<option value="Azerbaijan">Azerbaijan</option>
|
||||
<option value="Bahamas">Bahamas</option>
|
||||
<option value="Bahrain">Bahrain</option>
|
||||
<option value="Bangladesh">Bangladesh</option>
|
||||
<option value="Barbados">Barbados</option>
|
||||
<option value="Belarus">Belarus</option>
|
||||
<option value="Belgium">Belgium</option>
|
||||
<option value="Belize">Belize</option>
|
||||
<option value="Benin">Benin</option>
|
||||
<option value="Bermuda">Bermuda</option>
|
||||
<option value="Bhutan">Bhutan</option>
|
||||
<option value="Bolivia">Bolivia</option>
|
||||
<option value="Bosnia and Herzegovina">Bosnia and Herzegovina</option>
|
||||
<option value="Botswana">Botswana</option>
|
||||
<option value="Bouvet Island">Bouvet Island</option>
|
||||
<option value="Brazil">Brazil</option>
|
||||
<option value="British Indian Ocean Territory">British Indian Ocean Territory</option>
|
||||
<option value="Brunei Darussalam">Brunei Darussalam</option>
|
||||
<option value="Bulgaria">Bulgaria</option>
|
||||
<option value="Burkina Faso">Burkina Faso</option>
|
||||
<option value="Burundi">Burundi</option>
|
||||
<option value="Cambodia">Cambodia</option>
|
||||
<option value="Cameroon">Cameroon</option>
|
||||
<option value="Canada">Canada</option>
|
||||
<option value="Cape Verde">Cape Verde</option>
|
||||
<option value="Cayman Islands">Cayman Islands</option>
|
||||
<option value="Central African Republic">Central African Republic</option>
|
||||
<option value="Chad">Chad</option>
|
||||
<option value="Chile">Chile</option>
|
||||
<option value="China">China</option>
|
||||
<option value="Christmas Island">Christmas Island</option>
|
||||
<option value="Cocos (Keeling) Islands">Cocos (Keeling) Islands</option>
|
||||
<option value="Colombia">Colombia</option>
|
||||
<option value="Comoros">Comoros</option>
|
||||
<option value="Congo">Congo</option>
|
||||
<option value="Congo, The Democratic Republic of The">Congo, The Democratic Republic of The</option>
|
||||
<option value="Cook Islands">Cook Islands</option>
|
||||
<option value="Costa Rica">Costa Rica</option>
|
||||
<option value="Cote D'ivoire">Cote D'ivoire</option>
|
||||
<option value="Croatia">Croatia</option>
|
||||
<option value="Cuba">Cuba</option>
|
||||
<option value="Cyprus">Cyprus</option>
|
||||
<option value="Czech Republic">Czech Republic</option>
|
||||
<option value="Denmark">Denmark</option>
|
||||
<option value="Djibouti">Djibouti</option>
|
||||
<option value="Dominica">Dominica</option>
|
||||
<option value="Dominican Republic">Dominican Republic</option>
|
||||
<option value="Ecuador">Ecuador</option>
|
||||
<option value="Egypt">Egypt</option>
|
||||
<option value="El Salvador">El Salvador</option>
|
||||
<option value="Equatorial Guinea">Equatorial Guinea</option>
|
||||
<option value="Eritrea">Eritrea</option>
|
||||
<option value="Estonia">Estonia</option>
|
||||
<option value="Ethiopia">Ethiopia</option>
|
||||
<option value="Falkland Islands (Malvinas)">Falkland Islands (Malvinas)</option>
|
||||
<option value="Faroe Islands">Faroe Islands</option>
|
||||
<option value="Fiji">Fiji</option>
|
||||
<option value="Finland">Finland</option>
|
||||
<option value="France">France</option>
|
||||
<option value="French Guiana">French Guiana</option>
|
||||
<option value="French Polynesia">French Polynesia</option>
|
||||
<option value="French Southern Territories">French Southern Territories</option>
|
||||
<option value="Gabon">Gabon</option>
|
||||
<option value="Gambia">Gambia</option>
|
||||
<option value="Georgia">Georgia</option>
|
||||
<option value="Germany">Germany</option>
|
||||
<option value="Ghana">Ghana</option>
|
||||
<option value="Gibraltar">Gibraltar</option>
|
||||
<option value="Greece">Greece</option>
|
||||
<option value="Greenland">Greenland</option>
|
||||
<option value="Grenada">Grenada</option>
|
||||
<option value="Guadeloupe">Guadeloupe</option>
|
||||
<option value="Guam">Guam</option>
|
||||
<option value="Guatemala">Guatemala</option>
|
||||
<option value="Guinea">Guinea</option>
|
||||
<option value="Guinea-bissau">Guinea-bissau</option>
|
||||
<option value="Guyana">Guyana</option>
|
||||
<option value="Haiti">Haiti</option>
|
||||
<option value="Heard Island and Mcdonald Islands">Heard Island and Mcdonald Islands</option>
|
||||
<option value="Holy See (Vatican City State)">Holy See (Vatican City State)</option>
|
||||
<option value="Honduras">Honduras</option>
|
||||
<option value="Hong Kong">Hong Kong</option>
|
||||
<option value="Hungary">Hungary</option>
|
||||
<option value="Iceland">Iceland</option>
|
||||
<option value="India">India</option>
|
||||
<option value="Indonesia">Indonesia</option>
|
||||
<option value="Iran, Islamic Republic of">Iran, Islamic Republic of</option>
|
||||
<option value="Iraq">Iraq</option>
|
||||
<option value="Ireland">Ireland</option>
|
||||
<option value="Israel">Israel</option>
|
||||
<option value="Italy">Italy</option>
|
||||
<option value="Jamaica">Jamaica</option>
|
||||
<option value="Japan">Japan</option>
|
||||
<option value="Jordan">Jordan</option>
|
||||
<option value="Kazakhstan">Kazakhstan</option>
|
||||
<option value="Kenya">Kenya</option>
|
||||
<option value="Kiribati">Kiribati</option>
|
||||
<option value="Korea, Democratic People's Republic of">Korea, Democratic People's Republic of</option>
|
||||
<option value="Korea, Republic of">Korea, Republic of</option>
|
||||
<option value="Kuwait">Kuwait</option>
|
||||
<option value="Kyrgyzstan">Kyrgyzstan</option>
|
||||
<option value="Lao People's Democratic Republic">Lao People's Democratic Republic</option>
|
||||
<option value="Latvia">Latvia</option>
|
||||
<option value="Lebanon">Lebanon</option>
|
||||
<option value="Lesotho">Lesotho</option>
|
||||
<option value="Liberia">Liberia</option>
|
||||
<option value="Libyan Arab Jamahiriya">Libyan Arab Jamahiriya</option>
|
||||
<option value="Liechtenstein">Liechtenstein</option>
|
||||
<option value="Lithuania">Lithuania</option>
|
||||
<option value="Luxembourg">Luxembourg</option>
|
||||
<option value="Macao">Macao</option>
|
||||
<option value="Macedonia, The Former Yugoslav Republic of">Macedonia, The Former Yugoslav Republic of</option>
|
||||
<option value="Madagascar">Madagascar</option>
|
||||
<option value="Malawi">Malawi</option>
|
||||
<option value="Malaysia">Malaysia</option>
|
||||
<option value="Maldives">Maldives</option>
|
||||
<option value="Mali">Mali</option>
|
||||
<option value="Malta">Malta</option>
|
||||
<option value="Marshall Islands">Marshall Islands</option>
|
||||
<option value="Martinique">Martinique</option>
|
||||
<option value="Mauritania">Mauritania</option>
|
||||
<option value="Mauritius">Mauritius</option>
|
||||
<option value="Mayotte">Mayotte</option>
|
||||
<option value="Mexico">Mexico</option>
|
||||
<option value="Micronesia, Federated States of">Micronesia, Federated States of</option>
|
||||
<option value="Moldova, Republic of">Moldova, Republic of</option>
|
||||
<option value="Monaco">Monaco</option>
|
||||
<option value="Mongolia">Mongolia</option>
|
||||
<option value="Montenegro">Montenegro</option>
|
||||
<option value="Montserrat">Montserrat</option>
|
||||
<option value="Morocco">Morocco</option>
|
||||
<option value="Mozambique">Mozambique</option>
|
||||
<option value="Myanmar">Myanmar</option>
|
||||
<option value="Namibia">Namibia</option>
|
||||
<option value="Nauru">Nauru</option>
|
||||
<option value="Nepal">Nepal</option>
|
||||
<option value="Netherlands">Netherlands</option>
|
||||
<option value="Netherlands Antilles">Netherlands Antilles</option>
|
||||
<option value="New Caledonia">New Caledonia</option>
|
||||
<option value="New Zealand">New Zealand</option>
|
||||
<option value="Nicaragua">Nicaragua</option>
|
||||
<option value="Niger">Niger</option>
|
||||
<option value="Nigeria">Nigeria</option>
|
||||
<option value="Niue">Niue</option>
|
||||
<option value="Norfolk Island">Norfolk Island</option>
|
||||
<option value="Northern Mariana Islands">Northern Mariana Islands</option>
|
||||
<option value="Norway">Norway</option>
|
||||
<option value="Oman">Oman</option>
|
||||
<option value="Pakistan">Pakistan</option>
|
||||
<option value="Palau">Palau</option>
|
||||
<option value="Palestinian Territory, Occupied">Palestinian Territory, Occupied</option>
|
||||
<option value="Panama">Panama</option>
|
||||
<option value="Papua New Guinea">Papua New Guinea</option>
|
||||
<option value="Paraguay">Paraguay</option>
|
||||
<option value="Peru">Peru</option>
|
||||
<option value="Philippines">Philippines</option>
|
||||
<option value="Pitcairn">Pitcairn</option>
|
||||
<option value="Poland">Poland</option>
|
||||
<option value="Portugal">Portugal</option>
|
||||
<option value="Puerto Rico">Puerto Rico</option>
|
||||
<option value="Qatar">Qatar</option>
|
||||
<option value="Reunion">Reunion</option>
|
||||
<option value="Romania">Romania</option>
|
||||
<option value="Russian Federation">Russian Federation</option>
|
||||
<option value="Rwanda">Rwanda</option>
|
||||
<option value="Saint Helena">Saint Helena</option>
|
||||
<option value="Saint Kitts and Nevis">Saint Kitts and Nevis</option>
|
||||
<option value="Saint Lucia">Saint Lucia</option>
|
||||
<option value="Saint Pierre and Miquelon">Saint Pierre and Miquelon</option>
|
||||
<option value="Saint Vincent and The Grenadines">Saint Vincent and The Grenadines</option>
|
||||
<option value="Samoa">Samoa</option>
|
||||
<option value="San Marino">San Marino</option>
|
||||
<option value="Sao Tome and Principe">Sao Tome and Principe</option>
|
||||
<option value="Saudi Arabia">Saudi Arabia</option>
|
||||
<option value="Senegal">Senegal</option>
|
||||
<option value="Serbia">Serbia</option>
|
||||
<option value="Seychelles">Seychelles</option>
|
||||
<option value="Sierra Leone">Sierra Leone</option>
|
||||
<option value="Singapore">Singapore</option>
|
||||
<option value="Slovakia">Slovakia</option>
|
||||
<option value="Slovenia">Slovenia</option>
|
||||
<option value="Solomon Islands">Solomon Islands</option>
|
||||
<option value="Somalia">Somalia</option>
|
||||
<option value="South Africa">South Africa</option>
|
||||
<option value="South Georgia and The South Sandwich Islands">South Georgia and The South Sandwich Islands</option>
|
||||
<em>Single Select with Groups</em>
|
||||
<select data-placeholder="Your Favorite Football Team" style="width:350px;" class="chzn-select" tabindex="5">
|
||||
<option value=""></option>
|
||||
<optgroup label="NFC EAST">
|
||||
<option>Dallas Cowboys</option>
|
||||
<option>New York Giants</option>
|
||||
<option>Philadelphia Eagles</option>
|
||||
<option>Washington Redskins</option>
|
||||
</optgroup>
|
||||
<optgroup label="NFC NORTH">
|
||||
<option>Chicago Bears</option>
|
||||
<option>Detroit Lions</option>
|
||||
<option>Green Bay Packers</option>
|
||||
<option>Minnesota Vikings</option>
|
||||
</optgroup>
|
||||
<optgroup label="NFC SOUTH">
|
||||
<option>Atlanta Falcons</option>
|
||||
<option>Carolina Panthers</option>
|
||||
<option>New Orleans Saints</option>
|
||||
<option>Tampa Bay Buccaneers</option>
|
||||
</optgroup>
|
||||
<optgroup label="NFC WEST">
|
||||
<option>Arizona Cardinals</option>
|
||||
<option>St. Louis Rams</option>
|
||||
<option>San Francisco 49ers</option>
|
||||
<option>Seattle Seahawks</option>
|
||||
</optgroup>
|
||||
<optgroup label="AFC EAST">
|
||||
<option>Buffalo Bills</option>
|
||||
<option>Miami Dolphins</option>
|
||||
<option>New England Patriots</option>
|
||||
<option>New York Jets</option>
|
||||
</optgroup>
|
||||
<optgroup label="AFC NORTH">
|
||||
<option>Baltimore Ravens</option>
|
||||
<option>Cincinnati Bengals</option>
|
||||
<option>Cleveland Browns</option>
|
||||
<option>Pittsburgh Steelers</option>
|
||||
</optgroup>
|
||||
<optgroup label="AFC SOUTH">
|
||||
<option>Houston Texans</option>
|
||||
<option>Indianapolis Colts</option>
|
||||
<option>Jacksonville Jaguars</option>
|
||||
<option>Tennessee Titans</option>
|
||||
</optgroup>
|
||||
<optgroup label="AFC WEST">
|
||||
<option>Denver Broncos</option>
|
||||
<option>Kansas City Chiefs</option>
|
||||
<option>Oakland Raiders</option>
|
||||
<option>San Diego Chargers</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<em>Multiple Select with Groups</em>
|
||||
<select data-placeholder="Your Favorite Football Team" style="width:350px;" class="chzn-select" multiple tabindex="6">
|
||||
<option value=""></option>
|
||||
<optgroup label="NFC EAST">
|
||||
<option>Dallas Cowboys</option>
|
||||
<option>New York Giants</option>
|
||||
<option>Philadelphia Eagles</option>
|
||||
<option>Washington Redskins</option>
|
||||
</optgroup>
|
||||
<optgroup label="NFC NORTH">
|
||||
<option>Chicago Bears</option>
|
||||
<option>Detroit Lions</option>
|
||||
<option>Green Bay Packers</option>
|
||||
<option>Minnesota Vikings</option>
|
||||
</optgroup>
|
||||
<optgroup label="NFC SOUTH">
|
||||
<option>Atlanta Falcons</option>
|
||||
<option>Carolina Panthers</option>
|
||||
<option>New Orleans Saints</option>
|
||||
<option>Tampa Bay Buccaneers</option>
|
||||
</optgroup>
|
||||
<optgroup label="NFC WEST">
|
||||
<option>Arizona Cardinals</option>
|
||||
<option>St. Louis Rams</option>
|
||||
<option>San Francisco 49ers</option>
|
||||
<option>Seattle Seahawks</option>
|
||||
</optgroup>
|
||||
<optgroup label="AFC EAST">
|
||||
<option>Buffalo Bills</option>
|
||||
<option>Miami Dolphins</option>
|
||||
<option>New England Patriots</option>
|
||||
<option>New York Jets</option>
|
||||
</optgroup>
|
||||
<optgroup label="AFC NORTH">
|
||||
<option>Baltimore Ravens</option>
|
||||
<option>Cincinnati Bengals</option>
|
||||
<option>Cleveland Browns</option>
|
||||
<option>Pittsburgh Steelers</option>
|
||||
</optgroup>
|
||||
<optgroup label="AFC SOUTH">
|
||||
<option>Houston Texans</option>
|
||||
<option>Indianapolis Colts</option>
|
||||
<option>Jacksonville Jaguars</option>
|
||||
<option>Tennessee Titans</option>
|
||||
</optgroup>
|
||||
<optgroup label="AFC WEST">
|
||||
<option>Denver Broncos</option>
|
||||
<option>Kansas City Chiefs</option>
|
||||
<option>Oakland Raiders</option>
|
||||
<option>San Diego Chargers</option>
|
||||
</optgroup>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Selected and Disabled Support</h2>
|
||||
<div class="side-by-side clearfix">
|
||||
<p>Chosen automatically highlights selected options and removes disabled options.</p>
|
||||
<div>
|
||||
<em>Single Select</em>
|
||||
<select data-placeholder="Your Favorite Type of Bear" style="width:350px;" class="chzn-select" tabindex="7">
|
||||
<option value=""></option>
|
||||
<option>American Black Bear</option>
|
||||
<option>Asiatic Black Bear</option>
|
||||
<option>Brown Bear</option>
|
||||
<option>Giant Panda</option>
|
||||
<option selected>Sloth Bear</option>
|
||||
<option disabled>Sun Bear</option>
|
||||
<option>Polar Bear</option>
|
||||
<option disabled>Spectacled Bear</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<em>Multiple Select</em>
|
||||
<select data-placeholder="Your Favorite Types of Bear" style="width:350px;" multiple class="chzn-select" tabindex="8">
|
||||
<option value=""></option>
|
||||
<option>American Black Bear</option>
|
||||
<option>Asiatic Black Bear</option>
|
||||
<option>Brown Bear</option>
|
||||
<option>Giant Panda</option>
|
||||
<option selected>Sloth Bear</option>
|
||||
<option disabled>Sun Bear</option>
|
||||
<option selected>Polar Bear</option>
|
||||
<option disabled>Spectacled Bear</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Default Text Support</h2>
|
||||
<div class="side-by-side clearfix">
|
||||
<p>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.</p>
|
||||
<code><select <strong>data-placeholder="Choose a country..."</strong> style="width:350px;" multiple class="chzn-select"></code>
|
||||
<p><strong>Note:</strong> 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.</p>
|
||||
</div>
|
||||
|
||||
<h2>No Results Text Support</h2>
|
||||
<div class="side-by-side clearfix">
|
||||
<p>Setting the "No results" search text is as easy as passing an option when you create Chosen:</p>
|
||||
<code>
|
||||
New Chosen($("chzn_select_field"),{no_results_text: "No results matched"});
|
||||
</code>
|
||||
</div>
|
||||
|
||||
<h2>Allow Deselect on Single Selects</h2>
|
||||
<div class="side-by-side clearfix">
|
||||
<p>When a single select box isn't a required field, you can set <code>allow_single_deselect: true</code> and Chosen will add a UI element for option deselection. This will only work if the first option has blank text.</p>
|
||||
<div class="side-by-side clearfix">
|
||||
<select data-placeholder="Your Favorite Type of Bear" style="width:350px;" class="chzn-select-deselect" tabindex="7">
|
||||
<option value=""></option>
|
||||
<option>American Black Bear</option>
|
||||
<option>Asiatic Black Bear</option>
|
||||
<option>Brown Bear</option>
|
||||
<option>Giant Panda</option>
|
||||
<option selected>Sloth Bear</option>
|
||||
<option>Sun Bear</option>
|
||||
<option>Polar Bear</option>
|
||||
<option>Spectacled Bear</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Right to Left Support</h2>
|
||||
<div class="side-by-side clearfix">
|
||||
<p>Chosen supports right to left select boxes too. just add <code>"chzn-rtl"</code> in addition to <code>"chzn-select"</code> to your select tags and you are good to go.</p>
|
||||
<p><code><select class="chzn-select <strong>chzn-rtl</strong>"></code></p>
|
||||
<div>
|
||||
<em>Single right to left select</em>
|
||||
<select data-placeholder="Your Favorite Type of Bear" style="width:350px;" class="chzn-select chzn-rtl" tabindex="9">
|
||||
<option value=""></option>
|
||||
<option>American Black Bear</option>
|
||||
<option>Asiatic Black Bear</option>
|
||||
<option>Brown Bear</option>
|
||||
<option>Giant Panda</option>
|
||||
<option selected>Sloth Bear</option>
|
||||
<option>Polar Bear</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<em>Multiple right to left select</em>
|
||||
<select data-placeholder="Your Favorite Types of Bear" style="width:350px;" multiple class="chzn-select chzn-rtl" tabindex="10">
|
||||
<option value=""></option>
|
||||
<option>American Black Bear</option>
|
||||
<option>Asiatic Black Bear</option>
|
||||
<option>Brown Bear</option>
|
||||
<option>Giant Panda</option>
|
||||
<option selected>Sloth Bear</option>
|
||||
<option selected>Polar Bear</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h2>Change / Update Events</h2>
|
||||
<div class="side-by-side clearfix">
|
||||
<ul>
|
||||
<li>
|
||||
<h3>Form Field Change</h3>
|
||||
<p>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:</p>
|
||||
<p><code>$("#form_field").chosen().change( … );</code></p>
|
||||
<p><strong>Note:</strong> Prototype doesn't offer support for triggering standard browser events. <a href="https://github.com/kangax/protolicious/blob/5b56fdafcd7d7662c9d648534225039b2e78e371/event.simulate.js">Event.simulate</a> is required to trigger the change event when using the Prototype version.</p>
|
||||
</li>
|
||||
<li>
|
||||
<h3>Updating Chosen Dynamically</h3>
|
||||
<p>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.</p>
|
||||
<ul>
|
||||
<li><strong>jQuery Version:</strong> <code>$("#form_field").trigger("liszt:updated");</code></li>
|
||||
<li><strong>Prototype Version:</strong> <code>Event.fire($("form_field"), "liszt:updated");</code></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<h2>Setup (for Prototype)</h2>
|
||||
<p>Using Chosen is easy as can be.</p>
|
||||
<ol>
|
||||
<li>Download the plugin and copy the chosen files to your app.</li>
|
||||
<li>Activate the plugin by creating a new instance of Chosen: new Chosen(<em>some_form_field</em>);</li>
|
||||
<li><a href="http://youtu.be/pS-RsIzb78U?t=57s">Disco</a>.</li>
|
||||
</ol>
|
||||
|
||||
</div>
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/prototype/1.7.0.0/prototype.js" type="text/javascript"></script>
|
||||
<script src="chosen/chosen.proto.js" type="text/javascript"></script>
|
||||
<script type="text/javascript">
|
||||
document.observe('dom:loaded', function(evt) {
|
||||
var select, selects, _i, _len, _results;
|
||||
if (Prototype.Browser.IE && (Prototype.BrowserFeatures['Version'] === 6 || Prototype.BrowserFeatures['Version'] === 7)) {
|
||||
return;
|
||||
}
|
||||
selects = $$(".chzn-select");
|
||||
_results = [];
|
||||
for (_i = 0, _len = selects.length; _i < _len; _i++) {
|
||||
select = selects[_i];
|
||||
_results.push(new Chosen(select));
|
||||
}
|
||||
deselects = $$(".chzn-select-deselect");
|
||||
for (_i = 0, _len = deselects.length; _i < _len; _i++) {
|
||||
select = deselects[_i];
|
||||
_results.push(new Chosen(select,{allow_single_deselect:true}));
|
||||
}
|
||||
return _results;
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
orgia and The South Sandwich Islands">South Georgia and The South Sandwich Islands</option>
|
||||
<option value="South Sudan">South Sudan</option>
|
||||
<option value="Spain">Spain</option>
|
||||
<option value="Sri Lanka">Sri Lanka</option>
|
||||
|
18
admin/thirdparty/chosen/package.json
vendored
Normal file
@ -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"
|
||||
}
|
||||
}
|
@ -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); }
|
||||
|
@ -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
|
||||
|
@ -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: `<a href="..." class="cms-panel-link" data-target-panel=".cms-content">`
|
||||
* Load via ajax, and show response status message: `<a href="..." class="cms-link-ajax">`
|
||||
* Load URL as an iframe into a popup/dialog: `<a href="..." class="ss-ui-dialog-link">`
|
||||
|
||||
## 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: `<a href="..." class="ss-ui-button" data-icon="add" />Button text</a>`
|
||||
|
||||
Output: `<a href="..." data-icon="add" class="ss-ui-button ss-ui-action-constructive ui-button ui-widget ui-state-default ui-corner-all ui-button-text-icon-primary" role="button"><span class="ui-button-icon-primary ui-icon btn-icon-add"></span><span class="ui-button-text">Button text</span></a>`
|
||||
|
||||
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,
|
||||
|
@ -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' => '<strong>$Email</strong>',
|
||||
));
|
||||
|
||||
**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!
|
||||
|
||||
|
@ -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,12 +375,16 @@ 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.
|
||||
* This can be useful when grouping files by type,
|
||||
|
@ -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
|
||||
);
|
||||
|
||||
|
@ -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 <select multiple> style - array(0 => 'val1', 1 => 'val2')
|
||||
// and <input type="checkbox"> style - array('val1' => true, 'val2' => true).
|
||||
// The <select multiple> element doesn't allow for individual keys in parameter names.
|
||||
$valuesInKeys = (ArrayLib::is_associative($this->value));
|
||||
if($this->value) foreach($this->value as $k => $v) {
|
||||
if($valuesInKeys) {
|
||||
if($v) $idList[] = $k;
|
||||
} else {
|
||||
$idList[] = $v;
|
||||
if($this->value) foreach($this->value as $id => $bool) {
|
||||
if($bool) {
|
||||
$idList[] = $id;
|
||||
}
|
||||
}
|
||||
$record->$fieldname()->setByIDList($idList);
|
||||
$relation->setByIDList($idList);
|
||||
} elseif($fieldname && $record) {
|
||||
if($this->value) {
|
||||
$this->value = str_replace(',', '{comma}', $this->value);
|
||||
@ -220,6 +215,7 @@ class CheckboxSetField extends OptionsetField {
|
||||
$filtered[] = str_replace(",", "{comma}", $item);
|
||||
}
|
||||
}
|
||||
|
||||
return implode(',', $filtered);
|
||||
}
|
||||
|
||||
|
@ -113,7 +113,7 @@ class ConfirmedPasswordField extends FormField {
|
||||
}
|
||||
|
||||
$content .= "<div class=\"showOnClick\">\n";
|
||||
$content .= "<a href=\"#\"" . $this->getTabIndexHTML() . ">{$title}</a>\n";
|
||||
$content .= "<a href=\"#\">{$title}</a>\n";
|
||||
$content .= "<div class=\"showOnClickContainer\">";
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,17 @@ class CreditCardField extends TextField {
|
||||
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);
|
||||
else return $this->value;
|
||||
|
@ -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,30 +218,24 @@ 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 . '"' : '';
|
||||
Deprecation::notice('3.0', 'Use getAttribute("tabindex") instead');
|
||||
return $this->getAttribute('tabindex');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -301,6 +288,12 @@ class FormField extends RequestHandler {
|
||||
/**
|
||||
* Set an HTML attribute on the field element, mostly an <input> 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,14 +682,22 @@ 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;
|
||||
}
|
||||
|
@ -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
|
||||
*/
|
||||
@ -49,6 +51,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;
|
||||
|
||||
if($controllerClass = $this->controllerClass()) {
|
||||
|
@ -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,
|
||||
)
|
||||
);
|
||||
|
@ -41,6 +41,16 @@ class ListboxField extends DropdownField {
|
||||
*/
|
||||
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 <select> tag containing all the appropriate <option> tags
|
||||
*/
|
||||
function Field($properties = array()) {
|
||||
if($this->multiple) {
|
||||
$this->name .= '[]';
|
||||
}
|
||||
|
||||
if($this->multiple) $this->name .= '[]';
|
||||
$options = array();
|
||||
|
||||
// We have an array of values
|
||||
if(is_array($this->value)){
|
||||
// Loop through and figure out which values were selected.
|
||||
|
||||
foreach($this->getSource() as $value => $title) {
|
||||
// Loop through the array of values to find out if this value is selected.
|
||||
$selected = "";
|
||||
foreach($this->value as $v){
|
||||
if($value == $v) {
|
||||
$selected = " selected=\"selected\"";
|
||||
break;
|
||||
}
|
||||
}
|
||||
$options[] = new ArrayData(array(
|
||||
'Title' => $title,
|
||||
'Value' => $value,
|
||||
'Selected' => $selected,
|
||||
'Selected' => (in_array($value, $this->value) || in_array($value, $this->defaultItems)),
|
||||
'Disabled' => $this->disabled || in_array($value, $this->disabledItems),
|
||||
));
|
||||
}
|
||||
} else {
|
||||
// Listbox was based a singlular value, so treat it like a dropdown.
|
||||
foreach($this->getSource() as $value => $title) {
|
||||
$selected = $value == $this->value ? " selected=\"selected\"" : "";
|
||||
$options[] = new ArrayData(array(
|
||||
'Title' => $title,
|
||||
'Value' => $value,
|
||||
'Selected' => $selected,
|
||||
'Selected' => ($value == $this->value || in_array($value, $this->defaultItems)),
|
||||
'Disabled' => $this->disabled || in_array($value, $this->disabledItems),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
$properties = array_merge($properties, array('Options' => new ArrayList($options)));
|
||||
return $this->customise($properties)->renderWith($this->getTemplate());
|
||||
}
|
||||
@ -144,17 +142,65 @@ class ListboxField extends DropdownField {
|
||||
}
|
||||
|
||||
/**
|
||||
* @return String
|
||||
* Return the CheckboxSetField value as a string
|
||||
* selected item keys.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function dataValue() {
|
||||
if($this->value && $this->multiple && is_array($this->value)) {
|
||||
return implode(',', $this->value);
|
||||
if($this->value && is_array($this->value) && $this->multiple) {
|
||||
$filtered = array();
|
||||
foreach($this->value as $item) {
|
||||
if($item) {
|
||||
$filtered[] = str_replace(",", "{comma}", $item);
|
||||
}
|
||||
}
|
||||
return implode(',', $filtered);
|
||||
} else {
|
||||
return parent::dataValue();
|
||||
}
|
||||
}
|
||||
|
||||
function setValue($val) {
|
||||
/**
|
||||
* Save the current value of this field into a DataObject.
|
||||
* If the field it is saving to is a has_many or many_many relationship,
|
||||
* it is saved by setByIDList(), otherwise it creates a comma separated
|
||||
* list for a standard DB text/varchar field.
|
||||
*
|
||||
* @param DataObject $record The record to save into
|
||||
*/
|
||||
function saveInto(DataObject $record) {
|
||||
if($this->multiple) {
|
||||
$fieldname = $this->name;
|
||||
$relation = ($fieldname && $record && $record->hasMethod($fieldname)) ? $record->$fieldname() : null;
|
||||
if($fieldname && $record && $relation && $relation instanceof RelationList) {
|
||||
$idList = (is_array($this->value)) ? array_values($this->value) : array();
|
||||
if(!$record->ID) $record->write(); // record needs to have an ID in order to set relationships
|
||||
$relation->setByIDList($idList);
|
||||
} elseif($fieldname && $record) {
|
||||
if($this->value) {
|
||||
$this->value = str_replace(',', '{comma}', $this->value);
|
||||
$record->$fieldname = implode(",", $this->value);
|
||||
} else {
|
||||
$record->$fieldname = null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
parent::saveInto($record);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a value into this CheckboxSetField
|
||||
*/
|
||||
function setValue($val, $obj = null) {
|
||||
// If we're not passed a value directly,
|
||||
// we can look for it in a relation method on the object passed as a second arg
|
||||
if(!$val && $obj && $obj instanceof DataObject && $obj->hasMethod($this->name)) {
|
||||
$funcName = $this->name;
|
||||
$val = array_values($obj->$funcName()->getIDList());
|
||||
}
|
||||
|
||||
if($val) {
|
||||
if(!$this->multiple && is_array($val)) {
|
||||
throw new InvalidArgumentException('No array values allowed with multiple=false');
|
||||
@ -168,7 +214,6 @@ class ListboxField extends DropdownField {
|
||||
|
||||
// Doesn't check against unknown values in order to allow for less rigid data handling.
|
||||
// They're silently ignored and overwritten the next time the field is saved.
|
||||
|
||||
parent::setValue($parts);
|
||||
} else {
|
||||
if(!in_array($val, array_keys($this->source))) {
|
||||
@ -187,4 +232,41 @@ class ListboxField extends DropdownField {
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark certain elements as disabled,
|
||||
* regardless of the {@link setDisabled()} settings.
|
||||
*
|
||||
* @param array $items Collection of array keys, as defined in the $source array
|
||||
*/
|
||||
function setDisabledItems($items) {
|
||||
$this->disabledItems = $items;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Array
|
||||
*/
|
||||
function getDisabledItems() {
|
||||
return $this->disabledItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default selections, regardless of the {@link setValue()} settings.
|
||||
* Note: Items marked as disabled through {@link setDisabledItems()} can still be
|
||||
* selected by default through this method.
|
||||
*
|
||||
* @param Array $items Collection of array keys, as defined in the $source array
|
||||
*/
|
||||
function setDefaultItems($items) {
|
||||
$this->defaultItems = $items;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Array
|
||||
*/
|
||||
function getDefaultItems() {
|
||||
return $this->defaultItems;
|
||||
}
|
||||
|
||||
}
|
@ -30,6 +30,8 @@
|
||||
* );
|
||||
* </code>
|
||||
*
|
||||
* @deprecated 3.0 Use GridField with GridFieldConfig_RelationEditor
|
||||
*
|
||||
* @package forms
|
||||
* @subpackage fields-relational
|
||||
*/
|
||||
@ -41,6 +43,8 @@ class ManyManyComplexTableField extends HasManyComplexTableField {
|
||||
|
||||
function __construct($controller, $name, $sourceClass, $fieldList = null, $detailFormFields = null, $sourceFilter = "", $sourceSort = "", $sourceJoin = "") {
|
||||
|
||||
Deprecation::notice('3.0', 'Use GridField with GridFieldConfig_RelationEditor');
|
||||
|
||||
parent::__construct($controller, $name, $sourceClass, $fieldList, $detailFormFields, $sourceFilter, $sourceSort, $sourceJoin);
|
||||
|
||||
$classes = array_reverse(ClassInfo::ancestry($this->controllerClass()));
|
||||
|
@ -6,9 +6,6 @@
|
||||
class MemberDatetimeOptionsetField extends OptionsetField {
|
||||
|
||||
function Field() {
|
||||
Requirements::javascript(THIRDPARTY_DIR . '/thirdparty/jquery/jquery.js');
|
||||
Requirements::javascript(SAPPHIRE_DIR . '/javascript/MemberDatetimeOptionsetField.js');
|
||||
|
||||
$options = '';
|
||||
$odd = 0;
|
||||
$source = $this->getSource();
|
||||
@ -45,8 +42,12 @@ class MemberDatetimeOptionsetField extends OptionsetField {
|
||||
_t('MemberDatetimeOptionsetField.Preview', 'Preview'),
|
||||
Zend_Date::now()->toString($value)
|
||||
) : '';
|
||||
$options .= "<a class=\"formattingHelpToggle\" href=\"#\">" . _t('MemberDatetimeOptionsetField.TOGGLEHELP', 'Toggle formatting help') . "</a>";
|
||||
$options .= "<div class=\"formattingHelpText\">";
|
||||
$options .= sprintf(
|
||||
'<a class="cms-help-toggle" href="#%s">%s</a>',
|
||||
$this->id() . '_Help',
|
||||
_t('MemberDatetimeOptionsetField.TOGGLEHELP', 'Toggle formatting help')
|
||||
);
|
||||
$options .= "<div id=\"" . $this->id() . "_Help\">";
|
||||
$options .= $this->getFormattingHelpText();
|
||||
$options .= "</div>";
|
||||
$options .= "</li>\n";
|
||||
|
@ -102,7 +102,7 @@ class SimpleImageField extends FileField {
|
||||
"type" => "file",
|
||||
"name" => $this->name,
|
||||
"id" => $this->id(),
|
||||
"tabindex" => $this->getTabIndex(),
|
||||
"tabindex" => $this->getAttribute('tabindex'),
|
||||
'disabled' => $this->disabled
|
||||
)
|
||||
);
|
||||
@ -111,7 +111,7 @@ class SimpleImageField extends FileField {
|
||||
"type" => "hidden",
|
||||
"name" => "MAX_FILE_SIZE",
|
||||
"value" => $this->getValidator()->getAllowedMaxFileSize(),
|
||||
"tabindex" => $this->getTabIndex()
|
||||
"tabindex" => $this->getAttribute('tabindex'),
|
||||
)
|
||||
);
|
||||
$html .= "</div>";
|
||||
|
@ -54,6 +54,10 @@ class TreeDropdownField extends FormField {
|
||||
* @ignore
|
||||
*/
|
||||
protected $sourceObject, $keyField, $labelField, $filterCallback, $searchCallback, $baseID = 0;
|
||||
/**
|
||||
* @var string default child method in Hierarcy->getChildrenAsUL
|
||||
*/
|
||||
protected $childrenMethod = 'AllChildrenIncludingDeleted';
|
||||
|
||||
/**
|
||||
* Used by field search to leave only the relevant entries
|
||||
@ -143,6 +147,16 @@ class TreeDropdownField extends FormField {
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $method The parameter to ChildrenMethod to use when calling Hierarchy->getChildrenAsUL in {@link Hierarchy}.
|
||||
* The method specified determined the structure of the returned list. Use "ChildFolders" in place of the default
|
||||
* to get a drop-down listing with only folders, i.e. not including the child elements in the currently selected folder.
|
||||
* See {@link Hierarchy} for a complete list of possible methods.
|
||||
*/
|
||||
public function setChildrenMethod($method) {
|
||||
$this->childrenMethod = $method;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
@ -246,9 +260,9 @@ class TreeDropdownField extends FormField {
|
||||
' . $child->markingClasses() . "\"><a rel=\"$child->ID\">" . $child->' . $this->labelField . ' . "</a>"';
|
||||
|
||||
if($isSubTree) {
|
||||
return substr(trim($obj->getChildrenAsUL('', $eval, null, true)), 4, -5);
|
||||
return substr(trim($obj->getChildrenAsUL('', $eval, null, true, $this->childrenMethod)), 4, -5);
|
||||
} else {
|
||||
return $obj->getChildrenAsUL('class="tree"', $eval, null, true);
|
||||
return $obj->getChildrenAsUL('class="tree"', $eval, null, true, $this->childrenMethod);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -290,6 +290,17 @@ class GridField extends FormField {
|
||||
* @return string
|
||||
*/
|
||||
public function FieldHolder() {
|
||||
Requirements::css(THIRDPARTY_DIR . '/jquery-ui-themes/smoothness/jquery-ui.css');
|
||||
Requirements::css(SAPPHIRE_DIR . '/css/GridField.css');
|
||||
|
||||
Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.js');
|
||||
Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/jquery-ui/jquery-ui.js');
|
||||
Requirements::javascript(THIRDPARTY_DIR . '/json-js/json2.js');
|
||||
Requirements::javascript(SAPPHIRE_DIR . '/javascript/i18n.js');
|
||||
Requirements::add_i18n_javascript(SAPPHIRE_DIR . '/javascript/lang');
|
||||
Requirements::javascript(THIRDPARTY_DIR . '/jquery-entwine/dist/jquery.entwine-dist.js');
|
||||
Requirements::javascript(SAPPHIRE_DIR . '/javascript/GridField.js');
|
||||
|
||||
// Get columns
|
||||
$columns = $this->getColumns();
|
||||
|
||||
@ -319,8 +330,9 @@ class GridField extends FormField {
|
||||
}
|
||||
}
|
||||
|
||||
$total = $list->count();
|
||||
|
||||
$total = $list->count();
|
||||
if($total > 0) {
|
||||
foreach($list as $idx => $record) {
|
||||
$rowContent = '';
|
||||
foreach($columns as $column) {
|
||||
@ -330,12 +342,10 @@ class GridField extends FormField {
|
||||
$colAttributes = $this->getColumnAttributes($record, $column);
|
||||
$rowContent .= $this->createTag('td', $colAttributes, $colContent);
|
||||
}
|
||||
|
||||
$classes = array('ss-gridfield-item');
|
||||
if ($idx == 0) $classes[] = 'first';
|
||||
if ($idx == $total-1) $classes[] = 'last';
|
||||
$classes[] = ($idx % 2) ? 'even' : 'odd';
|
||||
|
||||
$row = $this->createTag(
|
||||
'tr',
|
||||
array(
|
||||
@ -348,6 +358,14 @@ class GridField extends FormField {
|
||||
);
|
||||
$content['body'][] = $row;
|
||||
}
|
||||
} else { //display a message when the grid field is empty
|
||||
$row = $this->createTag(
|
||||
'tr',
|
||||
array("class" => 'ss-gridfield-item ss-gridfield-no-items'),
|
||||
$this->createTag('td', array('colspan' => count($columns)), _t('GridField.NoItemsFound', 'No items found'))
|
||||
);
|
||||
$content['body'][] = $row;
|
||||
}
|
||||
|
||||
// Turn into the relevant parts of a table
|
||||
$head = $content['header'] ? $this->createTag('thead', array(), implode("\n", $content['header'])) : '';
|
||||
@ -651,13 +669,14 @@ class GridField extends FormField {
|
||||
|
||||
|
||||
/**
|
||||
* This class is the base class when you want to have an action that alters the state of the gridfield
|
||||
* This class is the base class when you want to have an action that alters the state of the gridfield,
|
||||
* rendered as a button element.
|
||||
*
|
||||
* @package sapphire
|
||||
* @subpackage forms
|
||||
*
|
||||
*/
|
||||
class GridField_Action extends FormAction {
|
||||
class GridField_FormAction extends FormAction {
|
||||
|
||||
/**
|
||||
*
|
||||
@ -665,12 +684,6 @@ class GridField_Action extends FormAction {
|
||||
*/
|
||||
protected $gridField;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $buttonLabel;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var array
|
||||
@ -684,8 +697,11 @@ class GridField_Action extends FormAction {
|
||||
//protected $stateFields = array();
|
||||
|
||||
protected $actionName;
|
||||
|
||||
protected $args = array();
|
||||
|
||||
public $useButtonTag = true;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param GridField $gridField
|
||||
@ -694,12 +710,11 @@ class GridField_Action extends FormAction {
|
||||
* @param type $actionName
|
||||
* @param type $args
|
||||
*/
|
||||
public function __construct(GridField $gridField, $name, $label, $actionName, $args) {
|
||||
public function __construct(GridField $gridField, $name, $title, $actionName, $args) {
|
||||
$this->gridField = $gridField;
|
||||
$this->buttonLabel = $label;
|
||||
$this->actionName = $actionName;
|
||||
$this->args = $args;
|
||||
parent::__construct($name);
|
||||
parent::__construct($name, $title);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -720,45 +735,26 @@ class GridField_Action extends FormAction {
|
||||
return '%'.dechex(ord($match[0]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Default method used by Templates to render the form
|
||||
*
|
||||
* @return string HTML tag
|
||||
*/
|
||||
public function Field() {
|
||||
Requirements::css(SAPPHIRE_DIR . '/css/GridField.css');
|
||||
|
||||
Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.js');
|
||||
Requirements::javascript(THIRDPARTY_DIR . '/json-js/json2.js');
|
||||
Requirements::javascript(SAPPHIRE_DIR . '/javascript/i18n.js');
|
||||
Requirements::javascript(THIRDPARTY_DIR . '/jquery-entwine/dist/jquery.entwine-dist.js');
|
||||
Requirements::javascript(SAPPHIRE_DIR . '/javascript/GridField.js');
|
||||
|
||||
public function getAttributes() {
|
||||
// Store state in session, and pass ID to client side
|
||||
$state = array(
|
||||
'grid' => $this->getNameFromParent(),
|
||||
'actionName' => $this->actionName,
|
||||
'args' => $this->args,
|
||||
);
|
||||
|
||||
$id = preg_replace('/[^\w]+/', '_', uniqid('', true));
|
||||
Session::set($id, $state);
|
||||
|
||||
$actionData['StateID'] = $id;
|
||||
|
||||
// And generate field
|
||||
$data = new ArrayData(array(
|
||||
'Class' => ($this->extraClass() ? $this->extraClass() : '') . ($this->isReadonly() ? ' disabled' : ''),
|
||||
'ID' => $this->id(),
|
||||
return array_merge(
|
||||
parent::getAttributes(),
|
||||
array(
|
||||
// Note: This field needs to be less than 65 chars, otherwise Suhosin security patch
|
||||
// will strip it from the requests
|
||||
'Name' => 'action_gridFieldAlterAction'. '?' . http_build_query($actionData),
|
||||
'Disabled' => $this->isReadonly(),
|
||||
'Label' => $this->buttonLabel,
|
||||
'DataURL' => $this->gridField->Link(),
|
||||
));
|
||||
|
||||
return $data->renderWith('GridField_Action');
|
||||
'name' => 'action_gridFieldAlterAction'. '?' . http_build_query($actionData),
|
||||
'data-url' => $this->gridField->Link(),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,196 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Provides the entry point to editing a single record presented by the grid.
|
||||
* Doesn't show an edit view on its own or modifies the record, but rather relies on routing conventions
|
||||
* established in {@link getColumnContent()}. The default routing applies to
|
||||
* the {@link GridFieldPopupForms} component, which has to be added separately
|
||||
* to the grid field configuration.
|
||||
*/
|
||||
class GridFieldAction_Edit implements GridField_ColumnProvider {
|
||||
|
||||
/**
|
||||
* Add a column 'Delete'
|
||||
*
|
||||
* @param type $gridField
|
||||
* @param array $columns
|
||||
*/
|
||||
public function augmentColumns($gridField, &$columns) {
|
||||
if(!in_array('Actions', $columns))
|
||||
$columns[] = 'Actions';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return any special attributes that will be used for FormField::createTag()
|
||||
*
|
||||
* @param GridField $gridField
|
||||
* @param DataObject $record
|
||||
* @param string $columnName
|
||||
* @return array
|
||||
*/
|
||||
public function getColumnAttributes($gridField, $record, $columnName) {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the title
|
||||
*
|
||||
* @param GridField $gridField
|
||||
* @param string $columnName
|
||||
* @return array
|
||||
*/
|
||||
public function getColumnMetadata($gridField, $columnName) {
|
||||
if($columnName == 'Actions') {
|
||||
return array('title' => '');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Which columns are handled by this component
|
||||
*
|
||||
* @param type $gridField
|
||||
* @return type
|
||||
*/
|
||||
public function getColumnsHandled($gridField) {
|
||||
return array('Actions');
|
||||
}
|
||||
|
||||
/**
|
||||
* Which GridField actions are this component handling
|
||||
*
|
||||
* @param GridField $gridField
|
||||
* @return array
|
||||
*/
|
||||
public function getActions($gridField) {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param GridField $gridField
|
||||
* @param DataObject $record
|
||||
* @param string $columnName
|
||||
* @return string - the HTML for the column
|
||||
*/
|
||||
public function getColumnContent($gridField, $record, $columnName) {
|
||||
$data = new ArrayData(array(
|
||||
'Link' => Controller::join_links($gridField->Link('item'), $record->ID, 'edit')
|
||||
));
|
||||
|
||||
return $data->renderWith('GridFieldAction_Edit');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the actions and apply any changes to the GridField
|
||||
*
|
||||
* @param GridField $gridField
|
||||
* @param string $actionName
|
||||
* @param mixed $arguments
|
||||
* @param array $data - form data
|
||||
* @return void
|
||||
*/
|
||||
public function handleAction(GridField $gridField, $actionName, $arguments, $data) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This class is an GridField Component that add Delete action for Objects in the GridField.
|
||||
* See {@link GridFieldRelationDelete} for detaching an item from the current relationship instead.
|
||||
*/
|
||||
class GridFieldAction_Delete implements GridField_ColumnProvider, GridField_ActionProvider {
|
||||
|
||||
/**
|
||||
* Add a column 'Delete'
|
||||
*
|
||||
* @param type $gridField
|
||||
* @param array $columns
|
||||
*/
|
||||
public function augmentColumns($gridField, &$columns) {
|
||||
if(!in_array('Actions', $columns))
|
||||
$columns[] = 'Actions';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return any special attributes that will be used for FormField::createTag()
|
||||
*
|
||||
* @param GridField $gridField
|
||||
* @param DataObject $record
|
||||
* @param string $columnName
|
||||
* @return array
|
||||
*/
|
||||
public function getColumnAttributes($gridField, $record, $columnName) {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the title
|
||||
*
|
||||
* @param GridField $gridField
|
||||
* @param string $columnName
|
||||
* @return array
|
||||
*/
|
||||
public function getColumnMetadata($gridField, $columnName) {
|
||||
if($columnName == 'Actions') {
|
||||
return array('title' => '');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Which columns are handled by this component
|
||||
*
|
||||
* @param type $gridField
|
||||
* @return type
|
||||
*/
|
||||
public function getColumnsHandled($gridField) {
|
||||
return array('Actions');
|
||||
}
|
||||
|
||||
/**
|
||||
* Which GridField actions are this component handling
|
||||
*
|
||||
* @param GridField $gridField
|
||||
* @return array
|
||||
*/
|
||||
public function getActions($gridField) {
|
||||
return array('deleterecord');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param GridField $gridField
|
||||
* @param DataObject $record
|
||||
* @param string $columnName
|
||||
* @return string - the HTML for the column
|
||||
*/
|
||||
public function getColumnContent($gridField, $record, $columnName) {
|
||||
$field = new GridField_Action(
|
||||
$gridField,
|
||||
'DeleteRecord'.$record->ID,
|
||||
_t('GridAction.Delete', "delete"),
|
||||
"deleterecord",
|
||||
array('RecordID' => $record->ID)
|
||||
);
|
||||
$field->addExtraClass('gridfield-button-delete');
|
||||
$output = $field->Field();
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the actions and apply any changes to the GridField
|
||||
*
|
||||
* @param GridField $gridField
|
||||
* @param string $actionName
|
||||
* @param mixed $arguments
|
||||
* @param array $data - form data
|
||||
* @return void
|
||||
*/
|
||||
public function handleAction(GridField $gridField, $actionName, $arguments, $data) {
|
||||
if($actionName == 'deleterecord') {
|
||||
$id = $arguments['RecordID'];
|
||||
// Always deletes a record. Use GridFieldRelationDelete to detach it from the current relationship.
|
||||
$item = $gridField->getList()->byID($id);
|
||||
if(!$item) return;
|
||||
$item->delete();
|
||||
}
|
||||
}
|
||||
}
|
@ -4,52 +4,132 @@
|
||||
* Base interface for all components that can be added to GridField.
|
||||
*/
|
||||
interface GridFieldComponent {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* A GridField manipulator that provides HTML for the header/footer rows, or for before/after the template
|
||||
*/
|
||||
interface GridField_HTMLProvider extends GridFieldComponent {
|
||||
|
||||
/**
|
||||
* Returns a map with 4 keys 'header', 'footer', 'before', 'after'. Each of these can contain an
|
||||
* HTML fragment and each of these are optional.
|
||||
* @return Array
|
||||
*/
|
||||
function getHTMLFragments($gridField);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new column to the table display body, or modify existing columns.
|
||||
* Used once per record/row.
|
||||
*/
|
||||
interface GridField_ColumnProvider extends GridFieldComponent {
|
||||
|
||||
/**
|
||||
* Modify the list of columns displayed in the table.
|
||||
* See {@link GridField->getDisplayFields()} and {@link GridFieldDefaultColumns}.
|
||||
*
|
||||
* @param GridField
|
||||
* @param Array List reference of all column names.
|
||||
*/
|
||||
function augmentColumns($gridField, &$columns);
|
||||
|
||||
/**
|
||||
* Names of all columns which are affected by this component.
|
||||
*
|
||||
* @param GridField
|
||||
* @return Array
|
||||
*/
|
||||
function getColumnsHandled($gridField);
|
||||
|
||||
/**
|
||||
* HTML for the column, content of the <td> element.
|
||||
*
|
||||
* @param GridField
|
||||
* @param DataObject Record displayed in this row
|
||||
* @param String
|
||||
* @return String HTML for the column. Return NULL to skip.
|
||||
*/
|
||||
function getColumnContent($gridField, $record, $columnName);
|
||||
|
||||
/**
|
||||
* Attributes for the element containing the content returned by {@link getColumnContent()}.
|
||||
*
|
||||
* @param GridField
|
||||
* @param DataObject Record displayed in this row
|
||||
* @param String
|
||||
* @return Array
|
||||
*/
|
||||
function getColumnAttributes($gridField, $record, $columnName);
|
||||
|
||||
/**
|
||||
* Additional metadata about the column which can be used by other components,
|
||||
* e.g. to set a title for a search column header.
|
||||
*
|
||||
* @param GridField
|
||||
* @param String
|
||||
* @return Array Map of arbitrary metadata identifiers to their values.
|
||||
*/
|
||||
function getColumnMetadata($gridField, $columnName);
|
||||
}
|
||||
|
||||
/**
|
||||
* An action is defined by two things: an action name, and zero or more named arguments.
|
||||
* There is no built-in notion of a record-specific or column-specific action,
|
||||
* but you may choose to define an argument such as ColumnName or RecordID in order to implement these.
|
||||
* Does not provide interface elements to call those actions, see {@link GridField_FormAction}.
|
||||
*/
|
||||
interface GridField_ActionProvider extends GridFieldComponent {
|
||||
/**
|
||||
* Return a list of the actions handled by this action provider
|
||||
* Return a list of the actions handled by this action provider.
|
||||
* Used to identify the action later on through the $actionName parameter in {@link handleAction}.
|
||||
* There is no namespacing on these actions, so you need to ensure that they don't conflict with other components.
|
||||
*
|
||||
* @param GridField
|
||||
* @return Array with action identifier strings.
|
||||
*/
|
||||
function getActions($gridField);
|
||||
|
||||
/**
|
||||
* Handle an action on the given gridField.
|
||||
* Handle an action on the given grid field.
|
||||
* Calls ALL components for every action handled, so the component
|
||||
* needs to ensure it only accepts actions it is actually supposed to handle.
|
||||
*
|
||||
* @param GridField
|
||||
* @param String Action identifier, see {@link getActions()}.
|
||||
* @param Array Arguments relevant for this
|
||||
* @param Array All form data
|
||||
*/
|
||||
function handleAction(GridField $gridField, $actionName, $arguments, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Can modify the data list.
|
||||
* For example, a paginating component can apply a limit, or a sorting component can apply a sort.
|
||||
* Generally, the data manipulator will make use of to `GridState` variables to decide
|
||||
* how to modify the data list (see {@link GridState}).
|
||||
*/
|
||||
interface GridField_DataManipulator extends GridFieldComponent {
|
||||
/**
|
||||
* Manipulate the datalist as needed by this grid modifier.
|
||||
* Return the new DataList.
|
||||
*
|
||||
* @param GridField
|
||||
* @param SS_List
|
||||
* @return DataList
|
||||
*/
|
||||
function getManipulatedData(GridField $gridField, SS_List $dataList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sometimes an action isn't enough: you need to provide additional support URLs for the grid.
|
||||
* These URLs may return user-visible content, for example a pop-up form for editing a record's details,
|
||||
* or they may be support URLs for front-end functionality.
|
||||
* For example a URL that will return JSON-formatted data for a javascript grid control.
|
||||
*/
|
||||
interface GridField_URLHandler extends GridFieldComponent {
|
||||
/**
|
||||
* Return URLs to be handled by this grid field, in an array the same form as $url_handlers.
|
||||
*
|
||||
* Handler methods will be called on the component, rather than the grid field.
|
||||
*
|
||||
* The handlers will be passed two arguments, $gridField and $request
|
||||
*/
|
||||
function getURLHandlers($gridField);
|
||||
}
|
@ -1,7 +1,17 @@
|
||||
<?php
|
||||
/**
|
||||
* Description of GridFieldConfig
|
||||
* Encapsulates a collection of components following the {@link GridFieldComponent} interface.
|
||||
* While the {@link GridField} itself has some configuration in the form of setters,
|
||||
* most of the details are dealt with through components.
|
||||
*
|
||||
* For example, you would add a {@link GridFieldPaginator} component to enable
|
||||
* pagination on the listed records, and configure it through {@link GridFieldPaginator->setItemsPerPage()}.
|
||||
*
|
||||
* In order to reduce the amount of custom code required, the framework provides
|
||||
* some default configurations for common use cases:
|
||||
* - {@link GridFieldConfig_Base} (added by default to GridField)
|
||||
* - {@link GridFieldConfig_RecordEditor}
|
||||
* - {@link GridFieldConfig_RelationEditor}
|
||||
*/
|
||||
class GridFieldConfig {
|
||||
|
||||
@ -43,6 +53,27 @@ class GridFieldConfig {
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param GridFieldComponent $component
|
||||
* @return GridFieldConfig $this
|
||||
*/
|
||||
public function removeComponent(GridFieldComponent $component) {
|
||||
$this->getComponents()->remove($component);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String Class name or interface
|
||||
* @return GridFieldConfig $this
|
||||
*/
|
||||
public function removeComponentsByType($type) {
|
||||
$components = $this->getComponentsByType($type);
|
||||
foreach($components as $component) {
|
||||
$this->removeComponent($component);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ArrayList Of GridFieldComponent
|
||||
*/
|
||||
@ -80,6 +111,10 @@ class GridFieldConfig {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple readonly, paginated view of records,
|
||||
* with sortable and searchable headers.
|
||||
*/
|
||||
class GridFieldConfig_Base extends GridFieldConfig {
|
||||
|
||||
/**
|
||||
@ -87,7 +122,7 @@ class GridFieldConfig_Base extends GridFieldConfig {
|
||||
* @param int $itemsPerPage - How many items per page should show up per page
|
||||
* @return GridFieldConfig_Base
|
||||
*/
|
||||
public static function create($itemsPerPage=15){
|
||||
public static function create($itemsPerPage=null){
|
||||
return new GridFieldConfig_Base($itemsPerPage);
|
||||
}
|
||||
|
||||
@ -95,7 +130,7 @@ class GridFieldConfig_Base extends GridFieldConfig {
|
||||
*
|
||||
* @param int $itemsPerPage - How many items per page should show up
|
||||
*/
|
||||
public function __construct($itemsPerPage=15) {
|
||||
public function __construct($itemsPerPage=null) {
|
||||
$this->addComponent(new GridFieldTitle());
|
||||
$this->addComponent(new GridFieldSortableHeader());
|
||||
$this->addComponent(new GridFieldFilter());
|
||||
@ -105,40 +140,72 @@ class GridFieldConfig_Base extends GridFieldConfig {
|
||||
}
|
||||
|
||||
/**
|
||||
* This GridFieldConfig bundles a common set of componentes used for displaying
|
||||
* a gridfield with:
|
||||
*
|
||||
* - Relation adding
|
||||
* - Sortable header
|
||||
* - Default columns
|
||||
* - Edit links on every item
|
||||
* - Action for removing relationship
|
||||
* - Paginator
|
||||
*
|
||||
*/
|
||||
class GridFieldConfig_ManyManyEditor extends GridFieldConfig {
|
||||
class GridFieldConfig_RecordEditor extends GridFieldConfig {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $fieldToSearch - Which field on the object should be searched for
|
||||
* @param int $itemsPerPage - How many items per page should show up
|
||||
* @return GridFieldConfig_ManyManyEditor
|
||||
* @return GridFieldConfig_RecordEditor
|
||||
*/
|
||||
public static function create($fieldToSearch, $itemsPerPage=15){
|
||||
return new GridFieldConfig_ManyManyEditor($fieldToSearch, $itemsPerPage=15);
|
||||
public static function create($itemsPerPage=null){
|
||||
return new GridFieldConfig_RecordEditor($itemsPerPage);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param string $fieldToSearch - Which field on the object should be searched for
|
||||
* @param int $itemsPerPage - How many items per page should show up
|
||||
*/
|
||||
public function __construct($fieldToSearch, $itemsPerPage=15) {
|
||||
$this->addComponent(new GridFieldRelationAdd($fieldToSearch));
|
||||
public function __construct($itemsPerPage=null) {
|
||||
$this->addComponent(new GridFieldTitle());
|
||||
$this->addComponent(new GridFieldSortableHeader());
|
||||
$this->addComponent(new GridFieldFilter());
|
||||
$this->addComponent(new GridFieldDefaultColumns());
|
||||
$this->addComponent(new GridFieldAction_Edit());
|
||||
$this->addComponent(new GridFieldEditAction());
|
||||
$this->addComponent(new GridFieldDeleteAction());
|
||||
$this->addComponent(new GridFieldPaginator($itemsPerPage));
|
||||
$this->addComponent(new GridFieldPopupForms());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Similar to {@link GridFieldConfig_RecordEditor}, but adds features
|
||||
* to work on has-many or many-many relationships.
|
||||
* Allows to search for existing records to add to the relationship,
|
||||
* detach listed records from the relationship (rather than removing them from the database),
|
||||
* and automatically add newly created records to it.
|
||||
*
|
||||
* To further configure the field, use {@link getComponentByType()},
|
||||
* for example to change the field to search.
|
||||
* <code>
|
||||
* GridFieldConfig_RelationEditor::create()
|
||||
* ->getComponentByType('GridFieldRelationAdd')->setSearchFields('MyField');
|
||||
* </code>
|
||||
*/
|
||||
class GridFieldConfig_RelationEditor extends GridFieldConfig {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param int $itemsPerPage - How many items per page should show up
|
||||
* @return GridFieldConfig_RelationEditor
|
||||
*/
|
||||
public static function create($itemsPerPage=null){
|
||||
return new GridFieldConfig_RelationEditor($itemsPerPage);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param int $itemsPerPage - How many items per page should show up
|
||||
*/
|
||||
public function __construct($itemsPerPage=null) {
|
||||
$this->addComponent(new GridFieldTitle());
|
||||
$this->addComponent(new GridFieldRelationAdd());
|
||||
$this->addComponent(new GridFieldSortableHeader());
|
||||
$this->addComponent(new GridFieldFilter());
|
||||
$this->addComponent(new GridFieldDefaultColumns());
|
||||
$this->addComponent(new GridFieldEditAction());
|
||||
$this->addComponent(new GridFieldRelationDelete());
|
||||
$this->addComponent(new GridFieldPaginator($itemsPerPage));
|
||||
$this->addComponent(new GridFieldPopupForms());
|
||||
|
103
forms/gridfield/GridFieldDeleteAction.php
Normal file
@ -0,0 +1,103 @@
|
||||
<?php
|
||||
/**
|
||||
* This class is an GridField Component that add Delete action for Objects in the GridField.
|
||||
* See {@link GridFieldRelationDelete} for detaching an item from the current relationship instead.
|
||||
*/
|
||||
class GridFieldDeleteAction implements GridField_ColumnProvider, GridField_ActionProvider {
|
||||
|
||||
/**
|
||||
* Add a column 'Delete'
|
||||
*
|
||||
* @param type $gridField
|
||||
* @param array $columns
|
||||
*/
|
||||
public function augmentColumns($gridField, &$columns) {
|
||||
if(!in_array('Actions', $columns))
|
||||
$columns[] = 'Actions';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return any special attributes that will be used for FormField::createTag()
|
||||
*
|
||||
* @param GridField $gridField
|
||||
* @param DataObject $record
|
||||
* @param string $columnName
|
||||
* @return array
|
||||
*/
|
||||
public function getColumnAttributes($gridField, $record, $columnName) {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the title
|
||||
*
|
||||
* @param GridField $gridField
|
||||
* @param string $columnName
|
||||
* @return array
|
||||
*/
|
||||
public function getColumnMetadata($gridField, $columnName) {
|
||||
if($columnName == 'Actions') {
|
||||
return array('title' => '');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Which columns are handled by this component
|
||||
*
|
||||
* @param type $gridField
|
||||
* @return type
|
||||
*/
|
||||
public function getColumnsHandled($gridField) {
|
||||
return array('Actions');
|
||||
}
|
||||
|
||||
/**
|
||||
* Which GridField actions are this component handling
|
||||
*
|
||||
* @param GridField $gridField
|
||||
* @return array
|
||||
*/
|
||||
public function getActions($gridField) {
|
||||
return array('deleterecord');
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param GridField $gridField
|
||||
* @param DataObject $record
|
||||
* @param string $columnName
|
||||
* @return string - the HTML for the column
|
||||
*/
|
||||
public function getColumnContent($gridField, $record, $columnName) {
|
||||
$field = Object::create('GridField_FormAction',
|
||||
$gridField,
|
||||
'DeleteRecord'.$record->ID,
|
||||
false,
|
||||
"deleterecord",
|
||||
array('RecordID' => $record->ID)
|
||||
)
|
||||
->addExtraClass('gridfield-button-delete')
|
||||
->setAttribute('title', _t('GridAction.Delete', "delete"))
|
||||
->setAttribute('data-icon', 'decline');
|
||||
return $field->Field();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the actions and apply any changes to the GridField
|
||||
*
|
||||
* @param GridField $gridField
|
||||
* @param string $actionName
|
||||
* @param mixed $arguments
|
||||
* @param array $data - form data
|
||||
* @return void
|
||||
*/
|
||||
public function handleAction(GridField $gridField, $actionName, $arguments, $data) {
|
||||
if($actionName == 'deleterecord') {
|
||||
$id = $arguments['RecordID'];
|
||||
// Always deletes a record. Use GridFieldRelationDelete to detach it from the current relationship.
|
||||
$item = $gridField->getList()->byID($id);
|
||||
if(!$item) return;
|
||||
$item->delete();
|
||||
}
|
||||
}
|
||||
}
|
94
forms/gridfield/GridFieldEditAction.php
Normal file
@ -0,0 +1,94 @@
|
||||
<?php
|
||||
/**
|
||||
* Provides the entry point to editing a single record presented by the grid.
|
||||
* Doesn't show an edit view on its own or modifies the record, but rather relies on routing conventions
|
||||
* established in {@link getColumnContent()}. The default routing applies to
|
||||
* the {@link GridFieldPopupForms} component, which has to be added separately
|
||||
* to the grid field configuration.
|
||||
*/
|
||||
class GridFieldEditAction implements GridField_ColumnProvider {
|
||||
|
||||
/**
|
||||
* Add a column 'Delete'
|
||||
*
|
||||
* @param type $gridField
|
||||
* @param array $columns
|
||||
*/
|
||||
public function augmentColumns($gridField, &$columns) {
|
||||
if(!in_array('Actions', $columns))
|
||||
$columns[] = 'Actions';
|
||||
}
|
||||
|
||||
/**
|
||||
* Return any special attributes that will be used for FormField::createTag()
|
||||
*
|
||||
* @param GridField $gridField
|
||||
* @param DataObject $record
|
||||
* @param string $columnName
|
||||
* @return array
|
||||
*/
|
||||
public function getColumnAttributes($gridField, $record, $columnName) {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the title
|
||||
*
|
||||
* @param GridField $gridField
|
||||
* @param string $columnName
|
||||
* @return array
|
||||
*/
|
||||
public function getColumnMetadata($gridField, $columnName) {
|
||||
if($columnName == 'Actions') {
|
||||
return array('title' => '');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Which columns are handled by this component
|
||||
*
|
||||
* @param type $gridField
|
||||
* @return type
|
||||
*/
|
||||
public function getColumnsHandled($gridField) {
|
||||
return array('Actions');
|
||||
}
|
||||
|
||||
/**
|
||||
* Which GridField actions are this component handling
|
||||
*
|
||||
* @param GridField $gridField
|
||||
* @return array
|
||||
*/
|
||||
public function getActions($gridField) {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param GridField $gridField
|
||||
* @param DataObject $record
|
||||
* @param string $columnName
|
||||
* @return string - the HTML for the column
|
||||
*/
|
||||
public function getColumnContent($gridField, $record, $columnName) {
|
||||
$data = new ArrayData(array(
|
||||
'Link' => Controller::join_links($gridField->Link('item'), $record->ID, 'edit')
|
||||
));
|
||||
|
||||
return $data->renderWith('GridFieldEditAction');
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle the actions and apply any changes to the GridField
|
||||
*
|
||||
* @param GridField $gridField
|
||||
* @param string $actionName
|
||||
* @param mixed $arguments
|
||||
* @param array $data - form data
|
||||
* @return void
|
||||
*/
|
||||
public function handleAction(GridField $gridField, $actionName, $arguments, $data) {
|
||||
|
||||
}
|
||||
}
|
@ -39,13 +39,15 @@ class GridFieldExporter implements GridField_HTMLProvider, GridField_ActionProvi
|
||||
* Place the export button in a <p> tag below the field
|
||||
*/
|
||||
public function getHTMLFragments($gridField) {
|
||||
$button = new GridField_Action(
|
||||
$button = new GridField_FormAction(
|
||||
$gridField,
|
||||
'export',
|
||||
_t('TableListField.CSVEXPORT', 'Export to CSV'),
|
||||
'export',
|
||||
null
|
||||
);
|
||||
$button->setAttribute('data-icon', 'download-csv');
|
||||
$button->addExtraClass('no-ajax');
|
||||
return array(
|
||||
'after' => '<p>' . $button->Field() . '</p>',
|
||||
);
|
||||
@ -129,6 +131,7 @@ class GridFieldExporter implements GridField_HTMLProvider, GridField_ActionProvi
|
||||
*/
|
||||
function setExportColumns($cols) {
|
||||
$this->exportColumns = $cols;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -143,6 +146,7 @@ class GridFieldExporter implements GridField_HTMLProvider, GridField_ActionProvi
|
||||
*/
|
||||
function setCsvSeparator($separator) {
|
||||
$this->csvSeparator = $separator;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -157,6 +161,7 @@ class GridFieldExporter implements GridField_HTMLProvider, GridField_ActionProvi
|
||||
*/
|
||||
function setCsvHasHeader($bool) {
|
||||
$this->csvHasHeader = $bool;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
|
@ -75,12 +75,14 @@ class GridFieldFilter implements GridField_HTMLProvider, GridField_DataManipulat
|
||||
|
||||
$field = new FieldGroup(
|
||||
$field,
|
||||
$filterbutton = new GridField_Action($gridField, 'filter', _t('GridField.Filter', "Filter"), 'filter', null),
|
||||
$resetbutton = new GridField_Action($gridField, 'reset', _t('GridField.ResetFilter', "Reset"), 'reset', null)
|
||||
Object::create('GridField_FormAction', $gridField, 'filter', false, 'filter', null)
|
||||
->addExtraClass('ss-gridfield-button-filter')
|
||||
->setAttribute('title', _t('GridField.Filter', "Filter"))
|
||||
,
|
||||
Object::create('GridField_FormAction', $gridField, 'reset', false, 'reset', null)
|
||||
->addExtraClass('ss-gridfield-button-reset')
|
||||
->setAttribute('title', _t('GridField.ResetFilter', "Reset"))
|
||||
);
|
||||
|
||||
$filterbutton->addExtraClass('ss-gridfield-button-filter');
|
||||
$resetbutton->addExtraClass('ss-gridfield-button-reset');
|
||||
} else {
|
||||
$field = new LiteralField('', '');
|
||||
}
|
||||
|
@ -7,13 +7,6 @@
|
||||
* @subpackage fields-relational
|
||||
*/
|
||||
class GridFieldPaginator implements GridField_HTMLProvider, GridField_DataManipulator, GridField_ActionProvider {
|
||||
|
||||
/**
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $currentPage = 1;
|
||||
|
||||
/**
|
||||
*
|
||||
* @var int
|
||||
@ -31,8 +24,8 @@ class GridFieldPaginator implements GridField_HTMLProvider, GridField_DataManipu
|
||||
*
|
||||
* @param int $itemsPerPage - How many items should be displayed per page
|
||||
*/
|
||||
public function __construct($itemsPerPage=15) {
|
||||
$this->itemsPerPage = $itemsPerPage;
|
||||
public function __construct($itemsPerPage=null) {
|
||||
if($itemsPerPage) $this->itemsPerPage = $itemsPerPage;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -57,7 +50,7 @@ class GridFieldPaginator implements GridField_HTMLProvider, GridField_DataManipu
|
||||
return;
|
||||
}
|
||||
$state = $gridField->State->GridFieldPaginator;
|
||||
$this->currentPage = $state->currentPage = (int)$arguments;
|
||||
$state->currentPage = (int)$arguments;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -67,13 +60,17 @@ class GridFieldPaginator implements GridField_HTMLProvider, GridField_DataManipu
|
||||
* @return SS_List
|
||||
*/
|
||||
public function getManipulatedData(GridField $gridField, SS_List $dataList) {
|
||||
$state = $gridField->State->GridFieldPaginator;
|
||||
if(!is_int($state->currentPage))
|
||||
$state->currentPage = 1;
|
||||
|
||||
if(!$this->getListPaginatable($dataList)) {
|
||||
return $dataList;
|
||||
}
|
||||
if(!$this->currentPage) {
|
||||
if(!$state->currentPage) {
|
||||
return $dataList->getRange(0, (int)$this->itemsPerPage);
|
||||
}
|
||||
$startRow = $this->itemsPerPage*($this->currentPage-1);
|
||||
$startRow = $this->itemsPerPage * ($state->currentPage - 1);
|
||||
return $dataList->getRange((int)$startRow, (int)$this->itemsPerPage);
|
||||
}
|
||||
|
||||
@ -83,30 +80,85 @@ class GridFieldPaginator implements GridField_HTMLProvider, GridField_DataManipu
|
||||
* @return array
|
||||
*/
|
||||
public function getHTMLFragments($gridField) {
|
||||
$forTemplate = new ArrayData(array());
|
||||
$forTemplate->Fields = new ArrayList;
|
||||
$state = $gridField->State->GridFieldPaginator;
|
||||
if(!is_int($state->currentPage))
|
||||
$state->currentPage = 1;
|
||||
|
||||
// Figure out which page and record range we're on
|
||||
$countList = clone $gridField->List;
|
||||
$totalRows = $countList->limit(null)->count();
|
||||
$totalPages = ceil($totalRows/$this->itemsPerPage);
|
||||
for($idx=1; $idx<=$totalPages; $idx++) {
|
||||
if($idx == $this->currentPage) {
|
||||
$field = new LiteralField('pagination_'.$idx, $idx);
|
||||
} else {
|
||||
$field = new GridField_Action($gridField, 'pagination_'.$idx, $idx, 'paginate', $idx);
|
||||
$field->addExtraClass('ss-gridfield-button');
|
||||
}
|
||||
if(!$totalRows) return array();
|
||||
|
||||
$forTemplate->Fields->push($field);
|
||||
}
|
||||
if(!$forTemplate->Fields->Count()) {
|
||||
return array();
|
||||
}
|
||||
$totalPages = ceil($totalRows/$this->itemsPerPage);
|
||||
if($totalPages == 0)
|
||||
$totalPages = 1;
|
||||
$firstShownRecord = ($state->currentPage - 1) * $this->itemsPerPage + 1;
|
||||
if($firstShownRecord > $totalRows)
|
||||
$firstShownRecord = $totalRows;
|
||||
$lastShownRecord = $state->currentPage * $this->itemsPerPage;
|
||||
if($lastShownRecord > $totalRows)
|
||||
$lastShownRecord = $totalRows;
|
||||
|
||||
|
||||
// First page button
|
||||
$firstPage = new GridField_FormAction($gridField, 'pagination_first', 'First', 'paginate', 1);
|
||||
$firstPage->addExtraClass('ss-gridfield-firstpage');
|
||||
if($state->currentPage == 1)
|
||||
$firstPage = $firstPage->performDisabledTransformation();
|
||||
|
||||
// Previous page button
|
||||
$previousPageNum = $state->currentPage <= 1 ? 1 : $state->currentPage - 1;
|
||||
$previousPage = new GridField_FormAction($gridField, 'pagination_prev', 'Previous', 'paginate', $previousPageNum);
|
||||
$previousPage->addExtraClass('ss-gridfield-previouspage');
|
||||
if($state->currentPage == 1)
|
||||
$previousPage = $previousPage->performDisabledTransformation();
|
||||
|
||||
// Next page button
|
||||
$nextPageNum = $state->currentPage >= $totalPages ? $totalPages : $state->currentPage + 1;
|
||||
$nextPage = new GridField_FormAction($gridField, 'pagination_next', 'Next', 'paginate', $nextPageNum);
|
||||
$nextPage->addExtraClass('ss-gridfield-nextpage');
|
||||
if($state->currentPage == $totalPages)
|
||||
$nextPage = $nextPage->performDisabledTransformation();
|
||||
|
||||
// Last page button
|
||||
$lastPage = new GridField_FormAction($gridField, 'pagination_last', 'Last', 'paginate', $totalPages);
|
||||
$lastPage->addExtraClass('ss-gridfield-lastpage');
|
||||
if($state->currentPage == $totalPages)
|
||||
$lastPage = $lastPage->performDisabledTransformation();
|
||||
|
||||
|
||||
// Render in template
|
||||
$forTemplate = new ArrayData(array(
|
||||
'FirstPage' => $firstPage,
|
||||
'PreviousPage' => $previousPage,
|
||||
'CurrentPageNum' => $state->currentPage,
|
||||
'NumPages' => $totalPages,
|
||||
'NextPage' => $nextPage,
|
||||
'LastPage' => $lastPage,
|
||||
'FirstShownRecord' => $firstShownRecord,
|
||||
'LastShownRecord' => $lastShownRecord,
|
||||
'NumRecords' => $totalRows
|
||||
));
|
||||
return array(
|
||||
'footer' => $forTemplate->renderWith('GridFieldPaginator_Row', array('Colspan'=>count($gridField->getColumns()))),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Int
|
||||
*/
|
||||
public function setItemsPerPage($num) {
|
||||
$this->itemsPerPage = $num;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Int
|
||||
*/
|
||||
public function getItemsPerPage() {
|
||||
return $this->itemsPerPage;
|
||||
}
|
||||
|
||||
/** Duck check to see if list support methods we need to paginate */
|
||||
protected function getListPaginatable(SS_List $list) {
|
||||
// If no list yet, not paginatable
|
||||
|
@ -3,7 +3,7 @@
|
||||
/**
|
||||
* Provides view and edit forms at GridField-specific URLs.
|
||||
* These can be placed into pop-ups by an appropriate front-end.
|
||||
* Usually added to a grid field alongside of {@link GridFieldAction_Edit}
|
||||
* Usually added to a grid field alongside of {@link GridFieldEditAction}
|
||||
* which takes care of linking the individual rows to their edit view.
|
||||
*
|
||||
* The URLs provided will be off the following form:
|
||||
@ -25,6 +25,11 @@ class GridFieldPopupForms implements GridField_URLHandler {
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* @var Validator The form validator used for both add and edit fields.
|
||||
*/
|
||||
protected $validator;
|
||||
|
||||
function getURLHandlers($gridField) {
|
||||
return array(
|
||||
'item/$ID' => 'handleItem',
|
||||
@ -68,7 +73,7 @@ class GridFieldPopupForms implements GridField_URLHandler {
|
||||
$handler = Object::create($class, $gridField, $this, $record, $controller, $this->name);
|
||||
$handler->setTemplate($this->template);
|
||||
|
||||
return $handler->handleRequest($request, $gridField);
|
||||
return $handler->handleRequest($request, DataModel::inst());
|
||||
}
|
||||
|
||||
/**
|
||||
@ -76,6 +81,7 @@ class GridFieldPopupForms implements GridField_URLHandler {
|
||||
*/
|
||||
function setTemplate($template) {
|
||||
$this->template = $template;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -90,6 +96,7 @@ class GridFieldPopupForms implements GridField_URLHandler {
|
||||
*/
|
||||
function setName($name) {
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -98,6 +105,21 @@ class GridFieldPopupForms implements GridField_URLHandler {
|
||||
function getName() {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Validator $validator
|
||||
*/
|
||||
public function setValidator(Validator $validator) {
|
||||
$this->validator = $validator;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Validator
|
||||
*/
|
||||
public function getValidator() {
|
||||
return $this->validator;
|
||||
}
|
||||
}
|
||||
|
||||
class GridFieldPopupForm_ItemRequest extends RequestHandler {
|
||||
@ -152,7 +174,7 @@ class GridFieldPopupForm_ItemRequest extends RequestHandler {
|
||||
*/
|
||||
public function __construct($gridField, $component, $record, $popupController, $popupFormName) {
|
||||
$this->gridField = $gridField;
|
||||
$this->component = $gridField;
|
||||
$this->component = $component;
|
||||
$this->record = $record;
|
||||
$this->popupController = $popupController;
|
||||
$this->popupFormName = $popupFormName;
|
||||
@ -164,22 +186,9 @@ class GridFieldPopupForm_ItemRequest extends RequestHandler {
|
||||
}
|
||||
|
||||
function edit($request) {
|
||||
$controller = $this->popupController;
|
||||
$controller = $this->getToplevelController();
|
||||
$form = $this->ItemEditForm($this->gridField, $request);
|
||||
|
||||
// TODO Coupling with CMS
|
||||
if($controller instanceof LeftAndMain) {
|
||||
$form->addExtraClass('cms-edit-form');
|
||||
$form->setTemplate($controller->getTemplatesWithSuffix('_EditForm'));
|
||||
$form->addExtraClass('cms-content center ss-tabset ' . $controller->BaseCSSClasses());
|
||||
if($form->Fields()->hasTabset()) $form->Fields()->findOrMakeTab('Root')->setTemplate('CMSTabSet');
|
||||
// TODO Link back to controller action (and edited root record) rather than index,
|
||||
// which requires more URL knowledge than the current link to this field gives us.
|
||||
// The current root record is held in session only,
|
||||
// e.g. page/edit/show/6/ vs. page/edit/EditForm/field/MyGridField/....
|
||||
$form->Backlink = $controller->Link();
|
||||
}
|
||||
|
||||
$return = $this->customise(array(
|
||||
'Backlink' => $controller->Link(),
|
||||
'ItemEditForm' => $form,
|
||||
@ -188,10 +197,9 @@ class GridFieldPopupForm_ItemRequest extends RequestHandler {
|
||||
if($controller->isAjax()) {
|
||||
return $return;
|
||||
} else {
|
||||
|
||||
// If not requested by ajax, we need to render it within the controller context+template
|
||||
return $controller->customise(array(
|
||||
// TODO Allow customization
|
||||
// TODO CMS coupling
|
||||
'Content' => $return,
|
||||
));
|
||||
}
|
||||
@ -208,29 +216,83 @@ class GridFieldPopupForm_ItemRequest extends RequestHandler {
|
||||
* @return Form
|
||||
*/
|
||||
function ItemEditForm() {
|
||||
if (empty($this->record)) {
|
||||
$controller = Controller::curr();
|
||||
$noActionURL = $controller->removeAction($_REQUEST['url']);
|
||||
$controller->getResponse()->removeHeader('Location'); //clear the existing redirect
|
||||
return Director::redirect($noActionURL, 302);
|
||||
}
|
||||
|
||||
$actions = new FieldList();
|
||||
if($this->record->ID !== 0) {
|
||||
$actions->push(FormAction::create('doSave', _t('GridFieldDetailsForm.Save', 'Save'))
|
||||
->setUseButtonTag(true)->addExtraClass('ss-ui-action-constructive')->setAttribute('data-icon', 'accept'));
|
||||
$actions->push(FormAction::create('doDelete', _t('GridFieldDetailsForm.Delete', 'Delete'))
|
||||
->addExtraClass('ss-ui-action-destructive'));
|
||||
}else{ // adding new record
|
||||
//Change the Save label to 'Create'
|
||||
$actions->push(FormAction::create('doSave', _t('GridFieldDetailsForm.Create', 'Create'))
|
||||
->setUseButtonTag(true)->addExtraClass('ss-ui-action-constructive')->setAttribute('data-icon', 'add'));
|
||||
|
||||
// Add a Cancel link which is a button-like link and link back to one level up.
|
||||
$curmbs = $this->Breadcrumbs();
|
||||
if($curmbs && $curmbs->count()>=2){
|
||||
$one_level_up = $curmbs->offsetGet($curmbs->count()-2);
|
||||
$text = "
|
||||
<a class=\"crumb ss-ui-button ss-ui-action-destructive cms-panel-link ui-corner-all\" href=\"".$one_level_up->Link."\">
|
||||
Cancel
|
||||
</a>";
|
||||
$actions->push(new LiteralField('cancelbutton', $text));
|
||||
}
|
||||
}
|
||||
$form = new Form(
|
||||
$this,
|
||||
'ItemEditForm',
|
||||
// WARNING: The arguments passed here are a little arbitrary. This API will need cleanup
|
||||
$this->record->getCMSFields($this->popupController, $this->popupFormName),
|
||||
new FieldList(
|
||||
FormAction::create('doSave', _t('GridFieldDetailsForm.Save', 'Save'))
|
||||
->setUseButtonTag(true)->addExtraClass('ss-ui-action-constructive')->setAttribute('data-icon', 'accept'),
|
||||
FormAction::create('doDelete', _t('GridFieldDetailsForm.Delete', 'Delete'))
|
||||
->setUseButtonTag(true)->addExtraClass('ss-ui-action-destructive')
|
||||
)
|
||||
$this->record->getCMSFields(),
|
||||
$actions,
|
||||
$this->component->getValidator()
|
||||
);
|
||||
$form->loadDataFrom($this->record);
|
||||
|
||||
// TODO Coupling with CMS
|
||||
$toplevelController = $this->getToplevelController();
|
||||
if($toplevelController && $toplevelController instanceof LeftAndMain) {
|
||||
// Always show with base template (full width, no other panels),
|
||||
// regardless of overloaded CMS controller templates.
|
||||
// TODO Allow customization, e.g. to display an edit form alongside a search form from the CMS controller
|
||||
$form->setTemplate('LeftAndMain_EditForm');
|
||||
$form->addExtraClass('cms-content cms-edit-form center ss-tabset');
|
||||
if($form->Fields()->hasTabset()) $form->Fields()->findOrMakeTab('Root')->setTemplate('CMSTabSet');
|
||||
// TODO Link back to controller action (and edited root record) rather than index,
|
||||
// which requires more URL knowledge than the current link to this field gives us.
|
||||
// The current root record is held in session only,
|
||||
// e.g. page/edit/show/6/ vs. page/edit/EditForm/field/MyGridField/....
|
||||
$form->Backlink = $toplevelController->Link();
|
||||
}
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Traverse up nested requests until we reach the first that's not a GridFieldPopupForm_ItemRequest.
|
||||
* The opposite of {@link Controller::curr()}, required because
|
||||
* Controller::$controller_stack is not directly accessible.
|
||||
*
|
||||
* @return Controller
|
||||
*/
|
||||
protected function getToplevelController() {
|
||||
$c = $this->popupController;
|
||||
while($c && $c instanceof GridFieldPopupForm_ItemRequest) {
|
||||
$c = $c->getController();
|
||||
}
|
||||
return $c;
|
||||
}
|
||||
|
||||
function doSave($data, $form) {
|
||||
$new_record = $this->record->ID == 0;
|
||||
|
||||
try {
|
||||
$form->saveInto($this->record);
|
||||
$this->record->write();
|
||||
if($new_record)
|
||||
$this->gridField->getList()->add($this->record);
|
||||
} catch(ValidationException $e) {
|
||||
$form->sessionMessage($e->getResult()->message(), 'bad');
|
||||
@ -247,7 +309,7 @@ class GridFieldPopupForm_ItemRequest extends RequestHandler {
|
||||
|
||||
$form->sessionMessage($message, 'good');
|
||||
|
||||
return $this->popupController->redirectBack();
|
||||
return Controller::curr()->redirectBack();
|
||||
}
|
||||
|
||||
function doDelete($data, $form) {
|
||||
@ -260,7 +322,7 @@ class GridFieldPopupForm_ItemRequest extends RequestHandler {
|
||||
$toDelete->delete();
|
||||
} catch(ValidationException $e) {
|
||||
$form->sessionMessage($e->getResult()->message(), 'bad');
|
||||
return Director::redirectBack();
|
||||
return Controller::curr()->redirectBack();
|
||||
}
|
||||
|
||||
$message = sprintf(
|
||||
@ -283,6 +345,7 @@ class GridFieldPopupForm_ItemRequest extends RequestHandler {
|
||||
*/
|
||||
function setTemplate($template) {
|
||||
$this->template = $template;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -292,6 +355,20 @@ class GridFieldPopupForm_ItemRequest extends RequestHandler {
|
||||
return $this->template;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Controller
|
||||
*/
|
||||
function getController() {
|
||||
return $this->popupController;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return GridField
|
||||
*/
|
||||
function getGridField() {
|
||||
return $this->gridField;
|
||||
}
|
||||
|
||||
/**
|
||||
* CMS-specific functionality: Passes through navigation breadcrumbs
|
||||
* to the template, and includes the currently edited record (if any).
|
||||
@ -301,12 +378,17 @@ class GridFieldPopupForm_ItemRequest extends RequestHandler {
|
||||
* @return ArrayData
|
||||
*/
|
||||
function Breadcrumbs($unlinked = false) {
|
||||
if(!($this->popupController instanceof LeftAndMain)) return false;
|
||||
if(!$this->popupController->hasMethod('Breadcrumbs')) return;
|
||||
|
||||
$items = $this->popupController->Breadcrumbs($unlinked);
|
||||
if($this->record) {
|
||||
if($this->record && $this->record->ID) {
|
||||
$items->push(new ArrayData(array(
|
||||
'Title' => $this->record->Title,
|
||||
'Link' => $this->Link()
|
||||
)));
|
||||
} else {
|
||||
$items->push(new ArrayData(array(
|
||||
'Title' => sprintf(_t('GridField.NewRecord', 'New %s'), $this->record->singular_name()),
|
||||
'Link' => false
|
||||
)));
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* A GridFieldRelationAdd is responsible for adding objects to another object's has_many and many_many relation,
|
||||
* as defined by the RelationList passed to the GridField constructor.
|
||||
* This class is is responsible for adding objects to another object's has_many and many_many relation,
|
||||
* as defined by the {@link 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 {@link GridFieldRelationDelete} for detaching existing records from a relatinship.
|
||||
* For easier setup, have a look at a sample configuration in {@link GridFieldConfig_RelationEditor}.
|
||||
*/
|
||||
class GridFieldRelationAdd implements GridField_HTMLProvider, GridField_ActionProvider, GridField_DataManipulator, GridField_URLHandler {
|
||||
|
||||
@ -17,6 +19,8 @@ class GridFieldRelationAdd implements GridField_HTMLProvider, GridField_ActionPr
|
||||
/**
|
||||
* Which columns that should be used for doing a "StartsWith" search.
|
||||
* If multiple fields are provided, the filtering is performed non-exclusive.
|
||||
* If no fields are provided, tries to auto-detect a "Title" or "Name" field,
|
||||
* and falls back to the first textual field defined on the object.
|
||||
*
|
||||
* @var Array
|
||||
*/
|
||||
@ -36,7 +40,7 @@ class GridFieldRelationAdd implements GridField_HTMLProvider, GridField_ActionPr
|
||||
*
|
||||
* @param array $searchFields Which fields on the object in the list should be searched
|
||||
*/
|
||||
public function __construct($searchFields) {
|
||||
public function __construct($searchFields = null) {
|
||||
$this->searchFields = (array)$searchFields;
|
||||
}
|
||||
|
||||
@ -47,26 +51,24 @@ class GridFieldRelationAdd implements GridField_HTMLProvider, GridField_ActionPr
|
||||
*/
|
||||
public function getHTMLFragments($gridField) {
|
||||
$searchState = $gridField->State->GridFieldSearchRelation;
|
||||
|
||||
|
||||
Requirements::css(THIRDPARTY_DIR . '/jquery-ui-themes/smoothness/jquery-ui.css');
|
||||
Requirements::add_i18n_javascript(SAPPHIRE_DIR . '/javascript/lang');
|
||||
Requirements::javascript(THIRDPARTY_DIR . '/jquery/jquery.js');
|
||||
Requirements::javascript(SAPPHIRE_DIR . '/thirdparty/jquery-ui/jquery-ui.js');
|
||||
Requirements::javascript(SAPPHIRE_DIR . "/javascript/GridFieldSearch.js");
|
||||
$dataClass = $gridField->getList()->dataClass();
|
||||
|
||||
$forTemplate = new ArrayData(array());
|
||||
$forTemplate->Fields = new ArrayList();
|
||||
|
||||
$value = $this->findSingleEntry($gridField, $this->searchFields, $searchState, $gridField->getList()->dataClass);
|
||||
$searchFields = ($this->getSearchFields()) ? $this->getSearchFields() : $this->scaffoldSearchFields($dataClass);
|
||||
|
||||
$value = $this->findSingleEntry($gridField, $searchFields, $searchState, $dataClass);
|
||||
$searchField = new TextField('gridfield_relationsearch', _t('GridField.RelationSearch', "Relation search"), $value);
|
||||
// Apparently the data-* needs to be double qouted for the jQuery.meta data plugin
|
||||
$searchField->setAttribute('data-search-url', '\''.Controller::join_links($gridField->Link('search').'\''));
|
||||
$searchField->setAttribute('placeholder', $this->getPlaceholderText($gridField->getList()->dataClass()));
|
||||
$searchField->setAttribute('placeholder', $this->getPlaceholderText($dataClass));
|
||||
$searchField->addExtraClass('relation-search');
|
||||
|
||||
$findAction = new GridField_Action($gridField, 'gridfield_relationfind', _t('GridField.Find', "Find"), 'find', 'find');
|
||||
$addAction = new GridField_Action($gridField, 'gridfield_relationadd', _t('GridField.LinkExisting', "Link Exisiting"), 'addto', 'addto');
|
||||
$findAction = new GridField_FormAction($gridField, 'gridfield_relationfind', _t('GridField.Find', "Find"), 'find', 'find');
|
||||
$findAction->setAttribute('data-icon', 'relationfind');
|
||||
$addAction = new GridField_FormAction($gridField, 'gridfield_relationadd', _t('GridField.LinkExisting', "Link Exisiting"), 'addto', 'addto');
|
||||
$addAction->setAttribute('data-icon', 'chain--plus');
|
||||
|
||||
// If an object is not found, disable the action
|
||||
if(!is_int($gridField->State->GridFieldAddRelation)) {
|
||||
@ -151,15 +153,24 @@ class GridFieldRelationAdd implements GridField_HTMLProvider, GridField_ActionPr
|
||||
* @param SS_HTTPRequest $request
|
||||
*/
|
||||
public function doSearch($gridField, $request) {
|
||||
$allList = DataList::create($gridField->getList()->dataClass());
|
||||
$dataClass = $gridField->getList()->dataClass();
|
||||
$allList = DataList::create($dataClass);
|
||||
$filters = array();
|
||||
$stmts = array();
|
||||
|
||||
$searchFields = ($this->getSearchFields()) ? $this->getSearchFields() : $this->scaffoldSearchFields($dataClass);
|
||||
if(!$searchFields) {
|
||||
throw new LogicException(
|
||||
sprintf('GridFieldRelationAdd: No searchable fields could be found for class "%s"', $dataClass)
|
||||
);
|
||||
}
|
||||
|
||||
// TODO Replace with DataList->filterAny() once it correctly supports OR connectives
|
||||
foreach($this->searchFields as $searchField) {
|
||||
foreach($searchFields as $searchField) {
|
||||
$stmts[] .= sprintf('"%s" LIKE \'%s%%\'', $searchField, $request->param('ID'));
|
||||
}
|
||||
$results = $allList->where(implode(' OR ', $stmts))->subtract($gridField->getList());
|
||||
$results->sort($this->searchFields[0], 'ASC');
|
||||
$results->sort($searchFields[0], 'ASC');
|
||||
|
||||
$json = array();
|
||||
foreach($results as $result) {
|
||||
@ -198,16 +209,35 @@ class GridFieldRelationAdd implements GridField_HTMLProvider, GridField_ActionPr
|
||||
return $this->searchFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect searchable
|
||||
*
|
||||
* @param String
|
||||
* @return Array
|
||||
*/
|
||||
protected function scaffoldSearchFields($dataClass) {
|
||||
$obj = singleton($dataClass);
|
||||
if($obj->hasDatabaseField('Title')) {
|
||||
return array('Title');
|
||||
} else if($obj->hasDatabaseField('Name')) {
|
||||
return array('Name');
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param String The class of the object being searched for
|
||||
* @return String
|
||||
*/
|
||||
public function getPlaceholderText($dataClass) {
|
||||
$searchFields = ($this->getSearchFields()) ? $this->getSearchFields() : $this->scaffoldSearchFields($dataClass);
|
||||
|
||||
if($this->placeholderText) {
|
||||
return $this->placeholderText;
|
||||
} else {
|
||||
$labels = array();
|
||||
foreach($this->searchFields as $searchField) {
|
||||
foreach($searchFields as $searchField) {
|
||||
$label = singleton($dataClass)->fieldLabel($searchField);
|
||||
if($label) $labels[] = $label;
|
||||
}
|
||||
|
@ -1,9 +1,11 @@
|
||||
<?php
|
||||
/**
|
||||
* Allows to detach an item from an existing has_many or many_many relationship.
|
||||
* Similar to {@link GridFieldAction_Delete}, but allows to distinguish between
|
||||
* 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 RelationList rather than a plain DataList.
|
||||
* Requires the GridField to be populated with a {@link RelationList} rather than a plain {@link DataList}.
|
||||
* Often used alongside {@link GridFieldRelationAdd} to add existing records to the relationship.
|
||||
* For easier setup, have a look at a sample configuration in {@link GridFieldConfig_RelationEditor}.
|
||||
*/
|
||||
class GridFieldRelationDelete implements GridField_ColumnProvider, GridField_ActionProvider {
|
||||
|
||||
@ -14,7 +16,8 @@ class GridFieldRelationDelete implements GridField_ColumnProvider, GridField_Act
|
||||
* @param array $columns
|
||||
*/
|
||||
public function augmentColumns($gridField, &$columns) {
|
||||
$columns[] = 'UnlinkRelation';
|
||||
if(!in_array('Actions', $columns))
|
||||
$columns[] = 'Actions';
|
||||
}
|
||||
|
||||
/**
|
||||
@ -37,7 +40,7 @@ class GridFieldRelationDelete implements GridField_ColumnProvider, GridField_Act
|
||||
* @return array
|
||||
*/
|
||||
public function getColumnMetadata($gridField, $columnName) {
|
||||
if($columnName == 'UnlinkRelation') {
|
||||
if($columnName == 'Actions') {
|
||||
return array('title' => '');
|
||||
}
|
||||
}
|
||||
@ -49,7 +52,7 @@ class GridFieldRelationDelete implements GridField_ColumnProvider, GridField_Act
|
||||
* @return type
|
||||
*/
|
||||
public function getColumnsHandled($gridField) {
|
||||
return array('UnlinkRelation');
|
||||
return array('Actions');
|
||||
}
|
||||
|
||||
/**
|
||||
@ -70,15 +73,17 @@ class GridFieldRelationDelete implements GridField_ColumnProvider, GridField_Act
|
||||
* @return string - the HTML for the column
|
||||
*/
|
||||
public function getColumnContent($gridField, $record, $columnName) {
|
||||
$field = new GridField_Action(
|
||||
$field = Object::create('GridField_FormAction',
|
||||
$gridField,
|
||||
'UnlinkRelation'.$record->ID,
|
||||
_t('GridAction.UnlinkRelation', "Unlink"),
|
||||
false,
|
||||
"unlinkrelation",
|
||||
array('RecordID' => $record->ID)
|
||||
);
|
||||
$output = $field->Field();
|
||||
return $output;
|
||||
)
|
||||
->setAttribute('title', _t('GridAction.UnlinkRelation', "Unlink"))
|
||||
->setAttribute('data-icon', 'chain--minus')
|
||||
->addExtraClass('gridfield-button-unlink');
|
||||
return $field->Field();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -28,9 +28,11 @@ class GridFieldSortableHeader implements GridField_HTMLProvider, GridField_DataM
|
||||
$dir = 'desc';
|
||||
}
|
||||
|
||||
$field = new GridField_Action($gridField, 'SetOrder'.$columnField, $title, "sort$dir", array('SortColumn' => $columnField));
|
||||
$field = Object::create(
|
||||
'GridField_FormAction', $gridField, 'SetOrder'.$columnField, $title,
|
||||
"sort$dir", array('SortColumn' => $columnField)
|
||||
)->addExtraClass('ss-gridfield-sort');
|
||||
|
||||
$field->addExtraClass('ss-gridfield-sort');
|
||||
if($state->SortColumn == $columnField){
|
||||
$field->addExtraClass('ss-gridfield-sorted');
|
||||
|
||||
|
@ -1,13 +1,47 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Adding this class to a {@link GridFieldConfig} of a {@link GridField} adds a header title to that field.
|
||||
* The header serves double duty of displaying the name of the data the GridField is showing and
|
||||
* providing an "add new" button to create new object instances.
|
||||
*
|
||||
* The reason for making "add new" part of the title component is to make it easier for the user to tell
|
||||
* which "add new" button belongs to which datagrid, in the case where multiple datagrids are on a single
|
||||
* page. It is also a more efficient use of screen space.
|
||||
*
|
||||
* The default DataGrid includes the add button. You can hide the button by setting a boolean using the
|
||||
* setNewEnabled() method
|
||||
*
|
||||
* @package sapphire
|
||||
* @subpackage gridfield
|
||||
*/
|
||||
class GridFieldTitle implements GridField_HTMLProvider {
|
||||
|
||||
protected $newEnabled = true;
|
||||
|
||||
function getHTMLFragments($gridField) {
|
||||
return array(
|
||||
'header' => $gridField->customise(array(
|
||||
'NewLink' => Controller::join_links($gridField->Link('item'), 'new')
|
||||
'NewLink' => Controller::join_links($gridField->Link('item'), 'new'),
|
||||
'NewEnabled' => $this->getNewEnabled()
|
||||
))->renderWith('GridFieldTitle')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether or not the "add new" button will appear when rendering this DataGrid title
|
||||
* @return bool
|
||||
*/
|
||||
function getNewEnabled() {
|
||||
return $this->newEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable the "add new" button to add new DataGrid object instances
|
||||
* @param $enabled
|
||||
*/
|
||||
function setNewEnabled($enabled) {
|
||||
$this->newEnabled = $enabled;
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
BIN
images/icons/pagination-arrows.png
Normal file
After Width: | Height: | Size: 358 B |
@ -6,7 +6,10 @@
|
||||
* @param {successCallback} callback to call after reloading succeeded.
|
||||
*/
|
||||
reload: function(ajaxOpts, successCallback) {
|
||||
var self = this, form = this.closest('form'), data = form.find(':input').serializeArray();
|
||||
var self = this, form = this.closest('form'),
|
||||
focusedElName = this.find(':input:focus').attr('name'), // Save focused element for restoring after refresh
|
||||
data = form.find(':input').serializeArray();
|
||||
|
||||
if(!ajaxOpts) ajaxOpts = {};
|
||||
if(!ajaxOpts.data) ajaxOpts.data = [];
|
||||
ajaxOpts.data = ajaxOpts.data.concat(data);
|
||||
@ -30,6 +33,10 @@
|
||||
// of the executing method. Means that it doesn't retrigger the onmatch() on the main container.
|
||||
self.empty().append($(data).children());
|
||||
|
||||
// Refocus previously focused element. Useful e.g. for finding+adding
|
||||
// multiple relationships via keyboard.
|
||||
if(focusedElName) self.find(':input[name="' + focusedElName + '"]').focus();
|
||||
|
||||
form.removeClass('loading');
|
||||
if(successCallback) successCallback.apply(this, arguments);
|
||||
self.trigger('reload', self);
|
||||
@ -71,9 +78,9 @@
|
||||
|
||||
$('.ss-gridfield .ss-gridfield-item').entwine({
|
||||
onclick: function(e) {
|
||||
if($(e.target).is('.action')) {
|
||||
if($(e.target).closest('.action').length) {
|
||||
this._super(e);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
var editLink = this.find('.edit-link');
|
||||
@ -94,10 +101,36 @@
|
||||
}
|
||||
});
|
||||
|
||||
$('.ss-gridfield .gridfield-button-delete').entwine({
|
||||
$('.ss-gridfield .action.gridfield-button-delete').entwine({
|
||||
onclick: function(e){
|
||||
if(!confirm(ss.i18n._t('TABLEFIELD.DELETECONFIRMMESSAGE'))) return false;
|
||||
else this._super(e);
|
||||
if(!confirm(ss.i18n._t('TABLEFIELD.DELETECONFIRMMESSAGE'))) {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
} else {
|
||||
this._super(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Prevents actions from causing an ajax reload of the field.
|
||||
* Useful e.g. for actions which rely on HTTP response headers being interpreted nativel
|
||||
* by the browser, like file download triggers.
|
||||
*/
|
||||
$('.ss-gridfield .action.no-ajax').entwine({
|
||||
onclick: function(e){
|
||||
var self = this, btn = this.closest(':button'), grid = this.getGridField(),
|
||||
form = this.closest('form'), data = form.find(':input').serialize();
|
||||
|
||||
// Add current button
|
||||
data += '&' + encodeURIComponent(btn.attr('name')) + '=' + encodeURIComponent(btn.val());
|
||||
|
||||
// Include any GET parameters from the current URL, as the view state might depend on it.
|
||||
// For example, a list prefiltered through external search criteria might be passed to GridField.
|
||||
if(window.location.search) data = window.location.search.replace(/^\?/, '') + '&' + data;
|
||||
|
||||
window.location.href = $.path.makeUrlAbsolute(grid.data('url') + '?' + data, $('base').attr('href'));
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
@ -152,10 +185,77 @@
|
||||
* rather than the whole form.
|
||||
*/
|
||||
$('.ss-gridfield .filter-header :input').entwine({
|
||||
onmatch: function(){
|
||||
filterbtn = this.closest('.fieldgroup').find('.ss-gridfield-button-filter');
|
||||
resetbtn = this.closest('.fieldgroup').find('.ss-gridfield-button-reset');
|
||||
if(this.val()) {
|
||||
filterbtn.addClass('filtered');
|
||||
resetbtn.addClass('filtered');
|
||||
}
|
||||
},
|
||||
onkeydown: function(e) {
|
||||
filterbtn = this.closest('.fieldgroup').find('.ss-gridfield-button-filter');
|
||||
resetbtn = this.closest('.fieldgroup').find('.ss-gridfield-button-reset');
|
||||
if(e.keyCode == '13') {
|
||||
btn = this.closest('.filter-header').find('.ss-gridfield-button-filter');
|
||||
this.getGridField().reload({data: [{name: btn.attr('name'), value: btn.val()}]});
|
||||
btns = this.closest('.filter-header').find('.ss-gridfield-button-filter');
|
||||
this.getGridField().reload({data: [{name: btns.attr('name'), value: btns.val()}]});
|
||||
return false;
|
||||
}else{
|
||||
filterbtn.addClass('hover-alike');
|
||||
resetbtn.addClass('hover-alike');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$(".ss-gridfield .relation-search").entwine({
|
||||
onfocusin: 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(
|
||||
'<input type="hidden" name="relationID" value="'+ui.item.id+'" id="relationID"/>'
|
||||
);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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(
|
||||
'<input type="hidden" name="relationID" value="'+ui.item.id+'" id="relationID"/>'
|
||||
);
|
||||
var addbutton = $(this).closest(".ss-gridfield").find("#action_gridfield_relationadd");
|
||||
if(addbutton.data('button')){
|
||||
addbutton.button('enable');
|
||||
}else{
|
||||
addbutton.removeAttr('disabled');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
});
|
@ -1,7 +0,0 @@
|
||||
(function($) {
|
||||
$('.formattingHelpText').hide();
|
||||
$('.formattingHelpToggle').click(function() {
|
||||
$(this).parent().find('.formattingHelpText').toggle();
|
||||
return false;
|
||||
})
|
||||
})(jQuery);
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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.<br />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';
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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) . "'";
|
||||
}
|
||||
|
@ -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,14 +93,12 @@ 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
|
||||
// Insert new entry/entries
|
||||
foreach((array)$this->foreignID as $foreignID) {
|
||||
$manipulation = array();
|
||||
$manipulation[$this->joinTable]['command'] = 'insert';
|
||||
|
||||
@ -109,10 +107,11 @@ class ManyManyList extends RelationList {
|
||||
}
|
||||
|
||||
$manipulation[$this->joinTable]['fields'][$this->localKey] = $itemID;
|
||||
$manipulation[$this->joinTable]['fields'][$this->foreignKey] = $this->foreignID;
|
||||
$manipulation[$this->joinTable]['fields'][$this->foreignKey] = $foreignID;
|
||||
|
||||
DB::manipulate($manipulation);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given item from this list.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -358,6 +366,66 @@ $gf_grid_x: 16px;
|
||||
&.bottom-all {
|
||||
@include border-bottom-radius($gf_border_radius);
|
||||
@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 {
|
||||
|
@ -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) {
|
||||
|
@ -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('<span class="aligned_right_label">' . _t('Group.GroupReminder', 'If you choose a parent group, this group will take all it\'s roles') . '</span>');
|
||||
|
||||
// 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,8 +129,16 @@ class Group extends DataObject {
|
||||
new LiteralField(
|
||||
"",
|
||||
"<p>" .
|
||||
_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.<br />They are inherited from parent groups if required."
|
||||
) . '<br />' .
|
||||
sprintf(
|
||||
'<a href="%s" class="add-role">%s</a>',
|
||||
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')
|
||||
) .
|
||||
"</p>"
|
||||
)
|
||||
@ -131,6 +146,7 @@ class Group extends DataObject {
|
||||
|
||||
// Add roles (and disable all checkboxes for inherited roles)
|
||||
$allRoles = Permission::check('ADMIN') ? DataObject::get('PermissionRole') : DataObject::get('PermissionRole', 'OnlyAdminCanApply = 0');
|
||||
if($this->ID) {
|
||||
$groupRoles = $this->Roles();
|
||||
$inheritedRoles = new ArrayList();
|
||||
$ancestors = $this->getAncestors();
|
||||
@ -138,13 +154,20 @@ class Group extends DataObject {
|
||||
$ancestorRoles = $ancestor->Roles();
|
||||
if($ancestorRoles) $inheritedRoles->merge($ancestorRoles);
|
||||
}
|
||||
$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'));
|
||||
$groupRoleIDs = $groupRoles->column('ID') + $inheritedRoles->column('ID');
|
||||
$inheritedRoleIDs = $inheritedRoles->column('ID');
|
||||
} else {
|
||||
$groupRoleIDs = array();
|
||||
$inheritedRoleIDs = array();
|
||||
}
|
||||
|
||||
$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.
|
||||
* 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.
|
||||
*
|
||||
* @TODO Where is this used, why is this overloaded?
|
||||
*
|
||||
* @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');
|
||||
}
|
||||
|
@ -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).
|
||||
|
@ -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) {
|
||||
|
@ -10,7 +10,7 @@
|
||||
<div class="ss-uploadfield-item-info">
|
||||
<label class="ss-uploadfield-fromcomputer ss-ui-button ss-ui-action-constructive" title="<% _t('AssetUploadField.FROMCOMPUTERINFO', 'Upload from your computer') %>" data-icon="drive-upload">
|
||||
<% _t('AssetUploadField.FROMCOMPUTER', 'Choose files from your computer') %>
|
||||
<input id="$id" name="$getName" class="$extraClass ss-uploadfield-fromcomputer-fileinput" data-config="$configString" type="file"<% if $multiple %> multiple="multiple"<% end_if %><% if $TabIndex %> tabindex="$TabIndex"<% end_if %> title="<% _t('AssetUploadField.FROMCOMPUTER', 'Choose files from your computer') %>" />
|
||||
<input id="$id" name="$getName" class="$extraClass ss-uploadfield-fromcomputer-fileinput" data-config="$configString" type="file"<% if $multiple %> multiple="multiple"<% end_if %>> title="<% _t('AssetUploadField.FROMCOMPUTER', 'Choose files from your computer') %>" />
|
||||
</label>
|
||||
|
||||
<div class="clear"><!-- --></div>
|
||||
|
@ -1,7 +1,9 @@
|
||||
<tr>
|
||||
<td class="bottom-all" colspan="$Colspan">
|
||||
<% control Fields %>
|
||||
$Field
|
||||
<% end_control %>
|
||||
<div class="datagrid-pagination">
|
||||
$FirstPage $PreviousPage <span class="pagination-page-number">Page <input class="text" value="$CurrentPageNum"/> of $NumPages</span> $NextPage $LastPage
|
||||
</div>
|
||||
|
||||
<span class="pagination-records-number">View $FirstShownRecord - $LastShownRecord of $NumRecords</span>
|
||||
</td>
|
||||
</tr>
|
@ -1,3 +1,3 @@
|
||||
<tr class="title">
|
||||
<th colspan="$ColumnCount"><h2>$Title</h2> <a href="$NewLink" class="action ss-ui-action-constructive ss-ui-button ui-button ui-widget ui-state-default ui-corner-all new new-link"><% _t('GridField.AddNew', 'Add New') %></a></th>
|
||||
<th colspan="$ColumnCount"><h2>$Title</h2><% if NewEnabled %> <a href="$NewLink" class="action ss-ui-action-constructive ss-ui-button ui-button ui-widget ui-state-default ui-corner-all new new-link" data-icon="add"><% _t('GridField.AddNew', 'Add New') %></a><% end_if %></th>
|
||||
</tr>
|
@ -1 +0,0 @@
|
||||
<button id="$ID" class="$Class" name="$Name" type="submit" data-url="$DataURL"<% if Disabled %> disabled="disabled"<% end_if %>>$Label</button>
|
3
templates/Includes/GridField_FormAction.ss
Normal file
@ -0,0 +1,3 @@
|
||||
<button $AttributesHTML>
|
||||
<% if ButtonContent %>$ButtonContent<% else %>$Title<% end_if %>
|
||||
</button>
|
@ -45,7 +45,7 @@
|
||||
</b></label>
|
||||
<label class="ss-uploadfield-fromcomputer ss-ui-button ui-corner-all" title="<% _t('UploadField.FROMCOMPUTERINFO', 'Upload from your computer') %>" data-icon="drive-upload">
|
||||
<% _t('UploadField.FROMCOMPUTER', 'From your computer') %>
|
||||
<input id="$id" name="$getName" class="$extraClass ss-uploadfield-fromcomputer-fileinput" data-config="$configString" type="file"<% if $multiple %> multiple="multiple"<% end_if %><% if $TabIndex %> tabindex="$TabIndex"<% end_if %> />
|
||||
<input id="$id" name="$getName" class="$extraClass ss-uploadfield-fromcomputer-fileinput" data-config="$configString" type="file"<% if $multiple %> multiple="multiple"<% end_if %> />
|
||||
</label>
|
||||
<button class="ss-uploadfield-fromfiles ss-ui-button ui-corner-all" title="<% _t('UploadField.FROMCOMPUTERINFO', 'Select from from files') %>" data-icon="network-cloud"><% _t('UploadField.FROMCOMPUTER', 'From files') %></button>
|
||||
<% if not $config.autoUpload %>
|
||||
|
@ -1,4 +1,4 @@
|
||||
<ul id="$ID" class="$extraClass">
|
||||
<ul id="$ID" class="$extraClass"<% if Description %> title="$Description"<% end_if %>>
|
||||
<% if Options.Count %>
|
||||
<% control Options %>
|
||||
<li class="$Class">
|
||||
|
@ -1,5 +1,5 @@
|
||||
<select $AttributesHTML>
|
||||
<% control Options %>
|
||||
<option value="$Value"<% if Selected %> selected<% end_if %>>$Title</option>
|
||||
<option value="$Value"<% if Selected %> selected="selected"<% end_if %><% if Disabled %> disabled="disabled"<% end_if %>>$Title</option>
|
||||
<% end_control %>
|
||||
</select>
|
@ -1,4 +1,4 @@
|
||||
<ul id="$ID" class="$extraClass">
|
||||
<ul id="$ID" class="$extraClass"<% if Description %> title="$Description"<% end_if %>>
|
||||
<% control Options %>
|
||||
<li class="$Class">
|
||||
<input id="$ID" class="radio" name="$Name" type="radio" value="$Value"<% if isChecked %> checked<% end_if %><% if isDisabled %> disabled<% end_if %>>
|
||||
|
@ -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');
|
||||
@ -99,40 +99,6 @@ class CheckboxSetFieldTest extends SapphireTest {
|
||||
);
|
||||
}
|
||||
|
||||
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');
|
||||
$articleWithTags = $this->objFromFixture('CheckboxSetFieldTest_Article', 'articlewithtags');
|
||||
|
@ -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
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?php
|
||||
class GridFieldtest extends SapphireTest {
|
||||
class GridFieldTest extends SapphireTest {
|
||||
|
||||
/**
|
||||
* @covers GridField::__construct
|
||||
|
@ -6,7 +6,49 @@
|
||||
|
||||
class ListboxFieldTest extends SapphireTest {
|
||||
|
||||
protected $extraDataObjects = array('ListboxFieldTest_DataObject');
|
||||
static $fixture_file = 'ListboxFieldTest.yml';
|
||||
|
||||
protected $extraDataObjects = array('ListboxFieldTest_DataObject', 'ListboxFieldTest_Article', 'ListboxFieldTest_Tag');
|
||||
|
||||
function testFieldWithManyManyRelationship() {
|
||||
$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);
|
||||
|
||||
$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');
|
||||
@ -63,6 +105,33 @@ class ListboxFieldTest extends SapphireTest {
|
||||
$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
|
||||
*/
|
||||
@ -131,3 +200,20 @@ class ListboxFieldTest_DataObject extends DataObject implements TestOnly {
|
||||
'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'
|
||||
);
|
||||
}
|
13
tests/forms/ListboxFieldTest.yml
Normal file
@ -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
|
@ -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 {
|
||||
|
121
tests/forms/gridfield/GridFieldPopupFormsTest.php
Normal file
@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
class GridFieldPopupFormsTest extends FunctionalTest {
|
||||
static $fixture_file = 'GridFieldPopupFormsTest.yml';
|
||||
|
||||
protected $extraDataObjects = array(
|
||||
'GridFieldPopupFormsTest_Person',
|
||||
'GridFieldPopupFormsTest_PeopleGroup'
|
||||
);
|
||||
|
||||
|
||||
function testAddForm() {
|
||||
$group = DataList::create('GridFieldPopupFormsTest_PeopleGroup')
|
||||
->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());
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
12
tests/forms/gridfield/GridFieldPopupFormsTest.yml
Normal file
@ -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
|
33
tests/forms/gridfield/GridFieldTitleTest.php
Normal file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
class GridFieldTitleTest extends SapphireTest {
|
||||
|
||||
|
||||
public function testGridTitleAddNewEnabled() {
|
||||
//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(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");
|
||||
}
|
||||
}
|
||||
?>
|
@ -1,4 +1,4 @@
|
||||
<?php
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Test the API for creating GridField_URLHandler compeonnts
|
||||
|
@ -3,7 +3,8 @@ DataObjectTest_Team:
|
||||
Title: Team 1
|
||||
team2:
|
||||
Title: Team 2
|
||||
|
||||
team3:
|
||||
Title: Team 3
|
||||
DataObjectTest_Player:
|
||||
captain1:
|
||||
FirstName: Captain
|
||||
|
20
tests/model/HasManyListTest.php
Normal file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
class HasManyListTest extends SapphireTest {
|
||||
|
||||
// Borrow the model from DataObjectTest
|
||||
public static $fixture_file = 'DataObjectTest.yml';
|
||||
|
||||
protected $extraDataObjects = array(
|
||||
'DataObjectTest_Team',
|
||||
'DataObjectTest_SubTeam',
|
||||
'DataObjectTest_Player',
|
||||
);
|
||||
|
||||
public function testRelationshipEmptyOnNewRecords() {
|
||||
// Relies on the fact that (unrelated) comments exist in the fixture file already
|
||||
$newTeam = new DataObjectTest_Team(); // has_many Comments
|
||||
$this->assertEquals(array(), $newTeam->Comments()->column('ID'));
|
||||
}
|
||||
|
||||
}
|
@ -16,6 +16,12 @@ class ManyManyListTest extends SapphireTest {
|
||||
$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');
|
||||
$team1 = $this->objFromFixture('DataObjectTest_Team', 'team1');
|
||||
@ -73,6 +79,20 @@ class ManyManyListTest extends SapphireTest {
|
||||
$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');
|
||||
$this->assertEquals(3, $allList->count(), 'Precondition; we have all 3 players connected to a team in the list');
|
||||
|