mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
API CHANGE Removed MemberTableField, use GridField with GridFieldConfig_RelationEditor instead
This commit is contained in:
parent
8da89c6f7c
commit
0117b32fee
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -17,9 +17,6 @@ class SecurityAdmin extends LeftAndMain implements PermissionProvider {
|
||||
static $subitem_class = 'Member';
|
||||
|
||||
static $allowed_actions = array(
|
||||
'autocomplete',
|
||||
'removememberfromgroup',
|
||||
'AddRecordForm',
|
||||
'EditForm',
|
||||
'MemberImportForm',
|
||||
'memberimport',
|
||||
@ -223,51 +220,6 @@ class SecurityAdmin extends LeftAndMain implements PermissionProvider {
|
||||
return $form;
|
||||
}
|
||||
|
||||
public function AddRecordForm() {
|
||||
$m = Object::create('MemberTableField',
|
||||
$this,
|
||||
"Members",
|
||||
$this->currentPageID()
|
||||
);
|
||||
return $m->AddRecordForm();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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');
|
||||
}
|
||||
|
@ -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.
|
||||
*/
|
||||
$('.cms-edit-form .Actions #Form_EditForm_action_addmember').entwine({
|
||||
// Function: onclick
|
||||
$('#Permissions .checkbox[value=ADMIN]').entwine({
|
||||
onmatch: function() {
|
||||
this.toggleCheckboxes();
|
||||
|
||||
this._super();
|
||||
},
|
||||
/**
|
||||
* Function: onclick
|
||||
*/
|
||||
onclick: function(e) {
|
||||
// CAUTION: Assumes that a MemberTableField-instance is present as an editing form
|
||||
var t = $('#Form_EditForm_Members');
|
||||
t[0].openPopup(
|
||||
null,
|
||||
$('base').attr('href') + t.find('a.addlink').attr('href'),
|
||||
t.find('table')[0]
|
||||
);
|
||||
return false;
|
||||
this.toggleCheckboxes();
|
||||
},
|
||||
/**
|
||||
* Function: toggleCheckboxes
|
||||
*/
|
||||
toggleCheckboxes: function() {
|
||||
var self = this, checkboxes = this.parents('.field:eq(0)').find('.checkbox').not(this);
|
||||
|
||||
if(this.is(':checked')) {
|
||||
checkboxes.each(function() {
|
||||
$(this).data('SecurityAdmin.oldChecked', $(this).attr('checked'));
|
||||
$(this).data('SecurityAdmin.oldDisabled', $(this).attr('disabled'));
|
||||
$(this).attr('disabled', 'disabled');
|
||||
$(this).attr('checked', 'checked');
|
||||
});
|
||||
} else {
|
||||
checkboxes.each(function() {
|
||||
$(this).attr('checked', $(this).data('SecurityAdmin.oldChecked'));
|
||||
$(this).attr('disabled', $(this).data('SecurityAdmin.oldDisabled'));
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -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,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
|
@ -182,3 +182,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
|
Loading…
Reference in New Issue
Block a user