mirror of
https://github.com/UndefinedOffset/SortableGridField.git
synced 2024-10-22 17:05:38 +02:00
Initial commit of module
This commit is contained in:
parent
0638c2de85
commit
710c7b88d2
6
.buildpath
Normal file
6
.buildpath
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<buildpath>
|
||||
<buildpathentry kind="con" path="org.eclipse.php.core.LANGUAGE"/>
|
||||
<buildpathentry kind="src" path=""/>
|
||||
<buildpathentry kind="con" path="ca.edchipman.silverstripepdt.LANGUAGE"/>
|
||||
</buildpath>
|
29
.project
Normal file
29
.project
Normal file
@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>SortableGridField</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.wst.jsdt.core.javascriptValidator</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.wst.validation.validationbuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.dltk.core.scriptbuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>ca.edchipman.silverstripepdt.SilverStripeNature</nature>
|
||||
<nature>org.eclipse.php.core.PHPNature</nature>
|
||||
<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
16
.settings/.jsdtscope
Normal file
16
.settings/.jsdtscope
Normal file
@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry kind="src" path="">
|
||||
<attributes>
|
||||
<attribute name="provider" value="org.eclipse.wst.jsdt.web.core.internal.project.ModuleSourcePathProvider"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.WebProject">
|
||||
<attributes>
|
||||
<attribute name="hide" value="true"/>
|
||||
</attributes>
|
||||
</classpathentry>
|
||||
<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.baseBrowserLibrary"/>
|
||||
<classpathentry kind="output" path=""/>
|
||||
</classpath>
|
3
.settings/org.eclipse.php.core.prefs
Normal file
3
.settings/org.eclipse.php.core.prefs
Normal file
@ -0,0 +1,3 @@
|
||||
eclipse.preferences.version=1
|
||||
include_path=0;/SortableGridField\u00055;ca.edchipman.silverstripepdt.LANGUAGE
|
||||
silverstripe_version=SS2.4
|
1
.settings/org.eclipse.wst.jsdt.ui.superType.container
Normal file
1
.settings/org.eclipse.wst.jsdt.ui.superType.container
Normal file
@ -0,0 +1 @@
|
||||
org.eclipse.wst.jsdt.launching.baseBrowserLibrary
|
1
.settings/org.eclipse.wst.jsdt.ui.superType.name
Normal file
1
.settings/org.eclipse.wst.jsdt.ui.superType.name
Normal file
@ -0,0 +1 @@
|
||||
Window
|
3
_config.php
Normal file
3
_config.php
Normal file
@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
?>
|
135
code/extensions/GridFieldSortableObject.php
Normal file
135
code/extensions/GridFieldSortableObject.php
Normal file
@ -0,0 +1,135 @@
|
||||
<?php
|
||||
class GridFieldSortableObject extends DataExtension {
|
||||
public static $db=array(
|
||||
'SortOrder'=>'Int'
|
||||
);
|
||||
|
||||
protected static $sortable_classes = array();
|
||||
protected static $many_many_sortable_relations = array();
|
||||
protected static $sort_dir = "ASC";
|
||||
|
||||
|
||||
public static function set_sort_dir($dir) {
|
||||
self::$sort_dir=$dir;
|
||||
}
|
||||
|
||||
|
||||
public static function add_sortable_class($className) {
|
||||
if(!self::is_sortable_class($className)) {
|
||||
Object::add_extension($className, 'GridFieldSortableObject');
|
||||
|
||||
self::$sortable_classes[]=$className;
|
||||
}
|
||||
}
|
||||
|
||||
public static function add_sortable_classes(array $classes) {
|
||||
foreach($classes as $class) {
|
||||
self::add_sortable_class($class);
|
||||
}
|
||||
}
|
||||
|
||||
public static function add_sortable_many_many_relation($ownerClass, $componentName) {
|
||||
list($parentClass, $componentClass, $parentField, $componentField, $table)=singleton($ownerClass)->many_many($componentName);
|
||||
|
||||
Object::add_static_var($ownerClass, 'many_many_extraFields', array(
|
||||
$componentName=>array(
|
||||
'SortOrder'=>'Int'
|
||||
)));
|
||||
|
||||
|
||||
if(!isset(self::$many_many_sortable_relations[$componentClass])) {
|
||||
self::$many_many_sortable_relations[$componentClass] = array();
|
||||
}
|
||||
|
||||
|
||||
self::$many_many_sortable_relations[$componentClass][$parentClass]=$table;
|
||||
self::add_sortable_class($componentClass);
|
||||
}
|
||||
|
||||
public static function remove_sortable_class($class) {
|
||||
Object::remove_extension($class, 'GridFieldSortableObject');
|
||||
}
|
||||
|
||||
public static function is_sortable_class($classname) {
|
||||
if(in_array($classname, self::$sortable_classes)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach(self::$sortable_classes as $class) {
|
||||
if(is_subclass_of($classname, $class)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return Object::has_extension($classname, 'GridFieldSortableObject');
|
||||
}
|
||||
|
||||
public static function is_sortable_many_many($componentClass, $parentClass=null) {
|
||||
$map=self::$many_many_sortable_relations;
|
||||
if($parentClass===null) {
|
||||
return isset($map[$componentClass]);
|
||||
}else {
|
||||
if(isset($map[$componentClass])) {
|
||||
return isset($map[$componentClass][$parentClass]);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static function get_join_tables($classname) {
|
||||
if(isset(self::$many_many_sortable_relations[$classname])) {
|
||||
return self::$many_many_sortable_relations[$classname];
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function augmentSQL(SQLQuery &$query) {
|
||||
if(empty($query->select) || $query->delete || in_array("COUNT(*)", $query->select) || in_array("count(*)", $query->select)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
$sort_field=false;
|
||||
if($join_tables=self::get_join_tables($this->owner->class)) {
|
||||
foreach($query->from as $from) {
|
||||
if($sort_field) {
|
||||
break;
|
||||
}
|
||||
|
||||
foreach($join_tables as $join_table) {
|
||||
if(stristr($from,$join_table)) {
|
||||
$sort_field="\"$join_table\".\"SortOrder\"";
|
||||
|
||||
if(isset($query->select['SortOrder'])) {
|
||||
$query->select['SortOrder']="\"{$this->owner->class}\".SortOrder AS LocalSort";
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!$sort_field) {
|
||||
$sort_field="\"SortOrder\"";
|
||||
}
|
||||
|
||||
if(!$query->orderby || ($query->orderby==$this->owner->stat('default_sort'))) {
|
||||
$query->orderby="$sort_field ".self::$sort_dir;
|
||||
}
|
||||
}
|
||||
|
||||
public function onBeforeWrite() {
|
||||
if(!$this->owner->ID) {
|
||||
if($peers=DataList::create($this->owner->class)) {
|
||||
$this->owner->SortOrder=$peers->Count()+1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
143
code/forms/GridFieldSortableRows.php
Normal file
143
code/forms/GridFieldSortableRows.php
Normal file
@ -0,0 +1,143 @@
|
||||
<?php
|
||||
/**
|
||||
* @package forms
|
||||
*/
|
||||
class GridFieldSortableRows implements GridField_HTMLProvider, GridField_ActionProvider {
|
||||
/**
|
||||
* Returns a map where the keys are fragment names and the values are pieces of HTML to add to these fragments.
|
||||
* @param GridField $gridField Grid Field Reference
|
||||
* @return {array} Map where the keys are fragment names and the values are pieces of HTML to add to these fragments.
|
||||
*/
|
||||
public function getHTMLFragments($gridField) {
|
||||
$state=$gridField->State->GridFieldSortableRows;
|
||||
if(!is_bool($state->sortableToggle)) {
|
||||
$state->sortableToggle=false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if(Object::has_extension($gridField->getModelClass(), 'GridFieldSortableObject')) {
|
||||
//Sort order toggle
|
||||
$sortOrderToggle=new GridField_FormAction($gridField, 'sortablerows_toggle', 'Allow drag and drop re-ordering', 'saveGridRowSort', null);
|
||||
$sortOrderToggle->addExtraClass('sortablerows_toggle');
|
||||
|
||||
//Disable Pagenator
|
||||
if($gridField->getConfig()->getComponentByType('GridFieldPaginator')) {
|
||||
$disablePagenator=new GridField_FormAction($gridField, 'sortablerows_disablepagenator', 'Disable Pagenator', 'sortableRowsDisablePaginator', null);
|
||||
$disablePagenator->addExtraClass('sortablerows_disablepagenator');
|
||||
}else {
|
||||
$disablePagenator=null;
|
||||
}
|
||||
|
||||
$forTemplate=new ArrayData(array(
|
||||
'SortableToggle'=>$sortOrderToggle,
|
||||
'PagenatorToggle'=>$disablePagenator,
|
||||
'Checked'=>($state->sortableToggle==true ? ' checked="checked"':'')
|
||||
));
|
||||
|
||||
|
||||
//Inject Requirements
|
||||
Requirements::css('SortableGridField/css/GridFieldSortableRows.css');
|
||||
Requirements::javascript('SortableGridField/javascript/GridFieldSortableRows.js');
|
||||
|
||||
|
||||
return array(
|
||||
'header'=>$forTemplate->renderWith('GridFieldSortableRows', array('Colspan'=>count($gridField->getColumns())))
|
||||
);
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a list of the actions handled by this action provider.
|
||||
* @param GridField $gridField Grid Field Reference
|
||||
* @return {array} Array with action identifier strings.
|
||||
*/
|
||||
public function getActions($gridField) {
|
||||
if(Object::has_extension($gridField->getModelClass(), 'GridFieldSortableObject')) {
|
||||
if($gridField->getConfig()->getComponentByType('GridFieldPaginator')) {
|
||||
return array('saveGridRowSort', 'sortableRowsDisablePaginator');
|
||||
}else {
|
||||
return array('saveGridRowSort');
|
||||
}
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle an action on the given grid field.
|
||||
* @param {GridField} $gridField Grid Field Reference
|
||||
* @param {string} $actionName Action identifier, see {@link getActions()}.
|
||||
* @param {array} $arguments Arguments relevant for this
|
||||
* @param {array} $data All form data
|
||||
*/
|
||||
public function handleAction(GridField $gridField, $actionName, $arguments, $data) {
|
||||
$state=$gridField->State->GridFieldSortableRows;
|
||||
if(!is_bool($state->sortableToggle)) {
|
||||
$state->sortableToggle=false;
|
||||
}else if($state->sortableToggle==true) {
|
||||
if($gridField->getConfig()->getComponentsByType('GridFieldPaginator')) {
|
||||
$gridField->getConfig()->removeComponentsByType('GridFieldPaginator');
|
||||
$gridField->getConfig()->addComponent(new GridFieldFooter());
|
||||
}
|
||||
|
||||
$gridField->getConfig()->removeComponentsByType('GridFieldFilterHeader');
|
||||
$gridField->getConfig()->removeComponentsByType('GridFieldSortableHeader');
|
||||
}
|
||||
|
||||
|
||||
if(Object::has_extension($gridField->getModelClass(), 'GridFieldSortableObject')) {
|
||||
if($actionName=='savegridrowsort') {
|
||||
return $this->saveGridRowSort($gridField, $data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles saving of the row sort order
|
||||
* @param {GridField} $gridField Grid Field Reference
|
||||
* @param {array} $data Data submitted in the request
|
||||
*/
|
||||
private function saveGridRowSort(GridField $gridField, $data) {
|
||||
if(empty($data['Items'])) {
|
||||
user_error('No items to sort', E_USER_ERROR);
|
||||
}
|
||||
|
||||
$className=$gridField->getModelClass();
|
||||
$ownerClass=$gridField->Form->Controller()->class;
|
||||
|
||||
$many_many=GridFieldSortableObject::is_sortable_many_many($className);
|
||||
if($many_many) {
|
||||
$candidates=singleton($ownerClass)->many_many();
|
||||
if(is_array($candidates)) {
|
||||
foreach($candidates as $name => $class)
|
||||
if($class==$className) {
|
||||
$relationName=$name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!isset($relationName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
list($parentClass, $componentClass, $parentField, $componentField, $table)=singleton($ownerClass)->many_many($relationName);
|
||||
}
|
||||
|
||||
|
||||
$data['Items']=explode(',', $data['Items']);
|
||||
for($sort=0;$sort<count($data['Items']);$sort++) {
|
||||
$id=intval($data['Items'][$sort]);
|
||||
if($many_many) {
|
||||
DB::query("UPDATE \"$table\" SET \"SortOrder\" = $sort WHERE \"{$className}ID\" = $id");
|
||||
}else {
|
||||
$obj=DataObject::get_by_id($className, $id);
|
||||
$obj->SortOrder=$sort;
|
||||
$obj->write();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
7
css/GridFieldSortableRows.css
Normal file
7
css/GridFieldSortableRows.css
Normal file
@ -0,0 +1,7 @@
|
||||
.cms table.ss-gridfield-table thead tr th.sortablerowsheading {
|
||||
border-bottom: 1px solid rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.cms table.ss-gridfield-table thead tr th.sortablerowsheading .gridfield-sortablerows button {
|
||||
display: none;
|
||||
}
|
43
javascript/GridFieldSortableRows.js
Normal file
43
javascript/GridFieldSortableRows.js
Normal file
@ -0,0 +1,43 @@
|
||||
(function($) {
|
||||
$('.ss-gridfield .gridfield-sortablerows input').entwine({
|
||||
onmatch: function() {
|
||||
var refCheckbox=$(this);
|
||||
|
||||
var gridField=$(this).getGridField();
|
||||
gridField.find('tbody').sortable({
|
||||
disabled: ($(this).is(':checked')==false),
|
||||
helper: function(e, ui) {
|
||||
//Maintains width of the columns
|
||||
ui.children().each(function() {
|
||||
$(this).width($(this).width());
|
||||
});
|
||||
|
||||
return ui;
|
||||
},
|
||||
update: function(event, ui) {
|
||||
var dataRows=[];
|
||||
var gridItems=gridField.getItems();
|
||||
var button=refCheckbox.parent().find('.sortablerows_toggle');
|
||||
|
||||
|
||||
for(var i=0;i<gridItems.length;i++) {
|
||||
dataRows[i]=$(gridItems[i]).data('id');
|
||||
}
|
||||
|
||||
|
||||
gridField.reload({data: [{name: button.attr('name'), value: button.val()}, {name: 'Items', value: dataRows}]});
|
||||
}
|
||||
}).disableSelection();
|
||||
},
|
||||
|
||||
onchange: function(e) {
|
||||
var gridField=$(this).getGridField();
|
||||
gridField.find('tbody').sortable('option', 'disabled', ($(this).is(':checked')==false));
|
||||
gridField.setState('GridFieldSortableRows', {sortableToggle: $(this).is(':checked')});
|
||||
|
||||
|
||||
var button=$(this).parent().find('.sortablerows_disablepagenator');
|
||||
gridField.reload({data: [{name: button.attr('name'), value: button.val()}]});
|
||||
}
|
||||
});
|
||||
})(jQuery);
|
9
templates/Includes/GridFieldSortableRows.ss
Normal file
9
templates/Includes/GridFieldSortableRows.ss
Normal file
@ -0,0 +1,9 @@
|
||||
<tr>
|
||||
<th class="extra sortablerowsheading" colspan="$Colspan">
|
||||
<div class="gridfield-sortablerows">
|
||||
<input type="checkbox" value="1"$Checked/> Allow drag and drop re-ordering
|
||||
$SortableToggle
|
||||
$PagenatorToggle
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
Loading…
Reference in New Issue
Block a user