Compare commits
210 Commits
Author | SHA1 | Date |
---|---|---|
UndefinedOffset | f6ce5741ab | |
UndefinedOffset | b1febae3d8 | |
UndefinedOffset | 9e5908c4ef | |
UndefinedOffset | 09f7be61ae | |
UndefinedOffset | 402dab8faa | |
UndefinedOffset | bb65d01748 | |
UndefinedOffset | e3d92e774a | |
UndefinedOffset | 237716571f | |
UndefinedOffset | 3940a7475f | |
UndefinedOffset | 29957be873 | |
UndefinedOffset | c3915cc2b8 | |
UndefinedOffset | 255347b755 | |
UndefinedOffset | eabbe33342 | |
Ed Chipman | f5a5346349 | |
UndefinedOffset | 66dfcc25ad | |
UndefinedOffset | 6f44c555cd | |
UndefinedOffset | 8ed1621f8b | |
UndefinedOffset | 5f37c8a0b4 | |
UndefinedOffset | e1b1bbf8b3 | |
UndefinedOffset | c965eb0c2e | |
Guy Sartorelli | e374c93ae3 | |
UndefinedOffset | fff3f08901 | |
Robbie Averill | 7bdeebb6cd | |
Samuel Mulliss | 6a14bfbcc1 | |
Ed Chipman | 51c43642ff | |
Steve Boyd | c3d202d4a0 | |
Ed Chipman | ee5f10e1e7 | |
Nicolaas | 902fe50c96 | |
Nicolaas | a0d1272238 | |
Nicolaas | f1a9c92784 | |
UndefinedOffset | 74756cad52 | |
UndefinedOffset | dd955ff1bb | |
Robbie Averill | 30b50a0597 | |
Nicolaas | 2e9d0e6b33 | |
UndefinedOffset | af492d0267 | |
UndefinedOffset | 35775ad2ce | |
UndefinedOffset | aef0a8acc1 | |
UndefinedOffset | 3ab5aadf45 | |
UndefinedOffset | a622fd4d6f | |
UndefinedOffset | cd86fe2fd4 | |
UndefinedOffset | fc83d6813e | |
UndefinedOffset | 8a2417a750 | |
UndefinedOffset | 504387d711 | |
UndefinedOffset | bc633e151d | |
UndefinedOffset | ae12e74aa8 | |
UndefinedOffset | 97b526ea87 | |
ChrissiQ | 118838fb79 | |
UndefinedOffset | 5e3e5cac3f | |
UndefinedOffset | dc11841e11 | |
UndefinedOffset | 6cfc1b7338 | |
UndefinedOffset | 20da27f7dd | |
UndefinedOffset | e53e3622a4 | |
UndefinedOffset | ecbe9b904a | |
UndefinedOffset | 12cd5776c1 | |
UndefinedOffset | e6eefdffd3 | |
Daniel Hensby | d8c379879f | |
UndefinedOffset | 8254ce7fe7 | |
UndefinedOffset | f0110c11e2 | |
UndefinedOffset | 0c66fa0ec6 | |
UndefinedOffset | fe104efad8 | |
UndefinedOffset | 21289b42f5 | |
UndefinedOffset | 2bde7362cd | |
UndefinedOffset | b70ec00945 | |
UndefinedOffset | 386fa1053d | |
UndefinedOffset | 710b94e25b | |
UndefinedOffset | 7e8cdd9c2b | |
UndefinedOffset | 9ea5caa91c | |
UndefinedOffset | b38d7f6f04 | |
UndefinedOffset | c537c86567 | |
UndefinedOffset | bf1f27e075 | |
UndefinedOffset | fc150881f2 | |
UndefinedOffset | c0c0518ae9 | |
UndefinedOffset | 0571a60875 | |
UndefinedOffset | 1925d5151e | |
UndefinedOffset | 5dc5bbc908 | |
UndefinedOffset | d3fd38e54c | |
UndefinedOffset | 775067ff93 | |
UndefinedOffset | 08a0781d56 | |
UndefinedOffset | 21a6f3c8e8 | |
UndefinedOffset | 2b03ab81f7 | |
UndefinedOffset | 684f0c8df6 | |
UndefinedOffset | e5d442cabe | |
UndefinedOffset | f0fbbd5650 | |
UndefinedOffset | 72d458c819 | |
Robbie Averill | 36dcdcef6b | |
Reece | 23da810b19 | |
Reece | 1862700761 | |
Reece | d88af0c513 | |
UndefinedOffset | 2d8cd6540f | |
UndefinedOffset | 2950efe6a6 | |
UndefinedOffset | 1750b7b45a | |
UndefinedOffset | d5fb2aaa9d | |
UndefinedOffset | 8ba6c2f3f6 | |
UndefinedOffset | 09b295d10d | |
UndefinedOffset | 06517fc3af | |
UndefinedOffset | 5f9610046e | |
UndefinedOffset | 1fecff9cc7 | |
UndefinedOffset | e8eb7994fc | |
UndefinedOffset | 94e916b4d9 | |
UndefinedOffset | 9acc93b361 | |
UndefinedOffset | 5d2aa717f3 | |
UndefinedOffset | 29e8996b4a | |
Matthias Schelling | d3cfda5fe1 | |
UndefinedOffset | bc38ff5693 | |
UndefinedOffset | 05637b8216 | |
UndefinedOffset | 6847bf2a42 | |
Damian Mooyman | 92dfcd0447 | |
Ingo Schommer | 372819a57a | |
UndefinedOffset | 0270e32c83 | |
UndefinedOffset | fc2e8e5538 | |
Ed Chipman | 62a744d48f | |
helpfulrobot | 69635d5070 | |
UndefinedOffset | 07e24d52e6 | |
Ed Chipman | 8f9201c696 | |
Ed Chipman | f921aff29d | |
Ed Chipman | 2f5cee4e36 | |
Ed Chipman | d37fdd2ea9 | |
Ed Chipman | 1eb946a8a5 | |
Ed Chipman | 9863a71380 | |
Ed Chipman | 7bd56c578d | |
Ed Chipman | 10a52463f4 | |
UndefinedOffset | c9ab0909f8 | |
UndefinedOffset | 925bc7c3f7 | |
Ed Chipman | a5d88c1f3f | |
UndefinedOffset | 01d03c61cf | |
helpfulrobot | 37fe9e4578 | |
Ed Chipman | 5e3802abe5 | |
helpfulrobot | 0ca027931f | |
Ed Chipman | e1b94a3bf3 | |
Peter Thaleikis | 1a55c0599c | |
UndefinedOffset | afffa5b09e | |
UndefinedOffset | b21e008b94 | |
UndefinedOffset | fa2731fea7 | |
UndefinedOffset | 4105ebdcd0 | |
UndefinedOffset | 51302bb0aa | |
UndefinedOffset | ebfaa26021 | |
Ed Chipman | c224c33173 | |
Ed Chipman | df26fe04a6 | |
UndefinedOffset | c7df1ab098 | |
UndefinedOffset | 74780bb110 | |
UndefinedOffset | 3893e7b052 | |
Ed Chipman | 089d4e796d | |
Ed Chipman | fae85f04c1 | |
Ed Chipman | 282ea74a76 | |
Ed Chipman | ddf5160891 | |
UndefinedOffset | e21c0d5790 | |
Daniel Hensby | 32cb8d67be | |
Ed Chipman | fe9b45bd3b | |
Ed Chipman | 5af763d05d | |
UndefinedOffset | e8ce22f9e9 | |
UndefinedOffset | 81e8fae97a | |
Ed Chipman | 9ce8bca316 | |
Dan Brooks | c6bd9e1878 | |
Ed Chipman | ff7a30825e | |
Matthew Hailwood | 70512329a1 | |
Ed Chipman | 3e9b1b6e2e | |
Aden Fraser | 68723005c8 | |
Ed Chipman | 9d60a58343 | |
UndefinedOffset | 946ca8dc9b | |
UndefinedOffset | b0d1ad1e9c | |
Ed Chipman | 2e9b7beffd | |
ismooth | 3dfe104b53 | |
Ed Chipman | 86d08f9757 | |
James Cocker | e493231556 | |
Ed Chipman | 81886ed81a | |
Ed Chipman | 3f1f5dbdb4 | |
Ed Chipman | 32a92e62f1 | |
UndefinedOffset | 97ca1f8f4d | |
UndefinedOffset | 1e24d1e888 | |
UndefinedOffset | 3f07ee7450 | |
Ed | c59ec68690 | |
UndefinedOffset | 278b6d6844 | |
Ed Chipman | 8b185cae3b | |
Ingo Schommer | e089a24856 | |
UndefinedOffset | 53efc6d9b1 | |
Ingo Schommer | ddbd0e0e3f | |
UndefinedOffset | e3895cc5ef | |
Ed | 15ead2ae94 | |
Ed | 9736c3a1a3 | |
Ed | eb1e736805 | |
Ed | 6ca5bf9a9d | |
Ed Chipman | 56b496509f | |
Ed Chipman | f0b711e1b5 | |
Ed Chipman | 73565ca916 | |
Pali Ondras | 0a1dda4009 | |
Tomas Bilek | c77d7148a5 | |
g4b0 | aa222987af | |
UndefinedOffset | 479325a5bc | |
Ed Chipman | 9240fa3193 | |
Simon Welsh | aa0b58f47a | |
Ed | 53eef90c97 | |
Ed | 1e963bfef1 | |
Ed | cd20fdf697 | |
Ed | f21e08f73e | |
Ed | 44cae7f0f6 | |
Ed | 830115fa4f | |
Ed | 8b10f39dce | |
Ed Chipman | 7cfeb8dc49 | |
Shrike | ee7251f93e | |
Ed Chipman | e33d57cb28 | |
Nicola Fontana | f3d6adf3b2 | |
Ed | f75ebaea34 | |
Ed | 60c8939f45 | |
Ed | fc2d17ace5 | |
Ed | a44c66dcb9 | |
Ed | 5af07ed75d | |
Ed | 4de269e53f | |
Ed | 4827b8e909 | |
UndefinedOffset | 399dc0ab89 | |
UndefinedOffset | efdaed9899 |
|
@ -0,0 +1,17 @@
|
|||
# For more information about the properties used in this file,
|
||||
# please see the EditorConfig documentation:
|
||||
# http://editorconfig.org
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[{*.yml,package.json}]
|
||||
indent_size = 2
|
||||
|
||||
# The indent size used in the package.json file cannot be changed:
|
||||
# https://github.com/npm/npm/pull/3180#issuecomment-16336516
|
|
@ -0,0 +1,5 @@
|
|||
/tests export-ignore
|
||||
/docs export-ignore
|
||||
/.gitignore export-ignore
|
||||
/.travis.yml export-ignore
|
||||
/.github export-ignore
|
|
@ -0,0 +1,14 @@
|
|||
## Affected Version
|
||||
|
||||
Show version numbers by pasting the output of `composer info --direct`.
|
||||
Alternatively, hover over the SilverStripe logo in the CMS to basic version information.
|
||||
|
||||
## Description
|
||||
|
||||
Describe expected and observed behaviour.
|
||||
For visual issues, please include browser version and screenshots.
|
||||
Please read https://docs.silverstripe.org/en/contributing/issues_and_bugs/
|
||||
|
||||
## Steps to Reproduce
|
||||
|
||||
Help us with step-by-step instructions.
|
|
@ -0,0 +1,5 @@
|
|||
Thanks for contributing, you're awesome! :star:
|
||||
Please describe expected and observed behaviour, and what you're fixing.
|
||||
For visual fixes, please include tested browsers and screenshots.
|
||||
Search for related existing issues and link to them if possible.
|
||||
Please read https://github.com/UndefinedOffset/SortableGridField/blob/master/CONTRIBUTING.md
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"problemMatcher": [
|
||||
{
|
||||
"owner": "phpcs",
|
||||
"severity": "error",
|
||||
"pattern": [
|
||||
{
|
||||
"regexp": "^<file name=\"(?:\\/github\\/workspace\\/)?(.*)\">$",
|
||||
"file": 1
|
||||
},
|
||||
{
|
||||
"regexp": "<error line=\"(\\d*)\" column=\"(\\d*)\" severity=\"(error|warning)\" message=\"(.*)\" source=\"(.*)(\"\\/>+)$",
|
||||
"line": 1,
|
||||
"column": 2,
|
||||
"severity": 3,
|
||||
"message": 4,
|
||||
"code": 5,
|
||||
"loop": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
|
@ -0,0 +1,241 @@
|
|||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ '**' ]
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
pull_request:
|
||||
branches: [ '**' ]
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
- '*.md'
|
||||
|
||||
|
||||
|
||||
jobs:
|
||||
silverstripe_5_php81:
|
||||
name: "Silverstripe 5.0 | PHP 8.1"
|
||||
runs-on: ubuntu-latest
|
||||
if: "!contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]')"
|
||||
env:
|
||||
php_version: 8.1
|
||||
php_extensions: ctype, dom, fileinfo, hash, intl, mbstring, session, simplexml, tokenizer, xml, pdo, mysqli, gd, zip
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:5.7
|
||||
env:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: false
|
||||
MYSQL_ROOT_PASSWORD: testpassword
|
||||
MYSQL_DATABASE: test_db
|
||||
ports:
|
||||
- 3306/tcp
|
||||
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP Extension Cache
|
||||
id: cache-env
|
||||
uses: shivammathur/cache-extensions@v1
|
||||
with:
|
||||
php-version: ${{ env.php_version }}
|
||||
extensions: ${{ env.php_extensions }}
|
||||
key: php74-ext-cache-${{ hashFiles('.github/workflows/ci.yml') }}
|
||||
|
||||
- name: Cache PHP Extensions
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ steps.cache-env.outputs.dir }}
|
||||
key: ${{ steps.cache-env.outputs.key }}
|
||||
restore-keys: ${{ steps.cache-env.outputs.key }}
|
||||
|
||||
- name: Setup PHP, with composer and extensions
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ env.php_version }}
|
||||
extensions: ${{ env.php_extensions }}
|
||||
ini-values: log_errors=On, error_log="${{github.workspace}}/artifacts/php_errors.log"
|
||||
coverage: none
|
||||
tools: composer:v2
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-composer-ss5-php81-${{ hashFiles('**/composer.json') }}-${{ hashFiles('.github/workflows/ci.yml') }}
|
||||
restore-keys: ${{ runner.os }}-composer-ss5-php81-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
env:
|
||||
GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
composer self-update --ansi || true
|
||||
if [[ $GITHUB_ACCESS_TOKEN ]]; then composer config --ansi -g github-oauth.github.com $GITHUB_ACCESS_TOKEN; fi
|
||||
composer config allow-plugins.composer/installers true
|
||||
composer config allow-plugins.silverstripe/recipe-plugin true
|
||||
composer config allow-plugins.silverstripe/vendor-plugin true
|
||||
composer require silverstripe/admin 2.0.* --no-update
|
||||
composer require silverstripe/versioned 2.0.*
|
||||
composer install --verbose --no-interaction --no-progress --no-suggest --optimize-autoloader --ansi
|
||||
|
||||
- name: Configure Environment
|
||||
run: |
|
||||
cp tests/utils/actions.env.template .env
|
||||
mkdir artifacts
|
||||
|
||||
- name: Perform PHPUnit Tests
|
||||
env:
|
||||
SS_DATABASE_PORT: ${{ job.services.mysql.ports['3306'] }}
|
||||
run: vendor/bin/phpunit --colors=always --printer UndefinedOffset\\SortableGridField\\Tests\\PHPUnit\\Bootstrap\\GitHubActionsAnnotatorPrinter
|
||||
|
||||
silverstripe_411_php80:
|
||||
name: "Silverstripe 4.11 | PHP 8.0"
|
||||
runs-on: ubuntu-latest
|
||||
if: "!contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]')"
|
||||
env:
|
||||
php_version: 8.0
|
||||
php_extensions: ctype, dom, fileinfo, hash, intl, mbstring, session, simplexml, tokenizer, xml, pdo, mysqli, gd, zip
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:5.7
|
||||
env:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: false
|
||||
MYSQL_ROOT_PASSWORD: testpassword
|
||||
MYSQL_DATABASE: test_db
|
||||
ports:
|
||||
- 3306/tcp
|
||||
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP Extension Cache
|
||||
id: cache-env
|
||||
uses: shivammathur/cache-extensions@v1
|
||||
with:
|
||||
php-version: ${{ env.php_version }}
|
||||
extensions: ${{ env.php_extensions }}
|
||||
key: php80-ext-cache-${{ hashFiles('.github/workflows/ci.yml') }}
|
||||
|
||||
- name: Cache PHP Extensions
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ steps.cache-env.outputs.dir }}
|
||||
key: ${{ steps.cache-env.outputs.key }}
|
||||
restore-keys: ${{ steps.cache-env.outputs.key }}
|
||||
|
||||
- name: Setup PHP, with composer and extensions
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ env.php_version }}
|
||||
extensions: ${{ env.php_extensions }}
|
||||
ini-values: log_errors=On, error_log="${{github.workspace}}/artifacts/php_errors.log"
|
||||
coverage: none
|
||||
tools: composer:v2
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-composer-ss411-php80-${{ hashFiles('**/composer.json') }}-${{ hashFiles('.github/workflows/ci.yml') }}
|
||||
restore-keys: ${{ runner.os }}-composer-ss411-php80-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
env:
|
||||
GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
composer self-update --ansi || true
|
||||
if [[ $GITHUB_ACCESS_TOKEN ]]; then composer config --ansi -g github-oauth.github.com $GITHUB_ACCESS_TOKEN; fi
|
||||
composer config allow-plugins.composer/installers true
|
||||
composer config allow-plugins.silverstripe/recipe-plugin true
|
||||
composer config allow-plugins.silverstripe/vendor-plugin true
|
||||
composer require silverstripe/admin 1.11.* --no-update
|
||||
composer require silverstripe/versioned 1.11.*
|
||||
composer install --verbose --no-interaction --no-progress --no-suggest --optimize-autoloader --ansi
|
||||
|
||||
- name: Configure Environment
|
||||
run: |
|
||||
cp tests/utils/actions.env.template .env
|
||||
mkdir artifacts
|
||||
|
||||
- name: Perform PHPUnit Tests
|
||||
env:
|
||||
SS_DATABASE_PORT: ${{ job.services.mysql.ports['3306'] }}
|
||||
run: vendor/bin/phpunit --colors=always --printer UndefinedOffset\\SortableGridField\\Tests\\PHPUnit\\Bootstrap\\GitHubActionsAnnotatorPrinter
|
||||
|
||||
phpcs:
|
||||
name: "PHP_CodeSniffer"
|
||||
runs-on: ubuntu-latest
|
||||
if: "!contains(github.event.head_commit.message, '[skip ci]') && !contains(github.event.head_commit.message, '[ci skip]')"
|
||||
env:
|
||||
php_version: 8.0
|
||||
php_extensions: ctype, dom, fileinfo, hash, intl, mbstring, session, simplexml, tokenizer, xml, pdo, mysqli, gd, zip
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Setup PHP Extension Cache
|
||||
id: cache-env
|
||||
uses: shivammathur/cache-extensions@v1
|
||||
with:
|
||||
php-version: ${{ env.php_version }}
|
||||
extensions: ${{ env.php_extensions }}
|
||||
key: php74-ext-cache-${{ hashFiles('.github/workflows/ci.yml') }}
|
||||
|
||||
- name: Cache PHP Extensions
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ steps.cache-env.outputs.dir }}
|
||||
key: ${{ steps.cache-env.outputs.key }}
|
||||
restore-keys: ${{ steps.cache-env.outputs.key }}
|
||||
|
||||
- name: Setup PHP, with composer and extensions
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ env.php_version }}
|
||||
extensions: ${{ env.php_extensions }}
|
||||
ini-values: log_errors=On, error_log="${{github.workspace}}/artifacts/php_errors.log"
|
||||
coverage: none
|
||||
tools: composer:v2
|
||||
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Cache composer dependencies
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-composer-phpcs-${{ hashFiles('.github/workflows/ci.yml') }}
|
||||
restore-keys: ${{ runner.os }}-composer-phpcs-
|
||||
|
||||
- name: Install Composer dependencies
|
||||
env:
|
||||
GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
rm composer.json
|
||||
composer self-update --ansi || true
|
||||
if [[ $GITHUB_ACCESS_TOKEN ]]; then composer config --ansi -g github-oauth.github.com $GITHUB_ACCESS_TOKEN; fi
|
||||
composer require squizlabs/php_codesniffer ~3.4
|
||||
composer install --verbose --no-interaction --no-progress --no-suggest --optimize-autoloader --ansi
|
||||
mkdir artifacts
|
||||
|
||||
- name: Validate Code Style
|
||||
run: vendor/bin/phpcs --colors --report=full --report-checkstyle=artifacts/phpcs.xml
|
||||
|
||||
- name: Annotate Code Style Issues
|
||||
if: failure()
|
||||
run: (test -f artifacts/phpcs.xml && echo "::add-matcher::.github/matchers/phpcs.json" && cat artifacts/phpcs.xml && echo "::remove-matcher owner=phpcs::")
|
|
@ -2,4 +2,5 @@
|
|||
/.buildpath
|
||||
/.project
|
||||
/.settings
|
||||
/.settings/*
|
||||
/.settings/*
|
||||
.phpunit.result.cache
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
inherit: true
|
||||
|
||||
checks:
|
||||
php:
|
||||
verify_property_names: true
|
||||
verify_argument_usable_as_reference: true
|
||||
verify_access_scope_valid: true
|
||||
useless_calls: true
|
||||
use_statement_alias_conflict: true
|
||||
variable_existence: true
|
||||
unused_variables: true
|
||||
unused_properties: true
|
||||
unused_parameters: true
|
||||
unused_methods: true
|
||||
unreachable_code: true
|
||||
too_many_arguments: true
|
||||
sql_injection_vulnerabilities: true
|
||||
simplify_boolean_return: true
|
||||
side_effects_or_types: true
|
||||
security_vulnerabilities: true
|
||||
return_doc_comments: true
|
||||
return_doc_comment_if_not_inferrable: true
|
||||
require_scope_for_properties: true
|
||||
require_scope_for_methods: true
|
||||
require_php_tag_first: true
|
||||
psr2_switch_declaration: true
|
||||
psr2_class_declaration: true
|
||||
property_assignments: true
|
||||
prefer_while_loop_over_for_loop: true
|
||||
precedence_mistakes: true
|
||||
precedence_in_conditions: true
|
||||
phpunit_assertions: true
|
||||
php5_style_constructor: true
|
||||
parse_doc_comments: true
|
||||
parameter_non_unique: true
|
||||
parameter_doc_comments: true
|
||||
param_doc_comment_if_not_inferrable: true
|
||||
optional_parameters_at_the_end: true
|
||||
one_class_per_file: true
|
||||
no_unnecessary_if: true
|
||||
no_trailing_whitespace: true
|
||||
no_property_on_interface: true
|
||||
no_non_implemented_abstract_methods: true
|
||||
no_error_suppression: true
|
||||
no_duplicate_arguments: true
|
||||
no_commented_out_code: true
|
||||
newline_at_end_of_file: true
|
||||
missing_arguments: true
|
||||
method_calls_on_non_object: true
|
||||
instanceof_class_exists: true
|
||||
foreach_traversable: true
|
||||
fix_line_ending: true
|
||||
fix_doc_comments: true
|
||||
duplication: true
|
||||
deprecated_code_usage: true
|
||||
deadlock_detection_in_loops: true
|
||||
code_rating: true
|
||||
closure_use_not_conflicting: true
|
||||
catch_class_exists: true
|
||||
blank_line_after_namespace_declaration: false
|
||||
avoid_multiple_statements_on_same_line: true
|
||||
avoid_duplicate_types: true
|
||||
avoid_conflicting_incrementers: true
|
||||
avoid_closing_tag: true
|
||||
assignment_of_null_return: true
|
||||
argument_type_checks: true
|
||||
|
||||
filter:
|
||||
paths: [src/*, tests/*]
|
|
@ -0,0 +1,42 @@
|
|||
language: php
|
||||
|
||||
dist: xenial
|
||||
|
||||
services:
|
||||
- mysql
|
||||
- postgresql
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/.composer/cache/files
|
||||
|
||||
matrix:
|
||||
include:
|
||||
- php: 5.6
|
||||
env: DB=MYSQL CORE_RELEASE=4.4.x-dev PHPUNIT_TEST=1
|
||||
- php: 7.1
|
||||
env: DB=MYSQL CORE_RELEASE=4.5.x-dev PHPUNIT_TEST=1 PDO=1
|
||||
- php: 7.2
|
||||
env: DB=PGSQL CORE_RELEASE=4.6.x-dev PHPUNIT_TEST=1
|
||||
- php: 7.3
|
||||
env: DB=MYSQL CORE_RELEASE=4.6.x-dev PHPUNIT_TEST=1
|
||||
- php: 7.4
|
||||
env: DB=MYSQL CORE_RELEASE=4.x-dev PHPUNIT_TEST=1
|
||||
|
||||
before_script:
|
||||
# Init PHP
|
||||
- composer self-update || true
|
||||
- phpenv rehash
|
||||
- phpenv config-rm xdebug.ini
|
||||
|
||||
# Install composer dependencies
|
||||
- composer validate
|
||||
- composer require --no-update silverstripe/recipe-core:$CORE_RELEASE
|
||||
- composer require --no-update phpunit/phpunit:^5.7
|
||||
# Fix for running phpunit 5 on php 7.4+
|
||||
- composer require --no-update sminnee/phpunit-mock-objects:^3
|
||||
- if [[ $DB == PGSQL ]]; then composer require silverstripe/postgresql:^2 --prefer-dist --no-update; fi
|
||||
- composer install --prefer-dist --no-interaction --no-progress --no-suggest --optimize-autoloader --verbose --profile
|
||||
|
||||
script:
|
||||
- vendor/bin/phpunit
|
|
@ -0,0 +1,8 @@
|
|||
[main]
|
||||
host = https://www.transifex.com
|
||||
|
||||
[silverstripe-sortablegridfield.master]
|
||||
file_filter = lang/<lang>.yml
|
||||
source_file = lang/en.yml
|
||||
source_lang = en
|
||||
type = YML
|
|
@ -0,0 +1,370 @@
|
|||
# Change Log
|
||||
|
||||
## [2.2.0](https://github.com/UndefinedOffset/SortableGridField/tree/2.2.0) (2023-05-08)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/2.1.0...2.2.0)
|
||||
|
||||
## [2.1.0](https://github.com/UndefinedOffset/SortableGridField/tree/2.1.0) (2022-07-06)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/2.0.9...2.1.0)
|
||||
|
||||
## [2.0.9](https://github.com/UndefinedOffset/SortableGridField/tree/2.0.9) (2021-07-19)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/2.0.8...2.0.9)
|
||||
|
||||
## [2.0.8](https://github.com/UndefinedOffset/SortableGridField/tree/2.0.8) (2019-01-08)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/2.0.7...2.0.8)
|
||||
|
||||
## [2.0.7](https://github.com/UndefinedOffset/SortableGridField/tree/2.0.7) (2018-12-13)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/2.0.6...2.0.7)
|
||||
|
||||
## [2.0.6](https://github.com/UndefinedOffset/SortableGridField/tree/2.0.6) (2018-07-04)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/2.0.5...2.0.6)
|
||||
|
||||
## [2.0.5](https://github.com/UndefinedOffset/SortableGridField/tree/2.0.5) (2018-06-07)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/2.0.4...2.0.5)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Int to DBInt [\#120](https://github.com/UndefinedOffset/SortableGridField/issues/120)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Fixes "undefined offset" error when moving a many\_many item to previous page [\#121](https://github.com/UndefinedOffset/SortableGridField/pull/121) ([ChrissiQ](https://github.com/ChrissiQ))
|
||||
|
||||
## [2.0.4](https://github.com/UndefinedOffset/SortableGridField/tree/2.0.4) (2018-03-07)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/2.0.3...2.0.4)
|
||||
|
||||
## [2.0.3](https://github.com/UndefinedOffset/SortableGridField/tree/2.0.3) (2018-03-01)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/2.0.2...2.0.3)
|
||||
|
||||
## [2.0.2](https://github.com/UndefinedOffset/SortableGridField/tree/2.0.2) (2017-12-11)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/2.0.1...2.0.2)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- many\_many ss 3.6 GridFieldAddNewMultiClass Column 'SortOrder' in field list is ambiguous [\#114](https://github.com/UndefinedOffset/SortableGridField/issues/114)
|
||||
- mapTableNameAndReturn can't parse namespace+classname into mysql tablename [\#113](https://github.com/UndefinedOffset/SortableGridField/issues/113)
|
||||
|
||||
## [2.0.1](https://github.com/UndefinedOffset/SortableGridField/tree/2.0.1) (2017-11-29)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/2.0.0...2.0.1)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Many Many relationships are broken due to renaming of many\_many and many\_many\_extraFields to manyMany and manyManyExtraFields [\#110](https://github.com/UndefinedOffset/SortableGridField/issues/110)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Merge 1.0.x into master [\#112](https://github.com/UndefinedOffset/SortableGridField/pull/112) ([dhensby](https://github.com/dhensby))
|
||||
- DOCS Update docs examples to be 3.1+ relevant [\#111](https://github.com/UndefinedOffset/SortableGridField/pull/111) ([dhensby](https://github.com/dhensby))
|
||||
|
||||
## [2.0.0](https://github.com/UndefinedOffset/SortableGridField/tree/2.0.0) (2017-11-24)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/2.0.0-beta2...2.0.0)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- SilverStripe 4 Compatibility [\#103](https://github.com/UndefinedOffset/SortableGridField/issues/103)
|
||||
|
||||
## [2.0.0-beta2](https://github.com/UndefinedOffset/SortableGridField/tree/2.0.0-beta2) (2017-11-01)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/1.0.0...2.0.0-beta2)
|
||||
|
||||
## [1.0.0](https://github.com/UndefinedOffset/SortableGridField/tree/1.0.0) (2017-10-27)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.6.10...1.0.0)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Remove tests against unsupported versions [\#97](https://github.com/UndefinedOffset/SortableGridField/issues/97)
|
||||
|
||||
## [0.6.10](https://github.com/UndefinedOffset/SortableGridField/tree/0.6.10) (2017-08-14)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/2.0.0-beta1...0.6.10)
|
||||
|
||||
## [2.0.0-beta1](https://github.com/UndefinedOffset/SortableGridField/tree/2.0.0-beta1) (2017-07-04)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/2.0.0-alpha1...2.0.0-beta1)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- No search capabilities when using in ModelAdmin [\#108](https://github.com/UndefinedOffset/SortableGridField/issues/108)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Remove closing PHP tag [\#107](https://github.com/UndefinedOffset/SortableGridField/pull/107) ([robbieaverill](https://github.com/robbieaverill))
|
||||
|
||||
## [2.0.0-alpha1](https://github.com/UndefinedOffset/SortableGridField/tree/2.0.0-alpha1) (2017-06-05)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.6.9...2.0.0-alpha1)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Tests required for tables with $table\_name declared [\#105](https://github.com/UndefinedOffset/SortableGridField/issues/105)
|
||||
|
||||
## [0.6.9](https://github.com/UndefinedOffset/SortableGridField/tree/0.6.9) (2017-04-21)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.6.8...0.6.9)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Query errors when sorted field is on a relation and appending to top [\#101](https://github.com/UndefinedOffset/SortableGridField/issues/101)
|
||||
|
||||
## [0.6.8](https://github.com/UndefinedOffset/SortableGridField/tree/0.6.8) (2017-04-18)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.6.7...0.6.8)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Typo error [\#100](https://github.com/UndefinedOffset/SortableGridField/issues/100)
|
||||
|
||||
## [0.6.7](https://github.com/UndefinedOffset/SortableGridField/tree/0.6.7) (2017-04-13)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.6.6...0.6.7)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Wrong sort field type check [\#99](https://github.com/UndefinedOffset/SortableGridField/issues/99)
|
||||
|
||||
## [0.6.6](https://github.com/UndefinedOffset/SortableGridField/tree/0.6.6) (2017-04-12)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.6.5...0.6.6)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Not working with SS3.5 fresh install [\#98](https://github.com/UndefinedOffset/SortableGridField/issues/98)
|
||||
|
||||
## [0.6.5](https://github.com/UndefinedOffset/SortableGridField/tree/0.6.5) (2016-11-24)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.6.4...0.6.5)
|
||||
|
||||
## [0.6.4](https://github.com/UndefinedOffset/SortableGridField/tree/0.6.4) (2016-11-22)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.6.3...0.6.4)
|
||||
|
||||
## [0.6.3](https://github.com/UndefinedOffset/SortableGridField/tree/0.6.3) (2016-11-18)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.6.2...0.6.3)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Use Sort of GridField Header [\#96](https://github.com/UndefinedOffset/SortableGridField/pull/96) ([schellmax](https://github.com/schellmax))
|
||||
|
||||
## [0.6.2](https://github.com/UndefinedOffset/SortableGridField/tree/0.6.2) (2016-06-09)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.6.1...0.6.2)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Drag and Drop Checkbox can't be selected [\#90](https://github.com/UndefinedOffset/SortableGridField/issues/90)
|
||||
- Issue edit and Adding New Gallery Holder Page and Gallery Page [\#89](https://github.com/UndefinedOffset/SortableGridField/issues/89)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- BUG Remove redundant leading underscore in strings [\#95](https://github.com/UndefinedOffset/SortableGridField/pull/95) ([tractorcow](https://github.com/tractorcow))
|
||||
- Test against 3.3 core and PHP 5.6 [\#93](https://github.com/UndefinedOffset/SortableGridField/pull/93) ([chillu](https://github.com/chillu))
|
||||
- Added standard Scrutinizer config [\#91](https://github.com/UndefinedOffset/SortableGridField/pull/91) ([helpfulrobot](https://github.com/helpfulrobot))
|
||||
|
||||
## [0.6.1](https://github.com/UndefinedOffset/SortableGridField/tree/0.6.1) (2016-03-03)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.6.0...0.6.1)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Unit tests failing with framework 3.2.3 [\#88](https://github.com/UndefinedOffset/SortableGridField/issues/88)
|
||||
|
||||
## [0.6.0](https://github.com/UndefinedOffset/SortableGridField/tree/0.6.0) (2016-02-13)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.5.4...0.6.0)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Can't set checkbox "Allow drag and drop re-ordering" [\#76](https://github.com/UndefinedOffset/SortableGridField/issues/76)
|
||||
- Investigate build failures for PostgreSQL on 3.1 and 3.2 [\#87](https://github.com/UndefinedOffset/SortableGridField/issues/87)
|
||||
- Multiple many\_many GridFields acting on the same relation not possible. [\#86](https://github.com/UndefinedOffset/SortableGridField/issues/86)
|
||||
- Expand unit test to cover page sorting [\#85](https://github.com/UndefinedOffset/SortableGridField/issues/85)
|
||||
|
||||
## [0.5.4](https://github.com/UndefinedOffset/SortableGridField/tree/0.5.4) (2016-01-18)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.5.3...0.5.4)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Support for 3.3 [\#84](https://github.com/UndefinedOffset/SortableGridField/issues/84)
|
||||
- Lithuanian translation [\#83](https://github.com/UndefinedOffset/SortableGridField/issues/83)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Added standard .gitattributes file [\#82](https://github.com/UndefinedOffset/SortableGridField/pull/82) ([helpfulrobot](https://github.com/helpfulrobot))
|
||||
- Added standard .editorconfig file [\#80](https://github.com/UndefinedOffset/SortableGridField/pull/80) ([helpfulrobot](https://github.com/helpfulrobot))
|
||||
|
||||
## [0.5.3](https://github.com/UndefinedOffset/SortableGridField/tree/0.5.3) (2015-12-10)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.5.2...0.5.3)
|
||||
|
||||
## [0.5.2](https://github.com/UndefinedOffset/SortableGridField/tree/0.5.2) (2015-11-30)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.5.1...0.5.2)
|
||||
|
||||
## [0.5.1](https://github.com/UndefinedOffset/SortableGridField/tree/0.5.1) (2015-10-09)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.5.0...0.5.1)
|
||||
|
||||
## [0.5.0](https://github.com/UndefinedOffset/SortableGridField/tree/0.5.0) (2015-09-18)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.4.5...0.5.0)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Change install instructions to prefer composer [\#75](https://github.com/UndefinedOffset/SortableGridField/issues/75)
|
||||
- Helper Columns do not maintain the widths of the item being dragged [\#74](https://github.com/UndefinedOffset/SortableGridField/issues/74)
|
||||
- Improved UI for moving to another page [\#72](https://github.com/UndefinedOffset/SortableGridField/issues/72)
|
||||
|
||||
## [0.4.5](https://github.com/UndefinedOffset/SortableGridField/tree/0.4.5) (2015-08-29)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.4.4...0.4.5)
|
||||
|
||||
## [0.4.4](https://github.com/UndefinedOffset/SortableGridField/tree/0.4.4) (2015-08-05)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.4.3...0.4.4)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- 3.2 compat? [\#73](https://github.com/UndefinedOffset/SortableGridField/issues/73)
|
||||
- Doesn't respect Dataobject's $default\_sort DESC [\#60](https://github.com/UndefinedOffset/SortableGridField/issues/60)
|
||||
|
||||
## [0.4.3](https://github.com/UndefinedOffset/SortableGridField/tree/0.4.3) (2015-05-07)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.4.2...0.4.3)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- setAppendToTop\(\) Does Not Work When the DataObjects Within the GridField are not Part of a RelationList [\#71](https://github.com/UndefinedOffset/SortableGridField/issues/71)
|
||||
- \(Drag and drop\) re-ordering over multiple pages [\#70](https://github.com/UndefinedOffset/SortableGridField/issues/70)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Allow installation anywhere by adding yml config [\#69](https://github.com/UndefinedOffset/SortableGridField/pull/69) ([danbroooks](https://github.com/danbroooks))
|
||||
|
||||
## [0.4.2](https://github.com/UndefinedOffset/SortableGridField/tree/0.4.2) (2015-04-07)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.4.1...0.4.2)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Add note for many\_many relations about the field name [\#66](https://github.com/UndefinedOffset/SortableGridField/issues/66)
|
||||
- Doesnt work for Sitetree descendants because of versioned dataobjects managed by ModelAdmin. [\#64](https://github.com/UndefinedOffset/SortableGridField/issues/64)
|
||||
- Error saving many to many relations [\#63](https://github.com/UndefinedOffset/SortableGridField/issues/63)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Allow 'disableSelection' to be disabled [\#68](https://github.com/UndefinedOffset/SortableGridField/pull/68) ([hailwood](https://github.com/hailwood))
|
||||
- Resets the classes of .odd, .even, .first and .last for gridfields when a update \(drop\) event occurs. [\#67](https://github.com/UndefinedOffset/SortableGridField/pull/67) ([AdenFraser](https://github.com/AdenFraser))
|
||||
|
||||
## [0.4.1](https://github.com/UndefinedOffset/SortableGridField/tree/0.4.1) (2014-10-27)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.4.0...0.4.1)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Sort column xxxxx must be an Int, column is of type [\#62](https://github.com/UndefinedOffset/SortableGridField/issues/62)
|
||||
|
||||
## [0.4.0](https://github.com/UndefinedOffset/SortableGridField/tree/0.4.0) (2014-10-16)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.3.2...0.4.0)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Column 'SortOrder' in field list is ambiguous in a Many\_Many relationship Gridfield [\#59](https://github.com/UndefinedOffset/SortableGridField/issues/59)
|
||||
- Sort column only updated when GridField is viewed [\#58](https://github.com/UndefinedOffset/SortableGridField/issues/58)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Initial sorting equals sortColumn [\#61](https://github.com/UndefinedOffset/SortableGridField/pull/61) ([ismooth](https://github.com/ismooth))
|
||||
- Fixes fixSortColumn's Random Initial Sorting [\#57](https://github.com/UndefinedOffset/SortableGridField/pull/57) ([purplespider](https://github.com/purplespider))
|
||||
|
||||
## [0.3.2](https://github.com/UndefinedOffset/SortableGridField/tree/0.3.2) (2014-08-02)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.3.1...0.3.2)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Gridfield sortable button [\#56](https://github.com/UndefinedOffset/SortableGridField/issues/56)
|
||||
- Problem with $belongs\_many\_many [\#55](https://github.com/UndefinedOffset/SortableGridField/issues/55)
|
||||
- setAppendToTop - Fatal error: Call to undefined method GridFieldSortableRows::create\(\) [\#54](https://github.com/UndefinedOffset/SortableGridField/issues/54)
|
||||
- Frontend not working / Error in Examples [\#52](https://github.com/UndefinedOffset/SortableGridField/issues/52)
|
||||
- Unable to toggle off, switched on by default [\#51](https://github.com/UndefinedOffset/SortableGridField/issues/51)
|
||||
- Duplicate Column names [\#50](https://github.com/UndefinedOffset/SortableGridField/issues/50)
|
||||
- Bug with pagination [\#38](https://github.com/UndefinedOffset/SortableGridField/issues/38)
|
||||
|
||||
## [0.3.1](https://github.com/UndefinedOffset/SortableGridField/tree/0.3.1) (2013-10-29)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.3.0...0.3.1)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Duplicate sort id's when fixing the sort with append\_to\_top [\#47](https://github.com/UndefinedOffset/SortableGridField/issues/47)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Chinese/Arabic/Te Reo translations [\#49](https://github.com/UndefinedOffset/SortableGridField/pull/49) ([chillu](https://github.com/chillu))
|
||||
- Transifex support [\#48](https://github.com/UndefinedOffset/SortableGridField/pull/48) ([chillu](https://github.com/chillu))
|
||||
|
||||
## [0.3.0](https://github.com/UndefinedOffset/SortableGridField/tree/0.3.0) (2013-10-22)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.2.1...0.3.0)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- is this available on composer/sivlerstripe addons? [\#45](https://github.com/UndefinedOffset/SortableGridField/issues/45)
|
||||
- Add Docs On Migration from Data Object Manager [\#16](https://github.com/UndefinedOffset/SortableGridField/issues/16)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- added slovak language [\#44](https://github.com/UndefinedOffset/SortableGridField/pull/44) ([silverstripesk](https://github.com/silverstripesk))
|
||||
- Append new items to the top by default [\#42](https://github.com/UndefinedOffset/SortableGridField/pull/42) ([g4b0](https://github.com/g4b0))
|
||||
|
||||
## [0.2.1](https://github.com/UndefinedOffset/SortableGridField/tree/0.2.1) (2013-09-03)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.2.0...0.2.1)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Create LICENSE [\#41](https://github.com/UndefinedOffset/SortableGridField/pull/41) ([simonwelsh](https://github.com/simonwelsh))
|
||||
|
||||
## [0.2.0](https://github.com/UndefinedOffset/SortableGridField/tree/0.2.0) (2013-08-04)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.1.3...0.2.0)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Breaks when used with GridFieldManyRelationHandler [\#40](https://github.com/UndefinedOffset/SortableGridField/issues/40)
|
||||
- \[REQUEST\] Event to indicate that there has been a change in sort order. [\#39](https://github.com/UndefinedOffset/SortableGridField/issues/39)
|
||||
- Moving to next page doesn't work in FF 20.0.1 [\#33](https://github.com/UndefinedOffset/SortableGridField/issues/33)
|
||||
|
||||
## [0.1.3](https://github.com/UndefinedOffset/SortableGridField/tree/0.1.3) (2013-07-10)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.1.2...0.1.3)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Partical Cache and sortColumn update [\#35](https://github.com/UndefinedOffset/SortableGridField/issues/35)
|
||||
- Add loading indicator to row sorting [\#34](https://github.com/UndefinedOffset/SortableGridField/issues/34)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Finnish language file [\#37](https://github.com/UndefinedOffset/SortableGridField/pull/37) ([mediaclinic](https://github.com/mediaclinic))
|
||||
- Added italian language [\#36](https://github.com/UndefinedOffset/SortableGridField/pull/36) ([ntd](https://github.com/ntd))
|
||||
|
||||
## [0.1.2](https://github.com/UndefinedOffset/SortableGridField/tree/0.1.2) (2013-04-26)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.1.1...0.1.2)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- An error occured while fetching data from the server Please try again later. [\#31](https://github.com/UndefinedOffset/SortableGridField/issues/31)
|
||||
|
||||
## [0.1.1](https://github.com/UndefinedOffset/SortableGridField/tree/0.1.1) (2013-04-19)
|
||||
[Full Changelog](https://github.com/UndefinedOffset/SortableGridField/compare/0.1.0...0.1.1)
|
||||
|
||||
**Closed issues:**
|
||||
|
||||
- Create a release tag [\#32](https://github.com/UndefinedOffset/SortableGridField/issues/32)
|
||||
|
||||
## [0.1.0](https://github.com/UndefinedOffset/SortableGridField/tree/0.1.0) (2013-03-29)
|
||||
**Closed issues:**
|
||||
|
||||
- SortOrder field on $has\_many relation [\#28](https://github.com/UndefinedOffset/SortableGridField/issues/28)
|
||||
- nested gridfield in 3.1 [\#27](https://github.com/UndefinedOffset/SortableGridField/issues/27)
|
||||
- Line 183 of the GridFieldSortableRows.php is producing problems [\#24](https://github.com/UndefinedOffset/SortableGridField/issues/24)
|
||||
- GridFieldSortableRowsTest::testSortActionWithAdminPermission No items to sort [\#23](https://github.com/UndefinedOffset/SortableGridField/issues/23)
|
||||
- Sorting on Extension classes [\#22](https://github.com/UndefinedOffset/SortableGridField/issues/22)
|
||||
- Drag&Drop button broke GridField - SS 3.1 - Latest SS 3.1 [\#21](https://github.com/UndefinedOffset/SortableGridField/issues/21)
|
||||
- Error "Sort column Sort Order must be an Int, column is of type Array" [\#20](https://github.com/UndefinedOffset/SortableGridField/issues/20)
|
||||
- 3.1 SQLQuery::aggregate\(\) doesn't work with limit set on SQLQuery [\#19](https://github.com/UndefinedOffset/SortableGridField/issues/19)
|
||||
- sortablegridfield not working with ss3.1 [\#18](https://github.com/UndefinedOffset/SortableGridField/issues/18)
|
||||
- make upgrading from SortableDataObject painless [\#15](https://github.com/UndefinedOffset/SortableGridField/issues/15)
|
||||
- IDE files should not be included in this repo [\#13](https://github.com/UndefinedOffset/SortableGridField/issues/13)
|
||||
- Adding GridFieldSortableRows to the wrong column causes massive data loss [\#12](https://github.com/UndefinedOffset/SortableGridField/issues/12)
|
||||
- Sort ModelAdmin GridFields [\#6](https://github.com/UndefinedOffset/SortableGridField/issues/6)
|
||||
- fixSortColumn doesn't always run [\#5](https://github.com/UndefinedOffset/SortableGridField/issues/5)
|
||||
- Optimize sorting in has\_many [\#4](https://github.com/UndefinedOffset/SortableGridField/issues/4)
|
||||
- dragdropcheckbox triggers 'changed' on form [\#3](https://github.com/UndefinedOffset/SortableGridField/issues/3)
|
||||
- sort order not being updated on delete [\#2](https://github.com/UndefinedOffset/SortableGridField/issues/2)
|
||||
- installation [\#1](https://github.com/UndefinedOffset/SortableGridField/issues/1)
|
||||
|
||||
**Merged pull requests:**
|
||||
|
||||
- Fixing undefined variable $dataList [\#30](https://github.com/UndefinedOffset/SortableGridField/pull/30) ([halkyon](https://github.com/halkyon))
|
||||
- FIX Do not use hardcoded IDs in tests, as records from fixture might not... [\#29](https://github.com/UndefinedOffset/SortableGridField/pull/29) ([patbolo](https://github.com/patbolo))
|
||||
- BUGFIX: Use config layer to check for decorated $db fields [\#26](https://github.com/UndefinedOffset/SortableGridField/pull/26) ([unclecheese](https://github.com/unclecheese))
|
||||
- Update code/forms/GridFieldSortableRows.php [\#25](https://github.com/UndefinedOffset/SortableGridField/pull/25) ([flxbot](https://github.com/flxbot))
|
||||
- Dutch language! [\#14](https://github.com/UndefinedOffset/SortableGridField/pull/14) ([ARNHOE](https://github.com/ARNHOE))
|
||||
- spanish translation. [\#11](https://github.com/UndefinedOffset/SortableGridField/pull/11) ([dospuntocero](https://github.com/dospuntocero))
|
||||
- BUGFIX Make sure it's possible to rename the module's directory without ... [\#10](https://github.com/UndefinedOffset/SortableGridField/pull/10) ([drzax](https://github.com/drzax))
|
||||
- German Translation [\#9](https://github.com/UndefinedOffset/SortableGridField/pull/9) ([PatrickElsing](https://github.com/PatrickElsing))
|
||||
- Update lang/en.yml [\#8](https://github.com/UndefinedOffset/SortableGridField/pull/8) ([PatrickElsing](https://github.com/PatrickElsing))
|
||||
- Renamed the Items array that is sent in post [\#7](https://github.com/UndefinedOffset/SortableGridField/pull/7) ([sheadawson](https://github.com/sheadawson))
|
|
@ -0,0 +1,11 @@
|
|||
Contributing
|
||||
=================
|
||||
## Translations
|
||||
|
||||
Translations of the natural language strings are managed through a third party translation interface, transifex.com. Newly added strings will be periodically uploaded there for translation, and any new translations will be merged back to the project source code.
|
||||
|
||||
Please use [https://www.transifex.com/projects/p/silverstripe-sortablegridfield](https://www.transifex.com/projects/p/silverstripe-sortablegridfield) to contribute translations, rather than sending pull requests with YAML files.
|
||||
|
||||
|
||||
## Reporting an issue
|
||||
When you're reporting an issue please ensure you specify what version of SilverStripe you are using i.e. 3.0.5, 3.1beta3, 3.0-master etc. Also be sure to include any JavaScript or PHP errors you receive, for PHP errors please ensure you include the full stack trace. Also please include your implementation code (where your setting up your grid field) as well as how you produced the issue. You may also be asked to provide some of the classes to aid in re-producing the issue. Stick with the issue, remember that you seen the issue not the maintainer of the module so it may take allot of questions to arrive at a fix or answer.
|
|
@ -0,0 +1,27 @@
|
|||
Copyright (c) 2024, Ed Chipman
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice, this
|
||||
list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
|
||||
Neither the name of Ed Chipman nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
138
README.md
138
README.md
|
@ -1,19 +1,42 @@
|
|||
SortableGridField
|
||||
=================
|
||||
|
||||
Adds drag and drop functionality to SilverStripe 3's GridField
|
||||
[![CI](https://github.com/UndefinedOffset/SortableGridField/actions/workflows/ci.yml/badge.svg)](https://github.com/UndefinedOffset/SortableGridField/actions/workflows/ci.yml)
|
||||
[![Latest Stable Version](https://poser.pugx.org/undefinedoffset/sortablegridfield/version.svg)](http://www.silverstripe.org/stable-download/)
|
||||
[![Latest Unstable Version](https://poser.pugx.org/undefinedoffset/sortablegridfield/v/unstable.svg)](https://packagist.org/packages/undefinedoffset/sortablegridfield)
|
||||
[![Total Downloads](https://poser.pugx.org/undefinedoffset/sortablegridfield/downloads.svg)](https://packagist.org/packages/undefinedoffset/sortablegridfield)
|
||||
[![License](https://poser.pugx.org/undefinedoffset/sortablegridfield/license.svg)](https://github.com/UndefinedOffset/SortableGridField/blob/master/LICENSE)
|
||||
|
||||
Adds drag and drop functionality to Silverstripe's GridField
|
||||
|
||||
## Requirements
|
||||
* SilverStripe 3.x
|
||||
|
||||
* Silverstripe 4.11+ or 5.0+
|
||||
|
||||
## Installation
|
||||
* Download the module from here https://github.com/UndefinedOffset/SortableGridField/archive/master.zip
|
||||
* Extract the downloaded archive into your site root so that the destination folder is called SortableGridField, opening the extracted folder should contain _config.php in the root along with other files/folders
|
||||
* Run dev/build?flush=all to regenerate the manifest
|
||||
* Upon entering the cms and using GridFieldSortableRows component for the first time you make need to add ?flush=all to the end of the address to force the templates to regenerate
|
||||
|
||||
Installation is supported via composer only
|
||||
|
||||
```sh
|
||||
composer require undefinedoffset/sortablegridfield
|
||||
```
|
||||
|
||||
* Run `dev/build?flush=all` to regenerate the manifest
|
||||
* Upon entering the cms and using `GridFieldSortableRows` component for the first time you make need to add `?flush=all`
|
||||
to the end of the address to force the templates to regenerate
|
||||
|
||||
## Usage
|
||||
To enable sorting on a has_many relationship set up an integer field on your data object. Also for has_many relationships make sure to set the $default_sort on the dataobject to this new integer field to ensure that the sort order is applied when the relationship is requested. For many_many relationships you must add a $many_many_extraFields static to the data object defining the relationship, see the SilverStripe documentation for more information on this. If you are using a many_many relationship you will need to do a custom getter to set the sort order of this relationship for use on the front end see bellow for an example. For new DataObjects you do not need to increment the Sort order yourself in your DataObject GridFieldSortableRows will automatically do this the next time the grid is displayed.
|
||||
|
||||
To enable sorting on a `has_many` relationship set up an integer field on your data object. Also for `has_many`
|
||||
relationships make sure to set the `$default_sort` on the `DataObject` to this new integer field to ensure that the sort
|
||||
order is applied when the relationship is requested. For `many_many` relationships you must add a
|
||||
`$many_many_extraFields` static to the `DataObject` defining the relationship, see the
|
||||
[SilverStripe documentation](https://docs.silverstripe.org/en/3/developer_guides/model/relations/#many-many)
|
||||
for more information on this. If you are using a `many_many` relationship you will need to do a custom getter to set the
|
||||
sort order of this relationship for use on the front end see below for an example. As well for `many_many` relationships
|
||||
the name of the GridField *must* be the same as the relationship name other wise error's will occur. For new
|
||||
`DataObject`s you do not need to increment the sort order yourself in your `DataObject`, `GridFieldSortableRows` will
|
||||
automatically do this the next time the grid is displayed.
|
||||
|
||||
```php
|
||||
public function getMyManyManyRelationship() {
|
||||
|
@ -21,23 +44,104 @@ public function getMyManyManyRelationship() {
|
|||
}
|
||||
```
|
||||
|
||||
|
||||
To enable drag and drop sorting on the grid field add the following to your grid field's config
|
||||
*Grid Field Config*
|
||||
To enable drag and drop sorting on the `GridField` add the following to your `GridField`'s config, also make sure you add
|
||||
the namespace `UndefinedOffset\SortableGridField\Forms` to your file.
|
||||
|
||||
```php
|
||||
//Namespace imports should be added to the top of your file
|
||||
use UndefinedOffset\SortableGridField\Forms\GridFieldSortableRows;
|
||||
|
||||
$myGridConfig->addComponent(new GridFieldSortableRows('{Column to store sort}'));
|
||||
```
|
||||
|
||||
To move an item to another page drag the row over the respective page button and release.
|
||||
To move an item to another page drag the row over the respective move to page button which appear on the left and right
|
||||
of the GridField and release.
|
||||
|
||||
#### Full code Examples
|
||||
* [has_many relationship] (https://github.com/UndefinedOffset/SortableGridField/blob/master/docs/HasManyExample.md)
|
||||
* [many_many relationship] (https://github.com/UndefinedOffset/SortableGridField/blob/master/docs/ManyManyExample.md)
|
||||
|
||||
## Migrating from SilverStripe 2.4 and Data Object Manager's SortableDataObject
|
||||
SortableGridField is not the same as SortableDataObject, since it is only a component of GridField it does not have the ability to catch the object when it is saved for the first time. So SortableGridField uses 1 as the first sort index because 0 is the default for an integer field/column in the database. For migrations from 2.4 with SortableDataObject you need to setup your DataObject based on the instructions above however you must name your sort column "SortOrder" to maintain your sort indexes defined by SortableDataObject. Then you need to run the following query on the table containing your sort field, for many_many relationships this will be something like {RelationshipClass}_{RelationshipName}. This query will maintain your sort order from SortableDataObject but increment the index by 1 giving it a starting number of 1.
|
||||
* [has_many relationship](https://github.com/UndefinedOffset/SortableGridField/blob/master/docs/HasManyExample.md)
|
||||
* [many_many relationship](https://github.com/UndefinedOffset/SortableGridField/blob/master/docs/ManyManyExample.md)
|
||||
* [ModelAdmin implementation](https://github.com/UndefinedOffset/SortableGridField/blob/master/docs/ModelAdminExample.md)
|
||||
|
||||
```sql
|
||||
UPDATE YourTable SET SortOrder=SortOrder+1;
|
||||
#### Events
|
||||
|
||||
`GridFieldSortableRows` provides 4 "events" `onBeforeGridFieldRowSort()`, `onAfterGridFieldRowSort()`,
|
||||
`onBeforeGridFieldPageSort()` and `onAfterGridFieldPageSort()`. These "events" are passed a clone of the `DataList`
|
||||
used in `GridFieldSortableRows`, in the case of page sorting this list has a limit that shows you the current page
|
||||
plus/minus one object. For `GridFieldSortableRows` that are on `ModelAdmin` descendants these events are called on the
|
||||
`ModelAdmin` if they do not have an owner `DataObject`, if you are using `GridFieldSortableRows` on a `GridField` for a
|
||||
`DataObject`'s relationship the events are called on that `DataObject`.
|
||||
|
||||
#### Appending to the top instead of the bottom
|
||||
|
||||
By default `GridFieldSortableRows` appends to the bottom of the list for performance on large data sets, however you can
|
||||
set new records to append new records to the top by calling `setAppendToTop(true)` on your `GridFieldSortableRows`
|
||||
instance.
|
||||
|
||||
```php
|
||||
//Namespace imports should be added to the top of your file
|
||||
use UndefinedOffset\SortableGridField\Forms\GridFieldSortableRows;
|
||||
|
||||
$myGridConfig->addComponent($sortable = new GridFieldSortableRows('SortOrder'));
|
||||
$sortable->setAppendToTop(true);
|
||||
```
|
||||
|
||||
#### Working with versioned records
|
||||
|
||||
By default `GridFieldSortableRows` does not update any other stage for versioned than the base stage. However you can
|
||||
enable this by calling `setUpdateVersionedStage()` and passing in the name of the stage you want to update along with
|
||||
the base stage. For example passing in "Live" will also update the "Live" stage when any sort happens.
|
||||
|
||||
```php
|
||||
//Namespace imports should be added to the top of your file
|
||||
use UndefinedOffset\SortableGridField\Forms\GridFieldSortableRows;
|
||||
|
||||
$myGridConfig->addComponent($sortable = new GridFieldSortableRows('SortOrder'));
|
||||
$sortable->setUpdateVersionedStage('Live');
|
||||
```
|
||||
|
||||
#### Overriding the default relationship name
|
||||
|
||||
By default the relationship name comes from the name of the `GridField`, however you can override this lookup by
|
||||
calling `setCustomRelationName()` and passing in the name of the relationship. This allows for you to have multiple
|
||||
`GridFields` on the same form interacting with the same `many_many` list maybe filtered slightly differently.
|
||||
|
||||
```php
|
||||
//Namespace imports should be added to the top of your file
|
||||
use UndefinedOffset\SortableGridField\Forms\GridFieldSortableRows;
|
||||
|
||||
$myGridConfig->addComponent($sortable = new GridFieldSortableRows('SortOrder'));
|
||||
$sortable->setCustomRelationName('MyRelationship');
|
||||
```
|
||||
|
||||
## Reporting an issue
|
||||
|
||||
When you're reporting an issue please ensure you specify what version of SilverStripe you are using i.e. 3.0.5,
|
||||
3.1beta3, 3.0-master etc. Also be sure to include any JavaScript or PHP errors you receive, for PHP errors please ensure
|
||||
you include the full stack trace. Also please include your implementation code (where your setting up your grid field)
|
||||
as well as how you produced the issue. You may also be asked to provide some of the classes to aid in re-producing the
|
||||
issue. Stick with the issue, remember that you seen the issue not the maintainer of the module so it may take a lot of
|
||||
questions to arrive at a fix or answer.
|
||||
|
||||
### Notes
|
||||
|
||||
* When using with GridFieldManyRelationHandler make sure that you add GridFieldSortableRows to your config before for
|
||||
example `GridFieldManyRelationHandler`:
|
||||
|
||||
```php
|
||||
//Namespace imports should be added to the top of your file
|
||||
use UndefinedOffset\SortableGridField\Forms\GridFieldSortableRows;
|
||||
|
||||
$config->addComponent(new GridFieldSortableRows('SortOrder'), 'GridFieldManyRelationHandler');
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
### Translations
|
||||
|
||||
Translations of the natural language strings are managed through a third party translation interface, transifex.com.
|
||||
Newly added strings will be periodically uploaded there for translation, and any new translations will be merged back to
|
||||
the project source code.
|
||||
|
||||
Please use [https://www.transifex.com/projects/p/silverstripe-sortablegridfield](https://www.transifex.com/projects/p/silverstripe-sortablegridfield)
|
||||
to contribute translations, rather than sending pull requests with YAML files.
|
||||
|
|
|
@ -1,3 +1 @@
|
|||
<?php
|
||||
define('SORTABLE_GRIDFIELD_BASE', basename(dirname(__FILE__)));
|
||||
?>
|
|
@ -1,465 +0,0 @@
|
|||
<?php
|
||||
/**
|
||||
* This component provides a checkbox which when checked enables drag-and-drop re-ordering of elements displayed in a {@link GridField}
|
||||
*
|
||||
* @package forms
|
||||
*/
|
||||
class GridFieldSortableRows implements GridField_HTMLProvider, GridField_ActionProvider, GridField_DataManipulator {
|
||||
protected $sortColumn;
|
||||
|
||||
/**
|
||||
* @param String $sortColumn Column that should be used to update the sort information
|
||||
*/
|
||||
public function __construct($sortColumn) {
|
||||
$this->sortColumn = $sortColumn;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
$dataList = $gridField->getList();
|
||||
|
||||
if(class_exists('UnsavedRelationList') && $dataList instanceof UnsavedRelationList) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$state = $gridField->State->GridFieldSortableRows;
|
||||
if(!is_bool($state->sortableToggle)) {
|
||||
$state->sortableToggle = false;
|
||||
}
|
||||
|
||||
//Ensure user can edit
|
||||
if(!singleton($gridField->getModelClass())->canEdit()){
|
||||
return array();
|
||||
}
|
||||
|
||||
|
||||
//Sort order toggle
|
||||
$sortOrderToggle = Object::create(
|
||||
'GridField_FormAction',
|
||||
$gridField,
|
||||
'sortablerows-toggle',
|
||||
_t('GridFieldSortableRows.ALLOW_DRAG_DROP', '_Allow drag and drop re-ordering'),
|
||||
'saveGridRowSort',
|
||||
null
|
||||
)->addExtraClass('sortablerows-toggle');
|
||||
|
||||
|
||||
//Disable Pagenator
|
||||
$disablePagenator = Object::create(
|
||||
'GridField_FormAction',
|
||||
$gridField,
|
||||
'sortablerows-disablepagenator',
|
||||
_t('GridFieldSortableRows.DISABLE_PAGINATOR', '_Disable Pagenator'),
|
||||
'sortableRowsDisablePaginator',
|
||||
null
|
||||
)->addExtraClass('sortablerows-disablepagenator');
|
||||
|
||||
|
||||
//Disable Pagenator
|
||||
$sortToPage = Object::create(
|
||||
'GridField_FormAction',
|
||||
$gridField,
|
||||
'sortablerows-sorttopage',
|
||||
_t('GridFieldSortableRows.SORT_TO_PAGE', '_Sort To Page'),
|
||||
'sortToPage',
|
||||
null
|
||||
)->addExtraClass('sortablerows-sorttopage');
|
||||
|
||||
|
||||
$data = array('SortableToggle' => $sortOrderToggle,
|
||||
'PagenatorToggle' => $disablePagenator,
|
||||
'SortToPage' => $sortToPage,
|
||||
'Checked' => ($state->sortableToggle == true ? ' checked = "checked"':''));
|
||||
|
||||
$forTemplate = new ArrayData($data);
|
||||
|
||||
|
||||
//Inject Requirements
|
||||
Requirements::css(SORTABLE_GRIDFIELD_BASE . '/css/GridFieldSortableRows.css');
|
||||
Requirements::javascript(SORTABLE_GRIDFIELD_BASE . '/javascript/GridFieldSortableRows.js');
|
||||
|
||||
|
||||
$args = array('Colspan' => count($gridField->getColumns()), 'ID' => $gridField->ID());
|
||||
|
||||
return array('header' => $forTemplate->renderWith('GridFieldSortableRows', $args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Manipulate the datalist as needed by this grid modifier.
|
||||
* @param GridField $gridField Grid Field Reference
|
||||
* @param SS_List $dataList Data List to adjust
|
||||
* @return DataList Modified Data List
|
||||
*/
|
||||
public function getManipulatedData(GridField $gridField, SS_List $dataList) {
|
||||
//Detect and correct items with a sort column value of 0 (push to bottom)
|
||||
$this->fixSortColumn($gridField, $dataList);
|
||||
|
||||
|
||||
$headerState = $gridField->State->GridFieldSortableHeader;
|
||||
$state = $gridField->State->GridFieldSortableRows;
|
||||
if ((!is_bool($state->sortableToggle) || $state->sortableToggle==false) && $headerState && !empty($headerState->SortColumn)) {
|
||||
return $dataList;
|
||||
}
|
||||
|
||||
if ($state->sortableToggle == true) {
|
||||
$gridField->getConfig()->removeComponentsByType('GridFieldFilterHeader');
|
||||
$gridField->getConfig()->removeComponentsByType('GridFieldSortableHeader');
|
||||
}
|
||||
|
||||
return $dataList->sort($this->sortColumn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects and corrects items with a sort column value of 0, by appending them to the bottom of the list
|
||||
* @param GridField $gridField Grid Field Reference
|
||||
* @param SS_List $dataList Data List of items to be checked
|
||||
*/
|
||||
protected function fixSortColumn($gridField, SS_List $dataList) {
|
||||
if(class_exists('UnsavedRelationList') && $dataList instanceof UnsavedRelationList) {
|
||||
return;
|
||||
}
|
||||
|
||||
$list=clone $dataList;
|
||||
$list=$list->alterDataQuery(function($query, SS_List $tmplist) {
|
||||
$query->limit(array());
|
||||
return $query;
|
||||
});
|
||||
|
||||
$many_many = ($list instanceof ManyManyList);
|
||||
if (!$many_many) {
|
||||
$sng=singleton($gridField->getModelClass());
|
||||
$fieldType=$sng->db($this->sortColumn);
|
||||
if(!$fieldType || !($fieldType=='Int' || is_subclass_of('Int', $fieldType))) {
|
||||
if(is_array($fieldType)) {
|
||||
user_error('Sort column '.$this->sortColumn.' could not be found in '.$gridField->getModelClass().'\'s ancestry', E_USER_ERROR);
|
||||
}else {
|
||||
user_error('Sort column '.$this->sortColumn.' must be an Int, column is of type '.$fieldType, E_USER_ERROR);
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$max = $list->Max($this->sortColumn);
|
||||
$list=$list->where('"'.$this->sortColumn.'"=0');
|
||||
if($list->Count()>0) {
|
||||
$owner = $gridField->Form->getRecord();
|
||||
$sortColumn = $this->sortColumn;
|
||||
$i = 1;
|
||||
|
||||
if ($many_many) {
|
||||
list($parentClass, $componentClass, $parentField, $componentField, $table) = $owner->many_many($gridField->getName());
|
||||
$extraFields=$owner->many_many_extraFields($gridField->getName());
|
||||
|
||||
if(!$extraFields || !array_key_exists($this->sortColumn, $extraFields) || !($extraFields[$this->sortColumn]=='Int' || is_subclass_of('Int', $extraFields[$this->sortColumn]))) {
|
||||
user_error('Sort column '.$this->sortColumn.' must be an Int, column is of type '.$fieldType, E_USER_ERROR);
|
||||
exit;
|
||||
}
|
||||
}else {
|
||||
//Find table containing the sort column
|
||||
$table=false;
|
||||
$class=$gridField->getModelClass();
|
||||
|
||||
$db = Config::inst()->get($class, "db", CONFIG::UNINHERITED);
|
||||
if(!empty($db) && array_key_exists($sortColumn, $db)) {
|
||||
$table=$class;
|
||||
}else {
|
||||
$classes=ClassInfo::ancestry($class, true);
|
||||
foreach($classes as $class) {
|
||||
$db = Config::inst()->get($class, "db", CONFIG::UNINHERITED);
|
||||
if(!empty($db) && array_key_exists($sortColumn, $db)) {
|
||||
$table=$class;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($table===false) {
|
||||
user_error('Sort column '.$this->sortColumn.' could not be found in '.$gridField->getModelClass().'\'s ancestry', E_USER_ERROR);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Start transaction if supported
|
||||
if(DB::getConn()->supportsTransactions()) {
|
||||
DB::getConn()->transactionStart();
|
||||
}
|
||||
|
||||
|
||||
foreach($list as $obj) {
|
||||
if($many_many) {
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn .'" = ' . ($max + $i)
|
||||
. ' WHERE "' . $componentField . '" = ' . $obj->ID . ' AND "' . $parentField . '" = ' . $owner->ID);
|
||||
}else {
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn . '" = ' . ($max + $i)
|
||||
. ' WHERE "ID" = '. $obj->ID);
|
||||
}
|
||||
|
||||
$i++;
|
||||
}
|
||||
|
||||
|
||||
//End transaction if supported
|
||||
if(DB::getConn()->supportsTransactions()) {
|
||||
DB::getConn()->transactionEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
return array('saveGridRowSort', 'sortableRowsDisablePaginator', 'sortToPage');
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
$gridField->getConfig()->removeComponentsByType('GridFieldFilterHeader');
|
||||
$gridField->getConfig()->removeComponentsByType('GridFieldSortableHeader');
|
||||
}
|
||||
|
||||
|
||||
if ($actionName == 'savegridrowsort') {
|
||||
return $this->saveGridRowSort($gridField, $data);
|
||||
} else if ($actionName == 'sorttopage') {
|
||||
return $this->sortToPage($gridField, $data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles saving of the row sort order
|
||||
* @param GridField $gridField Grid Field Reference
|
||||
* @param Array $data Data submitted in the request
|
||||
*/
|
||||
protected function saveGridRowSort(GridField $gridField, $data) {
|
||||
$dataList = $gridField->getList();
|
||||
|
||||
if(class_exists('UnsavedRelationList') && $dataList instanceof UnsavedRelationList) {
|
||||
user_error('Cannot sort an UnsavedRelationList', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if(!singleton($gridField->getModelClass())->canEdit()){
|
||||
throw new ValidationException(_t('GridFieldSortableRows.EditPermissionsFailure', "No edit permissions"),0);
|
||||
}
|
||||
|
||||
if (empty($data['ItemIDs'])) {
|
||||
user_error('No items to sort', E_USER_ERROR);
|
||||
}
|
||||
|
||||
$className = $gridField->getModelClass();
|
||||
$owner = $gridField->Form->getRecord();
|
||||
$items = clone $gridField->getList();
|
||||
$many_many = ($items instanceof ManyManyList);
|
||||
$sortColumn = $this->sortColumn;
|
||||
$pageOffset = 0;
|
||||
|
||||
if ($paginator = $gridField->getConfig()->getComponentsByType('GridFieldPaginator')->First()) {
|
||||
$pageState = $gridField->State->GridFieldPaginator;
|
||||
|
||||
if($pageState->currentPage && is_int($pageState->currentPage) && $pageState->currentPage>1) {
|
||||
$pageOffset = $paginator->getItemsPerPage() * ($pageState->currentPage - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($many_many) {
|
||||
list($parentClass, $componentClass, $parentField, $componentField, $table) = $owner->many_many($gridField->getName());
|
||||
}else {
|
||||
//Find table containing the sort column
|
||||
$table=false;
|
||||
$class=$gridField->getModelClass();
|
||||
$db = Config::inst()->get($class, "db", CONFIG::UNINHERITED);
|
||||
if(!empty($db) && array_key_exists($sortColumn, $db)) {
|
||||
$table=$class;
|
||||
}else {
|
||||
$classes=ClassInfo::ancestry($class, true);
|
||||
foreach($classes as $class) {
|
||||
$db = Config::inst()->get($class, "db", CONFIG::UNINHERITED);
|
||||
if(!empty($db) && array_key_exists($sortColumn, $db)) {
|
||||
$table=$class;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if($table===false) {
|
||||
user_error('Sort column '.$this->sortColumn.' could not be found in '.$gridField->getModelClass().'\'s ancestry', E_USER_ERROR);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Start transaction if supported
|
||||
if(DB::getConn()->supportsTransactions()) {
|
||||
DB::getConn()->transactionStart();
|
||||
}
|
||||
|
||||
|
||||
$ids = explode(',', $data['ItemIDs']);
|
||||
for($sort = 0;$sort<count($ids);$sort++) {
|
||||
$id = intval($ids[$sort]);
|
||||
if ($many_many) {
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn.'" = ' . (($sort + 1) + $pageOffset)
|
||||
. ' WHERE "' . $componentField . '" = ' . $id . ' AND "' . $parentField . '" = ' . $owner->ID);
|
||||
} else {
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn . '" = ' . (($sort + 1) + $pageOffset)
|
||||
. ' WHERE "ID" = '. $id);
|
||||
}
|
||||
}
|
||||
|
||||
//End transaction if supported
|
||||
if(DB::getConn()->supportsTransactions()) {
|
||||
DB::getConn()->transactionEnd();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles sorting across pages
|
||||
* @param GridField $gridField Grid Field Reference
|
||||
* @param Array $data Data submitted in the request
|
||||
*/
|
||||
protected function sortToPage(GridField $gridField, $data) {
|
||||
if (!$paginator = $gridField->getConfig()->getComponentsByType('GridFieldPaginator')->First()) {
|
||||
user_error('Paginator not detected', E_USER_ERROR);
|
||||
}
|
||||
|
||||
if (empty($data['ItemID'])) {
|
||||
user_error('No item to sort', E_USER_ERROR);
|
||||
}
|
||||
|
||||
if (empty($data['Target'])) {
|
||||
user_error('No target page', E_USER_ERROR);
|
||||
}
|
||||
|
||||
|
||||
$className = $gridField->getModelClass();
|
||||
$owner = $gridField->Form->getRecord();
|
||||
$items = clone $gridField->getList();
|
||||
$many_many = ($items instanceof ManyManyList);
|
||||
$sortColumn = $this->sortColumn;
|
||||
$targetItem = $items->byID(intval($data['ItemID']));
|
||||
|
||||
if (!$targetItem) {
|
||||
user_error('Target item not found', E_USER_ERROR);
|
||||
}
|
||||
|
||||
$currentPage = 1;
|
||||
|
||||
|
||||
$pageState = $gridField->State->GridFieldPaginator;
|
||||
if($pageState->currentPage && $pageState->currentPage>1) {
|
||||
$currentPage = $pageState->currentPage;
|
||||
}
|
||||
|
||||
|
||||
if ($many_many) {
|
||||
list($parentClass, $componentClass, $parentField, $componentField, $table) = $owner->many_many($gridField->getName());
|
||||
}
|
||||
|
||||
|
||||
if ($data['Target'] == 'previouspage') {
|
||||
$sortPositions = $items->limit($paginator->getItemsPerPage() + 1, ($paginator->getItemsPerPage() * ($currentPage - 1)) - 1)->column($sortColumn);
|
||||
} else if ($data['Target'] == 'nextpage') {
|
||||
$sortPositions = $items->limit($paginator->getItemsPerPage() + 1, $paginator->getItemsPerPage() * ($currentPage - 1))->column($sortColumn);
|
||||
} else {
|
||||
user_error('Not implemented: '.$data['Target'], E_USER_ERROR);
|
||||
}
|
||||
|
||||
|
||||
//Start transaction if supported
|
||||
if(DB::getConn()->supportsTransactions()) {
|
||||
DB::getConn()->transactionStart();
|
||||
}
|
||||
|
||||
if($data['Target']=='previouspage') {
|
||||
if ($many_many) {
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn.'" = ' . $sortPositions[0]
|
||||
. ' WHERE "' . $componentField . '" = ' . $targetItem->ID . ' AND "' . $parentField . '" = ' . $owner->ID);
|
||||
} else {
|
||||
$targetItem->$sortColumn = $sortPositions[0];
|
||||
$targetItem->write();
|
||||
}
|
||||
|
||||
|
||||
$i = 1;
|
||||
foreach ($items as $obj) {
|
||||
if ($obj->ID == $targetItem->ID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if ($many_many) {
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn.'" = ' . $sortPositions[$i]
|
||||
. ' WHERE "' . $componentField . '" = ' . $obj->ID . ' AND "' . $parentField . '" = ' . $owner->ID);
|
||||
} else {
|
||||
$obj->$sortColumn = $sortPositions[$i];
|
||||
$obj->write();
|
||||
}
|
||||
|
||||
$i++;
|
||||
}
|
||||
} else {
|
||||
if ($many_many) {
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn.'" = ' . $sortPositions[count($sortPositions) - 1]
|
||||
. ' WHERE "' . $componentField . '" = ' . $targetItem->ID . ' AND "' . $parentField . '" = ' . $owner->ID);
|
||||
} else {
|
||||
$targetItem->$sortColumn = $sortPositions[count($sortPositions) - 1];
|
||||
$targetItem->write();
|
||||
}
|
||||
|
||||
|
||||
$i = 0;
|
||||
foreach ($items as $obj) {
|
||||
if ($obj->ID == $targetItem->ID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if ($many_many) {
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn.'" = ' . $sortPositions[$i]
|
||||
. ' WHERE "' . $componentField . '" = ' . $obj->ID . ' AND "' . $parentField . '" = ' . $owner->ID);
|
||||
} else {
|
||||
$obj->$sortColumn = $sortPositions[$i];
|
||||
$obj->write();
|
||||
}
|
||||
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//End transaction if supported
|
||||
if(DB::getConn()->supportsTransactions()) {
|
||||
DB::getConn()->transactionEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -1,8 +1,9 @@
|
|||
{
|
||||
"name": "undefinedoffset/sortablegridfield",
|
||||
"description": "Adds drag and drop functionality to SilverStripe 3.0's GridField",
|
||||
"type": "silverstripe-module",
|
||||
"keywords": ["silverstripe", "gridfield"],
|
||||
"description": "Adds drag and drop functionality to Silverstripe's GridField",
|
||||
"type": "silverstripe-vendormodule",
|
||||
"keywords": ["silverstripe", "gridfield", "sortable", "sort"],
|
||||
"license": "BSD-3-Clause",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Ed Chipman",
|
||||
|
@ -10,15 +11,33 @@
|
|||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
"require":
|
||||
{
|
||||
"silverstripe/framework": "3.*",
|
||||
"composer/installers": "*"
|
||||
"require": {
|
||||
"silverstripe/framework": "~4.11 | ^5",
|
||||
"silverstripe/versioned": "^1 | ^2"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"squizlabs/php_codesniffer": "~3.4"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"UndefinedOffset\\SortableGridField\\": "src/",
|
||||
"UndefinedOffset\\SortableGridField\\Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"support": {
|
||||
"issues": "https://github.com/undefinedoffset/SortableGridField/issues"
|
||||
},
|
||||
"extra": {
|
||||
"installer-name": "sortablegridfield"
|
||||
}
|
||||
"installer-name": "sortablegridfield",
|
||||
"expose": [
|
||||
"css",
|
||||
"javascript"
|
||||
],
|
||||
"branch-alias": {
|
||||
"dev-master": "2.0.x-dev"
|
||||
}
|
||||
},
|
||||
"prefer-stable": true,
|
||||
"minimum-stability": "dev"
|
||||
}
|
||||
|
|
|
@ -1,23 +1,134 @@
|
|||
.cms table.ss-gridfield-table thead tr th.sortablerowsheading {
|
||||
form table.grid-field__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 input[type=checkbox] {
|
||||
form table.grid-field__table thead tr td.sortablerowsheading label {
|
||||
margin-bottom: 0;
|
||||
|
||||
line-height: normal;
|
||||
}
|
||||
|
||||
form table.grid-field__table thead tr td.sortablerowsheading .gridfield-sortablerows input[type=checkbox] {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.cms table.ss-gridfield-table thead tr th.sortablerowsheading .gridfield-sortablerows {
|
||||
form table.grid-field__table thead tr td.sortablerowsheading .gridfield-sortablerows {
|
||||
line-height: 28px;
|
||||
}
|
||||
|
||||
.cms table.ss-gridfield-table thead tr th.sortablerowsheading .gridfield-sortablerows button {
|
||||
form table.grid-field__table thead tr td.sortablerowsheading .gridfield-sortablerows button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.cms table.ss-gridfield-table.dragSorting tbody tr td {
|
||||
form .ss-gridfield {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
form .ss-gridfield .gridfield-sortablerows-movepage .sortablerows-psort-arrow {
|
||||
background: #5589A7;
|
||||
|
||||
display: none;
|
||||
|
||||
font-weight: bold;
|
||||
color: #FFFFFF;
|
||||
|
||||
position: absolute;
|
||||
|
||||
width: 40px;
|
||||
|
||||
opacity: 0.6;
|
||||
|
||||
text-align: center;
|
||||
|
||||
line-height: normal;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
z-index: 2000;
|
||||
}
|
||||
|
||||
form .ss-gridfield .gridfield-sortablerows-movepage .sortablerows-psort-arrow i {
|
||||
display: block;
|
||||
|
||||
position: relative;
|
||||
|
||||
font-style: normal;
|
||||
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
form .ss-gridfield .gridfield-sortablerows-movepage .sortablerows-psort-arrow i:before {
|
||||
display: block;
|
||||
|
||||
content: " ";
|
||||
|
||||
position: absolute;
|
||||
top: -30px;
|
||||
left: 50%;
|
||||
|
||||
height: 0;
|
||||
width: 0;
|
||||
|
||||
border: solid transparent;
|
||||
border-width: 14px;
|
||||
border-bottom-color: #FFFFFF;
|
||||
|
||||
margin-left: -8px;
|
||||
}
|
||||
|
||||
form .ss-gridfield .gridfield-sortablerows-movepage .sortablerows-psort-arrow:hover {
|
||||
opacity: 0.8;
|
||||
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
form .ss-gridfield .gridfield-sortablerows-movepage .sortablerows-prev-page {
|
||||
left: -20px;
|
||||
}
|
||||
|
||||
form .ss-gridfield .gridfield-sortablerows-movepage .sortablerows-prev-page i {
|
||||
left: 20px;
|
||||
|
||||
-o-transform: rotate(270deg) translateX(-50%);
|
||||
-ms-transform: rotate(270deg) translateX(-50%);
|
||||
-moz-transform: rotate(270deg) translateX(-50%);
|
||||
-webkit-transform: rotate(270deg) translateX(-50%);
|
||||
transform: rotate(270deg) translateX(-50%);
|
||||
|
||||
-o-transform-origin: top left;
|
||||
-ms-transform-origin: top left;
|
||||
-moz-transform-origin: top left;
|
||||
-webkit-transform-origin: top left;
|
||||
transform-origin: top left;
|
||||
}
|
||||
|
||||
form .ss-gridfield .gridfield-sortablerows-movepage .sortablerows-next-page {
|
||||
right: -20px;
|
||||
}
|
||||
|
||||
form .ss-gridfield .gridfield-sortablerows-movepage .sortablerows-next-page i {
|
||||
right: 36px;
|
||||
|
||||
-moz-transform: rotate(90deg) translateX(50%);
|
||||
-o-transform: rotate(90deg) translateX(50%);
|
||||
-ms-transform: rotate(90deg) translateX(50%);
|
||||
-webkit-transform: rotate(90deg) translateX(50%);
|
||||
transform: rotate(90deg) translateX(50%);
|
||||
|
||||
-o-transform-origin: bottom right;
|
||||
-ms-transform-origin: bottom right;
|
||||
-moz-transform-origin: bottom right;
|
||||
-webkit-transform-origin: bottom right;
|
||||
transform-origin: bottom right;
|
||||
}
|
||||
|
||||
form table.grid-field__table.dragSorting tbody tr td {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
.cms table.ss-gridfield-table .datagrid-pagination button.sortablerows-droptarget {
|
||||
background-image: url(./../images/pagination-arrows-drop.gif) !important;
|
||||
form table.grid-field__table.dragSorting .ui-sortable-helper {
|
||||
display: table;
|
||||
}
|
|
@ -1,32 +1,58 @@
|
|||
has_many Example
|
||||
=================
|
||||
|
||||
```php
|
||||
|
||||
/*** TestPage.php ***/
|
||||
class TestPage extends Page {
|
||||
public static $has_many=array(
|
||||
'TestObjects'=>'TestObject'
|
||||
);
|
||||
|
||||
public function getCMSFields() {
|
||||
$fields=parent::getCMSFields();
|
||||
|
||||
$conf=GridFieldConfig_RelationEditor::create(10);
|
||||
$conf->addComponent(new GridFieldSortableRows('SortOrder'));
|
||||
|
||||
$fields->addFieldToTab('Root.TestObjects', new GridField('TestObjects', 'TestObjects', $this->TestObjects(), $conf));
|
||||
|
||||
return $fields;
|
||||
}
|
||||
use SilverStripe\Forms\GridField\GridField;
|
||||
use SilverStripe\Forms\GridField\GridFieldConfig_RelationEditor;
|
||||
use UndefinedOffset\SortableGridField\Forms\GridFieldSortableRows;
|
||||
|
||||
class TestPage extends Page
|
||||
{
|
||||
private static $has_many = [
|
||||
'TestObjects' => 'TestObject',
|
||||
];
|
||||
|
||||
public function getCMSFields()
|
||||
{
|
||||
$fields = parent::getCMSFields();
|
||||
|
||||
$conf = GridFieldConfig_RelationEditor::create(10);
|
||||
$conf->addComponent(GridFieldSortableRows::create('SortOrder'));
|
||||
|
||||
$fields->addFieldToTab(
|
||||
'Root.TestObjects',
|
||||
GridField::create(
|
||||
'TestObjects',
|
||||
'TestObjects',
|
||||
$this->TestObjects(),
|
||||
$conf
|
||||
)
|
||||
);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*** TestObject.php ***/
|
||||
class TestObject extends DataObject {
|
||||
public static $db=array(
|
||||
'Title'=>'Text',
|
||||
'SortOrder'=>'Int'
|
||||
);
|
||||
|
||||
public static $default_sort='SortOrder';
|
||||
use SilverStripe\ORM\DataObject;
|
||||
|
||||
class TestObject extends DataObject
|
||||
{
|
||||
private static $db = [
|
||||
'Title' => 'Text',
|
||||
'SortOrder' => 'Int',
|
||||
];
|
||||
|
||||
private static $indexes = [
|
||||
'SortOrder' => true,
|
||||
];
|
||||
private static $has_one = [
|
||||
'Parent' => 'TestPage',
|
||||
];
|
||||
|
||||
private static $default_sort = 'SortOrder';
|
||||
}
|
||||
```
|
||||
```
|
||||
|
|
|
@ -1,44 +1,55 @@
|
|||
many_many Example
|
||||
=================
|
||||
|
||||
```php
|
||||
/*** TestPage.php ***/
|
||||
class TestPage extends Page {
|
||||
public static $many_many=array(
|
||||
'TestObjects'=>'TestObject'
|
||||
);
|
||||
|
||||
public static $many_many_extraFields=array(
|
||||
'TestObjects'=>array(
|
||||
'SortOrder'=>'Int'
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
public function getCMSFields() {
|
||||
$fields=parent::getCMSFields();
|
||||
|
||||
$conf=GridFieldConfig_RelationEditor::create(10);
|
||||
$conf->addComponent(new GridFieldSortableRows('SortOrder'));
|
||||
|
||||
$fields->addFieldToTab('Root.TestObjects', new GridField('TestObjects', 'TestObjects', $this->TestObjects(), $conf));
|
||||
|
||||
use SilverStripe\Forms\GridField\GridField;
|
||||
use SilverStripe\Forms\GridField\GridFieldConfig_RelationEditor;
|
||||
use UndefinedOffset\SortableGridField\Forms\GridFieldSortableRows;
|
||||
|
||||
class TestPage extends Page
|
||||
{
|
||||
private static $many_many = [
|
||||
'TestObjects' => 'TestObject',
|
||||
];
|
||||
|
||||
private static $many_many_extraFields = [
|
||||
'TestObjects' => [
|
||||
'SortOrder' => 'Int',
|
||||
]
|
||||
];
|
||||
|
||||
|
||||
public function getCMSFields()
|
||||
{
|
||||
$fields = parent::getCMSFields();
|
||||
|
||||
$conf = GridFieldConfig_RelationEditor::create(10);
|
||||
$conf->addComponent(GridFieldSortableRows::create('SortOrder'));
|
||||
|
||||
$fields->addFieldToTab('Root.TestObjects', GridField::create('TestObjects', 'TestObjects', $this->TestObjects(), $conf));
|
||||
|
||||
return $fields;
|
||||
}
|
||||
|
||||
public function TestObjects() {
|
||||
|
||||
public function TestObjects()
|
||||
{
|
||||
return $this->getManyManyComponents('TestObjects')->sort('SortOrder');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*** TestObject.php ***/
|
||||
class TestObject extends DataObject {
|
||||
public static $db=array(
|
||||
'Title'=>'Text'
|
||||
);
|
||||
|
||||
public static $belongs_many_many=array(
|
||||
'TestPages'=>'TestPage'
|
||||
);
|
||||
use SilverStripe\ORM\DataObject;
|
||||
|
||||
class TestObject extends DataObject
|
||||
{
|
||||
private static $db = [
|
||||
'Title' => 'Text',
|
||||
];
|
||||
|
||||
private static $belongs_many_many = [
|
||||
'TestPages' => 'TestPage',
|
||||
];
|
||||
}
|
||||
```
|
||||
```
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
ModelAdmin implementation Example
|
||||
=================
|
||||
|
||||
```php
|
||||
/**** MyModelAdmin.php ****/
|
||||
use SilverStripe\Admin\ModelAdmin;
|
||||
use SilverStripe\Forms\GridField\GridField;
|
||||
use UndefinedOffset\SortableGridField\Forms\GridFieldSortableRows;
|
||||
|
||||
class MyModelAdmin extends ModelAdmin
|
||||
{
|
||||
private static $menu_title = 'My Model Admin';
|
||||
|
||||
private static $url_segment = 'my-model-admin';
|
||||
|
||||
private static $managed_models = [
|
||||
MATestObject::class,
|
||||
];
|
||||
|
||||
public function getEditForm($id = null, $fields = null)
|
||||
{
|
||||
$form = parent::getEditForm($id, $fields);
|
||||
|
||||
// This check is simply to ensure you are on the managed model you want adjust accordingly
|
||||
if ($this->modelClass === MATestObject::class) {
|
||||
$gridField = $form->Fields()->dataFieldByName($this->sanitiseClassName($this->modelClass));
|
||||
|
||||
// This is just a precaution to ensure we got a GridField from dataFieldByName() which you should have
|
||||
if ($gridField instanceof GridField) {
|
||||
$gridField->getConfig()->addComponent(GridFieldSortableRows::create('SortOrder'));
|
||||
}
|
||||
}
|
||||
|
||||
return $form;
|
||||
}
|
||||
}
|
||||
|
||||
/**** MATestObject.php ****/
|
||||
use SilverStripe\ORM\DataObject;
|
||||
|
||||
class MATestObject extends DataObject
|
||||
{
|
||||
private static $db = [
|
||||
'Title' => 'Varchar',
|
||||
'SortOrder' => 'Int',
|
||||
];
|
||||
|
||||
private static $indexes = [
|
||||
'SortOrder' => true,
|
||||
];
|
||||
|
||||
private static $default_sort = 'SortOrder';
|
||||
}
|
||||
```
|
Binary file not shown.
Before Width: | Height: | Size: 4.0 KiB |
|
@ -1,131 +1,206 @@
|
|||
(function($) {
|
||||
$.entwine('ss', function($) {
|
||||
$('.ss-gridfield .gridfield-sortablerows input').entwine({
|
||||
onmatch: function() {
|
||||
var self=this;
|
||||
var refCheckbox=$(this);
|
||||
|
||||
var gridField=this.getGridField();
|
||||
|
||||
if($(this).is(':checked')) {
|
||||
gridField.find('table').addClass('dragSorting');
|
||||
}else {
|
||||
gridField.find('table').removeClass('dragSorting');
|
||||
}
|
||||
|
||||
gridField.find('tbody').sortable({
|
||||
opacity: 0.6,
|
||||
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');
|
||||
}
|
||||
|
||||
|
||||
self._makeRequest({data: [
|
||||
{
|
||||
name: button.attr('name'),
|
||||
value: button.val()
|
||||
},
|
||||
{
|
||||
name: 'ItemIDs',
|
||||
value: dataRows
|
||||
}
|
||||
]});
|
||||
}
|
||||
}).disableSelection();
|
||||
|
||||
gridField.find('.datagrid-pagination .ss-gridfield-previouspage, .datagrid-pagination .ss-gridfield-nextpage').each(function() {
|
||||
$(this).droppable({
|
||||
disabled: $(this).is(':disabled'),
|
||||
accept: 'tr.ss-gridfield-item',
|
||||
activeClass: 'sortablerows-droptarget',
|
||||
tolerance: 'pointer',
|
||||
drop: function(event, ui) {
|
||||
gridField.find('tbody').sortable('cancel');
|
||||
|
||||
var button=refCheckbox.parent().find('.sortablerows-sorttopage');
|
||||
var itemID=$(ui.draggable).data('id');
|
||||
var target='';
|
||||
|
||||
|
||||
if($(this).hasClass('ss-gridfield-previouspage')) {
|
||||
target='previouspage';
|
||||
}else if($(this).hasClass('ss-gridfield-nextpage')) {
|
||||
target='nextpage';
|
||||
}
|
||||
|
||||
|
||||
//Move and Reload the grid
|
||||
gridField.reload({data: [
|
||||
{
|
||||
name: button.attr('name'),
|
||||
value: button.val()
|
||||
},
|
||||
{
|
||||
name: 'ItemID',
|
||||
value: itemID
|
||||
},
|
||||
{
|
||||
name: 'Target',
|
||||
value: target
|
||||
}
|
||||
]});
|
||||
|
||||
event.stopPropagation();
|
||||
event.stopImmediatePropagation();
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
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()}]});
|
||||
},
|
||||
|
||||
_makeRequest: function(ajaxOpts, callback) {
|
||||
var gridField=this.getGridField();
|
||||
var form = gridField.closest('form'),
|
||||
focusedElName = gridField.find(':input:focus').attr('name'); // Save focused element for restoring after refresh
|
||||
|
||||
ajaxOpts.data = ajaxOpts.data.concat(form.find(':input').serializeArray());
|
||||
|
||||
// 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) {
|
||||
ajaxOpts.data = window.location.search.replace(/^\?/, '') + '&' + $.param(ajaxOpts.data);
|
||||
}
|
||||
|
||||
$.ajax($.extend({}, {
|
||||
headers: {"X-Pjax" : 'CurrentField'},
|
||||
type: "POST",
|
||||
url: gridField.data('url'),
|
||||
dataType: 'html',
|
||||
success: callback,
|
||||
error: function(e) {
|
||||
alert(ss.i18n._t('GRIDFIELD.ERRORINTRANSACTION'));
|
||||
}
|
||||
}, ajaxOpts));
|
||||
}
|
||||
});
|
||||
});
|
||||
})(jQuery);
|
||||
(function ($) {
|
||||
$.entwine('ss', function ($) {
|
||||
$('.ss-gridfield .gridfield-sortablerows input').entwine({
|
||||
PageSort: false,
|
||||
|
||||
onmatch: function () {
|
||||
var self = this;
|
||||
var refCheckbox = $(this);
|
||||
var gridField = this.getGridField();
|
||||
var form = gridField.closest('form');
|
||||
var pageArrows = gridField.find('.gridfield-sortablerows-movepage .sortablerows-psort-arrow');
|
||||
|
||||
if ($(this).is(':checked')) {
|
||||
gridField.find('table').addClass('dragSorting');
|
||||
} else {
|
||||
gridField.find('table').removeClass('dragSorting');
|
||||
}
|
||||
|
||||
gridField.find('tbody').sortable({
|
||||
opacity: 0.6,
|
||||
disabled: ($(this).is(':checked') == false),
|
||||
start: function (event, ui) {
|
||||
pageArrows.show();
|
||||
pageArrows.redraw();
|
||||
pageArrows.startMoveTracking();
|
||||
},
|
||||
stop: function (event, ui) {
|
||||
pageArrows.stopMoveTracking();
|
||||
pageArrows.hide();
|
||||
},
|
||||
sort: function (event, ui) {
|
||||
pageArrows.moveTracking(event, ui);
|
||||
},
|
||||
update: function (event, ui) {
|
||||
if (self.getPageSort()) {
|
||||
self.setPageSort(false);
|
||||
return;
|
||||
}
|
||||
|
||||
var gridItems = gridField.getItems();
|
||||
|
||||
gridItems.removeClass('first last odd even');
|
||||
gridItems.first().addClass('first');
|
||||
gridItems.last().addClass('last');
|
||||
gridItems.filter(':even').addClass('odd');
|
||||
gridItems.filter(':odd').addClass('even');
|
||||
|
||||
var dataRows = [];
|
||||
var button = refCheckbox.parent().find('.sortablerows-savesort');
|
||||
|
||||
|
||||
for (var i = 0; i < gridItems.length; i++) {
|
||||
dataRows[i] = $(gridItems[i]).data('id');
|
||||
}
|
||||
|
||||
|
||||
self._makeRequest({
|
||||
data: [
|
||||
{
|
||||
name: button.attr('name'),
|
||||
value: button.val()
|
||||
},
|
||||
{
|
||||
name: 'ItemIDs',
|
||||
value: dataRows
|
||||
}
|
||||
]
|
||||
}, function () {
|
||||
form.removeClass('loading');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (refCheckbox.hasClass('gridfield-sortablerows-noselection') || $(this).is(':checked')) {
|
||||
gridField.find('tbody').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-toggle');
|
||||
gridField.reload({data: [{name: button.attr('name'), value: button.val()}]});
|
||||
},
|
||||
|
||||
_makeRequest: function (ajaxOpts, callback) {
|
||||
var gridField = this.getGridField();
|
||||
var form = gridField.closest('form');
|
||||
|
||||
form.addClass('loading');
|
||||
|
||||
ajaxOpts.data = ajaxOpts.data.concat(form.find(':input').serializeArray());
|
||||
|
||||
// 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) {
|
||||
ajaxOpts.data = window.location.search.replace(/^\?/, '') + '&' + $.param(ajaxOpts.data);
|
||||
}
|
||||
|
||||
$.ajax($.extend({}, {
|
||||
headers: {"X-Pjax": 'CurrentField'},
|
||||
type: "POST",
|
||||
url: gridField.data('url'),
|
||||
dataType: 'html',
|
||||
success: callback,
|
||||
error: function (e) {
|
||||
alert(ss.i18n._t('Admin.ERRORINTRANSACTION', 'An error occured while fetching data from the server\n Please try again later.'));
|
||||
}
|
||||
}, ajaxOpts));
|
||||
}
|
||||
});
|
||||
|
||||
$('.ss-gridfield .gridfield-sortablerows-movepage .sortablerows-psort-arrow').entwine({
|
||||
ArrowIcon: null,
|
||||
|
||||
onmatch: function () {
|
||||
var gridField = this.getGridField();
|
||||
var sortableCheckbox = gridField.find('.gridfield-sortablerows input');
|
||||
var self = $(this);
|
||||
|
||||
if ($(this).hasClass('sortablerows-prev-page') && (gridField.find('.ss-gridfield-previouspage').length == 0 || gridField.find('.ss-gridfield-previouspage').is(':disabled'))) {
|
||||
$(this).remove();
|
||||
return;
|
||||
} else if ($(this).hasClass('sortablerows-next-page') && (gridField.find('.ss-gridfield-nextpage').length == 0 || gridField.find('.ss-gridfield-nextpage').is(':disabled'))) {
|
||||
$(this).remove();
|
||||
return;
|
||||
}
|
||||
|
||||
$(this).droppable({
|
||||
disabled: $(this).is(':disabled'),
|
||||
accept: 'tr.ss-gridfield-item',
|
||||
activeClass: 'sortablerows-droptarget',
|
||||
tolerance: 'pointer',
|
||||
drop: function (event, ui) {
|
||||
self.stopMoveTracking();
|
||||
|
||||
sortableCheckbox.setPageSort(true);
|
||||
|
||||
var button = gridField.find('.gridfield-sortablerows .sortablerows-sorttopage');
|
||||
var itemID = $(ui.draggable).data('id');
|
||||
var target = '';
|
||||
|
||||
if ($(this).hasClass('sortablerows-prev-page')) {
|
||||
target = 'previouspage';
|
||||
} else if ($(this).hasClass('sortablerows-next-page')) {
|
||||
target = 'nextpage';
|
||||
}
|
||||
|
||||
|
||||
//Move and Reload the grid
|
||||
gridField.reload({
|
||||
data: [
|
||||
{
|
||||
name: button.attr('name'),
|
||||
value: button.val()
|
||||
},
|
||||
{
|
||||
name: 'ItemID',
|
||||
value: itemID
|
||||
},
|
||||
{
|
||||
name: 'Target',
|
||||
value: target
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.redraw();
|
||||
},
|
||||
redraw: function () {
|
||||
var gridField = this.getGridField();
|
||||
var tbody = gridField.find('tbody');
|
||||
var tbodyPos = tbody.position();
|
||||
|
||||
$(this).css('top', tbodyPos.top + 'px').height(tbody.height());
|
||||
},
|
||||
startMoveTracking: function () {
|
||||
var self = $(this);
|
||||
self.setArrowIcon(self.find('i'));
|
||||
},
|
||||
stopMoveTracking: function () {
|
||||
$(this).setArrowIcon(null);
|
||||
},
|
||||
moveTracking: function (e, ui) {
|
||||
var self = $(this);
|
||||
var arrowIcon = self.getArrowIcon();
|
||||
if (arrowIcon) {
|
||||
var selfOffset = self.offset().top;
|
||||
var arrowIconHeight = arrowIcon.width() + 10;
|
||||
var railHeight = self.height() - arrowIconHeight;
|
||||
var helperPos = ui.helper.offset().top;
|
||||
|
||||
if (helperPos > selfOffset + 10 && helperPos < selfOffset + railHeight) {
|
||||
arrowIcon.css('top', ((helperPos - selfOffset) + arrowIconHeight / 2) + 'px');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
ar:
|
||||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: 'السماح بإعادة الترتيب عن طريق السحب والإسقاط'
|
||||
EditPermissionsFailure: 'التحرير غير مرخص له'
|
|
@ -0,0 +1,4 @@
|
|||
cs:
|
||||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: 'Povolit přesuny metodou táhni a pusť'
|
||||
EditPermissionsFailure: 'Nemáte práva pro úpravu'
|
|
@ -0,0 +1,6 @@
|
|||
da:
|
||||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: 'Tillad træk og slip sortering'
|
||||
EditPermissionsFailure: 'Manglende tilladelse til at redigere'
|
||||
NEXT: 'Flyt til næste side'
|
||||
PREVIOUS: 'Flyt til forrige side'
|
|
@ -1,6 +1,6 @@
|
|||
de:
|
||||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: "Drag & Drop neuordnen"
|
||||
DISABLE_PAGINATOR: "Paginator deaktivieren"
|
||||
SORT_TO_PAGE: "Seite zuordnen"
|
||||
EditPermissionsFailure: "Keine Berechtigung zu Editieren"
|
||||
ALLOW_DRAG_DROP: 'Drag & Drop neuordnen'
|
||||
EditPermissionsFailure: 'Keine Berechtigung zu Editieren'
|
||||
NEXT: 'Zur nächsten Seite wechseln'
|
||||
PREVIOUS: 'Zur vorherigen Seite wechseln'
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
en:
|
||||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: "Allow Drag and Drop"
|
||||
DISABLE_PAGINATOR: "Disable Paginator"
|
||||
SORT_TO_PAGE: "Sort To Page"
|
||||
EditPermissionsFailure: "No edit permissions"
|
||||
ALLOW_DRAG_DROP: 'Allow drag and drop re-ordering'
|
||||
EditPermissionsFailure: 'No edit permissions'
|
||||
NEXT: 'Move to Next Page'
|
||||
PREVIOUS: 'Move to Previous Page'
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
eo:
|
||||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: 'Enŝalti reordigadon ŝove kaj demete'
|
||||
EditPermissionsFailure: 'Mankas enhavopermesoj'
|
||||
NEXT: 'Movi al sekva paĝo'
|
||||
PREVIOUS: 'Movi al antaŭa paĝo'
|
|
@ -1,6 +1,4 @@
|
|||
es:
|
||||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: "Permitir arrastrar y soltar"
|
||||
DISABLE_PAGINATOR: "Deshabilitar paginador"
|
||||
SORT_TO_PAGE: "Ordenar a la página"
|
||||
EditPermissionsFailure: "No tienes permisos de edición"
|
||||
ALLOW_DRAG_DROP: 'Permitir arrastrar y soltar'
|
||||
EditPermissionsFailure: 'No tienes permisos de edición'
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
fa_IR:
|
||||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: 'اجازه مرتب سازی مجدد با کشیدن و رها کردن'
|
||||
EditPermissionsFailure: 'بدون مجوز ویرایش'
|
|
@ -0,0 +1,6 @@
|
|||
fi:
|
||||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: 'Salli raahaus ja pudotus'
|
||||
EditPermissionsFailure: 'Ei oikeuksia muokata'
|
||||
NEXT: 'Siirrä seuraavalle sivulle'
|
||||
PREVIOUS: 'Siirrä edelliselle sivulle'
|
|
@ -0,0 +1,6 @@
|
|||
fr:
|
||||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: 'Activer le classement par glisser-déposer'
|
||||
EditPermissionsFailure: 'Vous n''avez pas les permissions pour éditer'
|
||||
NEXT: 'Aller à la page suivante'
|
||||
PREVIOUS: 'Aller à la page précédente'
|
|
@ -0,0 +1,6 @@
|
|||
hr:
|
||||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: 'Omogući raspoređivanje drag and drop metodom'
|
||||
EditPermissionsFailure: 'Nema dozvola uređivanja'
|
||||
NEXT: 'Prelazak na sljedeću stranicu'
|
||||
PREVIOUS: 'Prelazak na prethodnu stranicu'
|
|
@ -0,0 +1,6 @@
|
|||
it:
|
||||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: 'Consenti il trascinamento'
|
||||
EditPermissionsFailure: 'Non hai i permessi per modificare'
|
||||
NEXT: 'Vai alla pagina successiva'
|
||||
PREVIOUS: 'Vai alla pagina precedente'
|
|
@ -0,0 +1,4 @@
|
|||
lt:
|
||||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: 'Įjungti tempimo ir įmetimo rėžimą rikiavimui'
|
||||
EditPermissionsFailure: 'Nėra leidimų redagavimui'
|
|
@ -0,0 +1,4 @@
|
|||
mi:
|
||||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: 'Tukuna te raupapa anō mā te tō me te taka'
|
||||
EditPermissionsFailure: 'Kāore he whakaaetanga whakatika'
|
|
@ -0,0 +1,4 @@
|
|||
nb:
|
||||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: 'Tillat dra og slipp-sortering'
|
||||
EditPermissionsFailure: 'Ingen redigeringstilgang'
|
|
@ -0,0 +1,4 @@
|
|||
nb_NO:
|
||||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: 'Tillat dra og slipp-sortering'
|
||||
EditPermissionsFailure: 'Ingen redigeringstilgang'
|
12
lang/nl.yml
12
lang/nl.yml
|
@ -1,6 +1,6 @@
|
|||
nl:
|
||||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: "Rangschikken met drag & drop toestaan"
|
||||
DISABLE_PAGINATOR: "Rangschikken uitzetten"
|
||||
SORT_TO_PAGE: "Sorteer op Pagina"
|
||||
EditPermissionsFailure: "Geen toegang"
|
||||
nl:
|
||||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: 'Rangschikken met drag & drop toestaan'
|
||||
EditPermissionsFailure: 'Geen toegang'
|
||||
NEXT: 'Verplaats naar Volgende Pagina'
|
||||
PREVIOUS: 'Verplaats naar Vorige Pagina'
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
pl:
|
||||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: 'Pozwól na reorganizację przez drag and drop'
|
||||
EditPermissionsFailure: 'Brak możliwości edycji'
|
||||
NEXT: 'Przenieś do następnej strony'
|
||||
PREVIOUS: 'Przenieś do poprzedniej strony'
|
|
@ -0,0 +1,6 @@
|
|||
ru:
|
||||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: 'Разрешить перетаскивание для сортировки'
|
||||
EditPermissionsFailure: 'Нет прав на изменение'
|
||||
NEXT: 'Переместить на следующую страницу'
|
||||
PREVIOUS: 'Переместить на предыдущую страницу'
|
|
@ -0,0 +1,6 @@
|
|||
sk:
|
||||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: 'Pracovať v režime Drag & Drop (Ťahaj a pusť)'
|
||||
EditPermissionsFailure: 'Nemáte oprávnenie upravovať'
|
||||
NEXT: 'Prejsť na nasledujúcu stránku'
|
||||
PREVIOUS: 'Prejsť na predchádzajúcu stránku'
|
|
@ -0,0 +1,6 @@
|
|||
sl:
|
||||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: 'Omogoči razvrščanje s "povleci in spusti" '
|
||||
EditPermissionsFailure: 'Nimate pravic za urejanje'
|
||||
NEXT: 'Prestavi na naslednjo stran'
|
||||
PREVIOUS: 'Prestavi na prejšnjo stran'
|
|
@ -0,0 +1,6 @@
|
|||
sv:
|
||||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: 'Aktivera dra och släpp sortering'
|
||||
EditPermissionsFailure: 'Rättighet för att redigera saknas'
|
||||
NEXT: 'Gå till nästa sida'
|
||||
PREVIOUS: 'Gå till föregående sida'
|
|
@ -0,0 +1,4 @@
|
|||
zh:
|
||||
GridFieldSortableRows:
|
||||
ALLOW_DRAG_DROP: '允许拖放重新排序'
|
||||
EditPermissionsFailure: '没有编辑权限'
|
|
@ -0,0 +1,49 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ruleset name="SilverStripe">
|
||||
<description>CodeSniffer ruleset for SilverStripe coding conventions.</description>
|
||||
|
||||
<!-- base rules are PSR-2 -->
|
||||
<rule ref="PSR2" >
|
||||
<!-- Current exclusions -->
|
||||
<exclude name="PSR1.Methods.CamelCapsMethodName" />
|
||||
<exclude name="PSR1.Files.SideEffects.FoundWithSymbols" />
|
||||
<exclude name="PSR2.Classes.PropertyDeclaration" />
|
||||
<exclude name="PSR2.Methods.MethodDeclaration.Underscore" />
|
||||
<exclude name="Squiz.Scope.MethodScope" />
|
||||
<exclude name="Squiz.Classes.ValidClassName.NotCamelCaps" />
|
||||
<exclude name="Generic.Files.LineLength.TooLong" />
|
||||
<exclude name="PEAR.Functions.ValidDefaultValue.NotAtEnd" />
|
||||
<exclude name="PSR2.ControlStructures.ElseIfDeclaration" />
|
||||
</rule>
|
||||
|
||||
<rule ref="Squiz.Strings.ConcatenationSpacing">
|
||||
<properties>
|
||||
<property name="spacing" value="1" />
|
||||
<property name="ignoreNewlines" value="true"/>
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<rule ref="PEAR.ControlStructures.MultiLineCondition" />
|
||||
|
||||
<rule ref="Generic.Formatting.SpaceAfterCast" />
|
||||
<rule ref="Generic.Arrays.DisallowLongArraySyntax.Found">
|
||||
<type>warning</type>
|
||||
</rule>
|
||||
|
||||
<rule ref="Squiz.Arrays.ArrayDeclaration.NoComma" />
|
||||
<rule ref="Squiz.WhiteSpace.OperatorSpacing">
|
||||
<properties>
|
||||
<property name="ignoreNewlines" value="true" />
|
||||
</properties>
|
||||
</rule>
|
||||
|
||||
<rule ref="PSR12.Functions.ReturnTypeDeclaration" />
|
||||
|
||||
<!-- include php files only -->
|
||||
<arg name="extensions" value="php,lib,inc,php5"/>
|
||||
|
||||
<file>./src</file>
|
||||
<file>./tests</file>
|
||||
<file>./_config.php</file>
|
||||
</ruleset>
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="vendor/silverstripe/framework/tests/bootstrap.php" colors="true" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
|
||||
<testsuites>
|
||||
<testsuite name="Default">
|
||||
<directory suffix=".php">tests/PHPUnit</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
|
||||
<groups>
|
||||
<exclude>
|
||||
<group>sanitychecks</group>
|
||||
</exclude>
|
||||
</groups>
|
||||
|
||||
<coverage includeUncoveredFiles="true">
|
||||
<include>
|
||||
<directory suffix=".php">src/</directory>
|
||||
</include>
|
||||
<exclude>
|
||||
<directory suffix=".php">tests/</directory>
|
||||
</exclude>
|
||||
</coverage>
|
||||
|
||||
<php>
|
||||
<get name="flush" value="1"/>
|
||||
</php>
|
||||
</phpunit>
|
|
@ -0,0 +1,808 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Forms;
|
||||
|
||||
use SilverStripe\Admin\ModelAdmin;
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Core\ClassInfo;
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Forms\GridField\AbstractGridFieldComponent;
|
||||
use SilverStripe\Forms\GridField\GridField;
|
||||
use SilverStripe\Forms\GridField\GridField_ActionProvider;
|
||||
use SilverStripe\Forms\GridField\GridField_DataManipulator;
|
||||
use SilverStripe\Forms\GridField\GridField_FormAction;
|
||||
use SilverStripe\Forms\GridField\GridField_HTMLProvider;
|
||||
use SilverStripe\Forms\GridField\GridFieldFilterHeader;
|
||||
use SilverStripe\Forms\GridField\GridFieldPaginator;
|
||||
use SilverStripe\Forms\GridField\GridFieldSortableHeader;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\DataObjectSchema;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\ORM\ManyManyList;
|
||||
use SilverStripe\ORM\ManyManyThroughList;
|
||||
use SilverStripe\ORM\RelationList;
|
||||
use SilverStripe\ORM\SS_List;
|
||||
use SilverStripe\ORM\UnsavedRelationList;
|
||||
use SilverStripe\ORM\ValidationException;
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
use SilverStripe\View\ArrayData;
|
||||
use SilverStripe\View\Requirements;
|
||||
|
||||
/**
|
||||
* This component provides a checkbox which when checked enables drag-and-drop re-ordering of elements displayed in a {@link GridField}
|
||||
*/
|
||||
class GridFieldSortableRows extends AbstractGridFieldComponent implements GridField_HTMLProvider, GridField_ActionProvider, GridField_DataManipulator
|
||||
{
|
||||
/** @var string */
|
||||
protected $sortColumn;
|
||||
|
||||
/** @var bool */
|
||||
protected $disable_selection = true;
|
||||
|
||||
/** @var bool */
|
||||
protected $append_to_top = false;
|
||||
|
||||
/** @var null|string */
|
||||
protected $update_versioned_stage = null;
|
||||
|
||||
/** @var null|string */
|
||||
protected $custom_relation_name = null;
|
||||
|
||||
/**
|
||||
* @param string $sortColumn Column that should be used to update the sort information
|
||||
* @param bool $disableSelection Disable selection on the GridField when dragging
|
||||
* @param string $updateVersionStage Name of the versioned stage to update this disabled by default unless this is set
|
||||
* @param string $customRelationName Name of the relationship to use, if left null the name is determined from the GridField's name
|
||||
*/
|
||||
public function __construct($sortColumn, $disableSelection = true, $updateVersionStage = null, $customRelationName = null)
|
||||
{
|
||||
$this->sortColumn = $sortColumn;
|
||||
$this->disable_selection = $disableSelection;
|
||||
$this->update_versioned_stage = $updateVersionStage;
|
||||
$this->custom_relation_name = $customRelationName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
$dataList = $gridField->getList();
|
||||
|
||||
if (class_exists('UnsavedRelationList') && $dataList instanceof UnsavedRelationList) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$state = $gridField->State->GridFieldSortableRows;
|
||||
if (!is_bool($state->sortableToggle)) {
|
||||
$state->sortableToggle = false;
|
||||
}
|
||||
|
||||
//Ensure user can edit
|
||||
if (!singleton($gridField->getModelClass())->canEdit()) {
|
||||
return [];
|
||||
}
|
||||
|
||||
|
||||
//Sort order toggle
|
||||
$sortOrderToggle = GridField_FormAction::create(
|
||||
$gridField,
|
||||
'sortablerows-toggle',
|
||||
'sorttoggle',
|
||||
'sortableRowsToggle',
|
||||
null
|
||||
)->addExtraClass('sortablerows-toggle');
|
||||
|
||||
|
||||
$sortOrderSave = GridField_FormAction::create(
|
||||
$gridField,
|
||||
'sortablerows-savesort',
|
||||
'savesort',
|
||||
'saveGridRowSort',
|
||||
null
|
||||
)->addExtraClass('sortablerows-savesort');
|
||||
|
||||
|
||||
//Sort to Page Action
|
||||
$sortToPage = GridField_FormAction::create(
|
||||
$gridField,
|
||||
'sortablerows-sorttopage',
|
||||
'sorttopage',
|
||||
'sortToPage',
|
||||
null
|
||||
)->addExtraClass('sortablerows-sorttopage');
|
||||
|
||||
|
||||
$data = [
|
||||
'SortableToggle' => $sortOrderToggle,
|
||||
'SortOrderSave' => $sortOrderSave,
|
||||
'SortToPage' => $sortToPage,
|
||||
'Checked' => ($state->sortableToggle == true ? ' checked = "checked"' : ''),
|
||||
'List' => $dataList,
|
||||
];
|
||||
|
||||
$forTemplate = new ArrayData($data);
|
||||
|
||||
Requirements::css('undefinedoffset/sortablegridfield:css/GridFieldSortableRows.css');
|
||||
Requirements::javascript('undefinedoffset/sortablegridfield:javascript/GridFieldSortableRows.js');
|
||||
|
||||
$args = ['Colspan' => count($gridField->getColumns()), 'ID' => $gridField->ID(), 'DisableSelection' => $this->disable_selection];
|
||||
|
||||
$fragments = ['header' => $forTemplate->renderWith('SortableGridField\Forms\Includes\GridFieldSortableRows', $args)];
|
||||
|
||||
if ($gridField->getConfig()->getComponentByType(GridFieldPaginator::class)) {
|
||||
$fragments['after'] = $forTemplate->renderWith('SortableGridField\Forms\Includes\GridFieldSortableRows_paginator');
|
||||
}
|
||||
|
||||
return $fragments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Manipulate the datalist as needed by this grid modifier.
|
||||
* @param GridField $gridField Grid Field Reference
|
||||
* @param SS_List|\SilverStripe\ORM\DataList $dataList Data List to adjust
|
||||
* @return \SilverStripe\ORM\DataList Modified Data List
|
||||
*/
|
||||
public function getManipulatedData(GridField $gridField, SS_List $dataList)
|
||||
{
|
||||
//Detect and correct items with a sort column value of 0 (push to bottom)
|
||||
$this->fixSortColumn($gridField, $dataList);
|
||||
|
||||
|
||||
$headerState = $gridField->State->GridFieldSortableHeader;
|
||||
$state = $gridField->State->GridFieldSortableRows;
|
||||
if ((!is_bool($state->sortableToggle) || $state->sortableToggle === false) && $headerState && is_string($headerState->SortColumn) && is_string($headerState->SortDirection)) {
|
||||
return $dataList->sort($headerState->SortColumn, $headerState->SortDirection);
|
||||
}
|
||||
|
||||
if ($state->sortableToggle === true) {
|
||||
$gridField->getConfig()->removeComponentsByType(GridFieldFilterHeader::class);
|
||||
$gridField->getConfig()->removeComponentsByType(GridFieldSortableHeader::class);
|
||||
}
|
||||
|
||||
return $dataList->sort($this->sortColumn);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if new records should be appended to the top or the bottom of the list
|
||||
* @param bool $value Boolean true to append to the top false to append to the bottom
|
||||
* @return GridFieldSortableRows Returns the current instance
|
||||
*/
|
||||
public function setAppendToTop($value)
|
||||
{
|
||||
$this->append_to_top = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $value Boolean true to disable selection of table contents false to enable selection
|
||||
* @return GridFieldSortableRows Returns the current instance
|
||||
*/
|
||||
public function setDisableSelection($value)
|
||||
{
|
||||
$this->disable_selection = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the suffix of the versioned stage that should be updated along side the default stage
|
||||
* @param string $value Versioned Stage to update this is disabled by default unless this is set
|
||||
* @return GridFieldSortableRows Returns the current instance
|
||||
*/
|
||||
public function setUpdateVersionedStage($value)
|
||||
{
|
||||
$this->update_versioned_stage = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the name of the relationship to use, by default the name is determined from the GridField's name
|
||||
* @param string $value Name of the relationship to use, by default the name is determined from the GridField's name
|
||||
* @return GridFieldSortableRows Returns the current instance
|
||||
*/
|
||||
public function setCustomRelationName($value)
|
||||
{
|
||||
$this->custom_relation_name = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects and corrects items with a sort column value of 0, by appending them to the bottom of the list
|
||||
* @param GridField $gridField Grid Field Reference
|
||||
* @param SS_List|\SilverStripe\ORM\DataList $dataList Data List of items to be checked
|
||||
*/
|
||||
protected function fixSortColumn($gridField, SS_List $dataList)
|
||||
{
|
||||
if ($dataList instanceof UnsavedRelationList) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var SS_List|\SilverStripe\ORM\DataList $list */
|
||||
$list = clone $dataList;
|
||||
$list = $list->alterDataQuery(function ($query, SS_List $tmplist) {
|
||||
/** @var \SilverStripe\ORM\DataQuery $query */
|
||||
$query->limit(null);
|
||||
return $query;
|
||||
});
|
||||
|
||||
$many_many = ($list instanceof ManyManyList || $list instanceof ManyManyThroughList);
|
||||
if (!$many_many) {
|
||||
$sng = singleton($gridField->getModelClass());
|
||||
$fieldType = $sng->config()->db[$this->sortColumn];
|
||||
|
||||
if (!$fieldType || !($fieldType == 'Int' || $fieldType == 'SilverStripe\\ORM\\FieldType\\DBInt' || is_subclass_of($fieldType, 'SilverStripe\\ORM\\FieldType\\DBInt'))) {
|
||||
if (is_array($fieldType)) {
|
||||
user_error('Sort column ' . $this->sortColumn . ' could not be found in ' . $gridField->getModelClass() . '\'s ancestry', E_USER_ERROR);
|
||||
} else {
|
||||
user_error('Sort column ' . $this->sortColumn . ' must be an instance of SilverStripe\\ORM\\FieldType\\DBInt, column is of type ' . $fieldType, E_USER_ERROR);
|
||||
}
|
||||
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
$max = $list->Max($this->sortColumn);
|
||||
$list = $list->filter($this->sortColumn, 0)->sort("Created,ID");
|
||||
if ($list->Count() > 0) {
|
||||
$owner = $gridField->getForm()->getRecord();
|
||||
$sortColumn = $this->sortColumn;
|
||||
$i = 1;
|
||||
|
||||
if ($many_many) {
|
||||
$schema = Injector::inst()->get(DataObjectSchema::class);
|
||||
$componentDetails = $schema->manyManyComponent(get_class($owner), (!empty($this->custom_relation_name) ? $this->custom_relation_name : $gridField->getName()));
|
||||
if (empty($componentDetails)) {
|
||||
user_error('Could not find the relationship "' . (!empty($this->custom_relation_name) ? $this->custom_relation_name : $gridField->getName()) . '" on "' . get_class($owner) . '"', E_USER_ERROR);
|
||||
}
|
||||
|
||||
$parentField = $componentDetails['parentField'];
|
||||
$componentField = $componentDetails['childField'];
|
||||
$table = $componentDetails['join'];
|
||||
|
||||
//For ManyManyThroughLists get the right join table
|
||||
if ($list instanceof ManyManyThroughList && class_exists($table)) {
|
||||
$table = $schema->tableName($table);
|
||||
}
|
||||
|
||||
$extraFields = $list->getExtraFields();
|
||||
|
||||
if (!$extraFields || !array_key_exists($this->sortColumn, $extraFields) || !($extraFields[$this->sortColumn] == 'Int' || $extraFields[$this->sortColumn] == 'SilverStripe\\ORM\\FieldType\\DBInt' || is_subclass_of('SilverStripe\\ORM\\FieldType\\DBInt', $extraFields[$this->sortColumn]))) {
|
||||
user_error('Sort column ' . $this->sortColumn . ' must be an SilverStripe\\ORM\\FieldType\\DBInt, column is of type ' . $extraFields[$this->sortColumn], E_USER_ERROR);
|
||||
exit;
|
||||
}
|
||||
} else {
|
||||
//Find table containing the sort column
|
||||
$table = false;
|
||||
$class = $gridField->getModelClass();
|
||||
|
||||
$db = Config::inst()->get($class, "db", CONFIG::UNINHERITED);
|
||||
if (!empty($db) && array_key_exists($sortColumn, $db)) {
|
||||
$table = DataObject::getSchema()->tableName($class);
|
||||
} else {
|
||||
$classes = ClassInfo::ancestry($class, true);
|
||||
foreach ($classes as $class) {
|
||||
$db = Config::inst()->get($class, "db", CONFIG::UNINHERITED);
|
||||
if (!empty($db) && array_key_exists($sortColumn, $db)) {
|
||||
$table = DataObject::getSchema()->tableName($class);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($table === false) {
|
||||
user_error('Sort column ' . $this->sortColumn . ' could not be found in ' . $gridField->getModelClass() . '\'s ancestry', E_USER_ERROR);
|
||||
exit;
|
||||
}
|
||||
|
||||
$baseDataClass = DataObject::getSchema()->baseDataClass($gridField->getModelClass());
|
||||
$baseDataTable = DataObject::getSchema()->tableName($baseDataClass);
|
||||
}
|
||||
|
||||
|
||||
//Start transaction if supported
|
||||
if (DB::get_conn()->supportsTransactions()) {
|
||||
DB::get_conn()->transactionStart();
|
||||
}
|
||||
|
||||
$idCondition = null;
|
||||
if ($this->append_to_top && !($list instanceof RelationList)) {
|
||||
$idCondition = '"ID" IN(\'' . implode("','", $dataList->getIDList()) . '\')';
|
||||
}
|
||||
|
||||
if ($this->append_to_top) {
|
||||
$topIncremented = [];
|
||||
}
|
||||
|
||||
$modelClass = $gridField->getModelClass();
|
||||
$hasVersioned = $this->hasVersionedExtension($modelClass);
|
||||
foreach ($list as $obj) {
|
||||
if ($many_many) {
|
||||
if ($this->append_to_top) {
|
||||
//Upgrade all the records (including the last inserted from 0 to 1)
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn . '" = "' . $sortColumn . '"+1'
|
||||
. ' WHERE "' . $parentField . '" = ' . $owner->ID . (!empty($topIncremented) ? ' AND "' . $componentField . '" NOT IN(\'' . implode('\',\'', $topIncremented) . '\')' : ''));
|
||||
|
||||
$topIncremented[] = $obj->ID;
|
||||
} else {
|
||||
//Append the last record to the bottom
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn . '" = ' . ($max + $i)
|
||||
. ' WHERE "' . $componentField . '" = ' . $obj->ID . ' AND "' . $parentField . '" = ' . $owner->ID);
|
||||
}
|
||||
} else if ($this->append_to_top) {
|
||||
if ($hasVersioned) {
|
||||
// For versioned objects, modify them with the ORM so that the *_versions table is updated
|
||||
$itemsToUpdate = $modelClass::get()->where(($list instanceof RelationList ? '"' . $list->foreignKey . '" = ' . $owner->ID : $idCondition) . (!empty($topIncremented) ? ' AND "ID" NOT IN(\'' . implode('\',\'', $topIncremented) . '\')' : ''));
|
||||
if ($itemsToUpdate->exists()) {
|
||||
foreach ($itemsToUpdate as $item) {
|
||||
$item->$sortColumn = $item->$sortColumn + 1;
|
||||
$item->write();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//Upgrade all the records (including the last inserted from 0 to 1)
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn . '" = "' . $sortColumn . '"+1'
|
||||
. ' WHERE ' . ($list instanceof RelationList ? '"' . $list->foreignKey . '" = ' . $owner->ID : $idCondition) . (!empty($topIncremented) ? ' AND "ID" NOT IN(\'' . implode('\',\'', $topIncremented) . '\')' : ''));
|
||||
}
|
||||
|
||||
if ($this->update_versioned_stage && $this->hasVersionedExtension($gridField->getModelClass())) {
|
||||
DB::query('UPDATE "' . $table . '_' . $this->update_versioned_stage
|
||||
. '" SET "' . $sortColumn . '" = "' . $sortColumn . '"+1'
|
||||
. ' WHERE ' . ($list instanceof RelationList ? '"' . $list->foreignKey . '" = ' . $owner->ID : $idCondition) . (!empty($topIncremented) ? ' AND "ID" NOT IN(\'' . implode('\',\'', $topIncremented) . '\')' : ''));
|
||||
}
|
||||
|
||||
$topIncremented[] = $obj->ID;
|
||||
} else {
|
||||
if ($hasVersioned) {
|
||||
// For versioned objects, modify them with the ORM so that the *_versions table is updated
|
||||
$obj->$sortColumn = ($max + $i);
|
||||
$obj->write();
|
||||
} else {
|
||||
//Append the last record to the bottom
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn . '" = ' . ($max + $i)
|
||||
. ' WHERE "ID" = ' . $obj->ID);
|
||||
|
||||
//LastEdited
|
||||
DB::query('UPDATE "' . $baseDataTable
|
||||
. '" SET "LastEdited" = \'' . date('Y-m-d H:i:s') . '\''
|
||||
. ' WHERE "ID" = ' . $obj->ID);
|
||||
}
|
||||
|
||||
if ($this->update_versioned_stage && $this->hasVersionedExtension($gridField->getModelClass())) {
|
||||
DB::query('UPDATE "' . $table . '_' . $this->update_versioned_stage
|
||||
. '" SET "' . $sortColumn . '" = ' . ($max + $i)
|
||||
. ' WHERE "ID" = ' . $obj->ID);
|
||||
|
||||
if ($this->hasVersionedExtension($baseDataClass)) {
|
||||
DB::query('UPDATE "' . $baseDataTable . '_' . $this->update_versioned_stage
|
||||
. '" SET "LastEdited" = \'' . date('Y-m-d H:i:s') . '\''
|
||||
. ' WHERE "ID" = ' . $obj->ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$i++;
|
||||
}
|
||||
|
||||
//Update LastEdited for affected records when using append to top on a many_many relationship
|
||||
if (!$many_many && $this->append_to_top && count($topIncremented) > 0) {
|
||||
DB::query('UPDATE "' . $baseDataTable
|
||||
. '" SET "LastEdited" = \'' . date('Y-m-d H:i:s') . '\''
|
||||
. ' WHERE "ID" IN(\'' . implode('\',\'', $topIncremented) . '\')');
|
||||
|
||||
if ($this->update_versioned_stage && $this->hasVersionedExtension($gridField->getModelClass()) && $this->hasVersionedExtension($baseDataClass)) {
|
||||
DB::query('UPDATE "' . $baseDataTable . '_' . $this->update_versioned_stage
|
||||
. '" SET "LastEdited" = \'' . date('Y-m-d H:i:s') . '\''
|
||||
. ' WHERE "ID" IN(\'' . implode('\',\'', $topIncremented) . '\')');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//End transaction if supported
|
||||
if (DB::get_conn()->supportsTransactions()) {
|
||||
DB::get_conn()->transactionEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
return ['saveGridRowSort', 'sortableRowsToggle', 'sortToPage'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
$gridField->getConfig()->removeComponentsByType(GridFieldFilterHeader::class);
|
||||
$gridField->getConfig()->removeComponentsByType(GridFieldSortableHeader::class);
|
||||
}
|
||||
|
||||
|
||||
if ($actionName == 'savegridrowsort') {
|
||||
return $this->saveGridRowSort($gridField, $data);
|
||||
} else if ($actionName == 'sorttopage') {
|
||||
return $this->sortToPage($gridField, $data);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles saving of the row sort order
|
||||
* @param GridField $gridField Grid Field Reference
|
||||
* @param array $data Data submitted in the request
|
||||
* @throws ValidationException If user has no edit permissions
|
||||
*/
|
||||
protected function saveGridRowSort(GridField $gridField, $data)
|
||||
{
|
||||
$dataList = $gridField->getList();
|
||||
|
||||
if ($dataList instanceof UnsavedRelationList) {
|
||||
user_error('Cannot sort an UnsavedRelationList', E_USER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!singleton($gridField->getModelClass())->canEdit()) {
|
||||
throw new ValidationException(_t('GridFieldSortableRows.EditPermissionsFailure', "No edit permissions"), 0);
|
||||
}
|
||||
|
||||
if (empty($data['ItemIDs'])) {
|
||||
user_error('No items to sort', E_USER_ERROR);
|
||||
}
|
||||
|
||||
$className = $gridField->getModelClass();
|
||||
$owner = $gridField->Form->getRecord();
|
||||
$items = clone $gridField->getList();
|
||||
$many_many = ($items instanceof ManyManyList || $items instanceof ManyManyThroughList);
|
||||
$sortColumn = $this->sortColumn;
|
||||
$pageOffset = 0;
|
||||
|
||||
if ($paginator = $gridField->getConfig()->getComponentsByType(GridFieldPaginator::class)->First()) {
|
||||
$pageState = $gridField->State->GridFieldPaginator;
|
||||
|
||||
if ($pageState->currentPage && is_int($pageState->currentPage) && $pageState->currentPage > 1) {
|
||||
$pageOffset = $paginator->getItemsPerPage() * ($pageState->currentPage - 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($many_many) {
|
||||
$schema = Injector::inst()->get(DataObjectSchema::class);
|
||||
$componentDetails = $schema->manyManyComponent(get_class($owner), (!empty($this->custom_relation_name) ? $this->custom_relation_name : $gridField->getName()));
|
||||
if (empty($componentDetails)) {
|
||||
user_error('Could not find the relationship "' . (!empty($this->custom_relation_name) ? $this->custom_relation_name : $gridField->getName()) . '" on "' . get_class($owner) . '"', E_USER_ERROR);
|
||||
}
|
||||
|
||||
$parentField = $componentDetails['parentField'];
|
||||
$componentField = $componentDetails['childField'];
|
||||
$table = $componentDetails['join'];
|
||||
|
||||
//For ManyManyThroughLists get the right join table
|
||||
if ($items instanceof ManyManyThroughList && class_exists($table)) {
|
||||
$table = $schema->tableName($table);
|
||||
}
|
||||
} else {
|
||||
//Find table containing the sort column
|
||||
$table = false;
|
||||
$class = $gridField->getModelClass();
|
||||
$db = Config::inst()->get($class, "db", CONFIG::UNINHERITED);
|
||||
if (!empty($db) && array_key_exists($sortColumn, $db)) {
|
||||
$table = DataObject::getSchema()->tableName($class);
|
||||
} else {
|
||||
$classes = ClassInfo::ancestry($class, true);
|
||||
foreach ($classes as $class) {
|
||||
$db = Config::inst()->get($class, "db", CONFIG::UNINHERITED);
|
||||
if (!empty($db) && array_key_exists($sortColumn, $db)) {
|
||||
$table = DataObject::getSchema()->tableName($class);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($table === false) {
|
||||
user_error('Sort column ' . $this->sortColumn . ' could not be found in ' . $gridField->getModelClass() . '\'s ancestry', E_USER_ERROR);
|
||||
exit;
|
||||
}
|
||||
|
||||
$baseDataClass = DataObject::getSchema()->baseDataClass($gridField->getModelClass());
|
||||
$baseDataTable = DataObject::getSchema()->tableName($baseDataClass);
|
||||
}
|
||||
|
||||
|
||||
//Event to notify the Controller or owner DataObject before list sort
|
||||
if ($owner && $owner instanceof DataObject && method_exists($owner, 'onBeforeGridFieldRowSort')) {
|
||||
$owner->onBeforeGridFieldRowSort(clone $items);
|
||||
} else if (Controller::has_curr() && Controller::curr() instanceof ModelAdmin && method_exists(Controller::curr(), 'onBeforeGridFieldRowSort')) {
|
||||
Controller::curr()->onBeforeGridFieldRowSort(clone $items);
|
||||
}
|
||||
|
||||
//Start transaction if supported
|
||||
if (DB::get_conn()->supportsTransactions()) {
|
||||
DB::get_conn()->transactionStart();
|
||||
}
|
||||
|
||||
//Perform sorting
|
||||
$ids = explode(',', $data['ItemIDs']);
|
||||
$modelClass = $gridField->getModelClass();
|
||||
$hasVersioned = $this->hasVersionedExtension($modelClass);
|
||||
for ($sort = 0; $sort < count($ids); $sort++) {
|
||||
$id = intval($ids[$sort]);
|
||||
if ($many_many) {
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn . '" = ' . (($sort + 1) + $pageOffset)
|
||||
. ' WHERE "' . $componentField . '" = ' . $id . ' AND "' . $parentField . '" = ' . $owner->ID);
|
||||
} else {
|
||||
if ($hasVersioned) {
|
||||
// For versioned objects, modify them with the ORM so that the *_versions table is updated
|
||||
$obj = $modelClass::get()->byID(intval($id));
|
||||
if (!empty($obj) && $obj !== false && $obj->exists()) {
|
||||
$obj->$sortColumn = (($sort + 1) + $pageOffset);
|
||||
$obj->write();
|
||||
}
|
||||
} else {
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn . '" = ' . (($sort + 1) + $pageOffset)
|
||||
. ' WHERE "ID" = ' . $id);
|
||||
|
||||
DB::query('UPDATE "' . $baseDataTable
|
||||
. '" SET "LastEdited" = \'' . date('Y-m-d H:i:s') . '\''
|
||||
. ' WHERE "ID" = ' . $id);
|
||||
}
|
||||
|
||||
if ($this->update_versioned_stage && $hasVersioned) {
|
||||
DB::query('UPDATE "' . $table . '_' . $this->update_versioned_stage
|
||||
. '" SET "' . $sortColumn . '" = ' . (($sort + 1) + $pageOffset)
|
||||
. ' WHERE "ID" = ' . $id);
|
||||
|
||||
if ($this->hasVersionedExtension($baseDataClass)) {
|
||||
DB::query('UPDATE "' . $baseDataTable . '_' . $this->update_versioned_stage
|
||||
. '" SET "LastEdited" = \'' . date('Y-m-d H:i:s') . '\''
|
||||
. ' WHERE "ID" = ' . $id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//End transaction if supported
|
||||
if (DB::get_conn()->supportsTransactions()) {
|
||||
DB::get_conn()->transactionEnd();
|
||||
}
|
||||
|
||||
|
||||
//Event to notify the Controller or owner DataObject after list sort
|
||||
if ($owner && $owner instanceof DataObject && method_exists($owner, 'onAfterGridFieldRowSort')) {
|
||||
$owner->onAfterGridFieldRowSort(clone $items);
|
||||
} else if (Controller::has_curr() && Controller::curr() instanceof ModelAdmin && method_exists(Controller::curr(), 'onAfterGridFieldRowSort')) {
|
||||
Controller::curr()->onAfterGridFieldRowSort(clone $items);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles sorting across pages
|
||||
* @param GridField $gridField Grid Field Reference
|
||||
* @param array $data Data submitted in the request
|
||||
*/
|
||||
protected function sortToPage(GridField $gridField, $data)
|
||||
{
|
||||
if (!$paginator = $gridField->getConfig()->getComponentsByType(GridFieldPaginator::class)->First()) {
|
||||
user_error('Paginator not detected', E_USER_ERROR);
|
||||
}
|
||||
|
||||
if (empty($data['ItemID'])) {
|
||||
user_error('No item to sort', E_USER_ERROR);
|
||||
}
|
||||
|
||||
if (empty($data['Target'])) {
|
||||
user_error('No target page', E_USER_ERROR);
|
||||
}
|
||||
|
||||
/** @var \SilverStripe\Core\Extensible $className */
|
||||
$className = $gridField->getModelClass();
|
||||
$owner = $gridField->Form->getRecord();
|
||||
|
||||
/** @var DataList $items */
|
||||
$items = clone $gridField->getList();
|
||||
|
||||
$many_many = ($items instanceof ManyManyList || $items instanceof ManyManyThroughList);
|
||||
$sortColumn = $this->sortColumn;
|
||||
$targetItem = $items->byID(intval($data['ItemID']));
|
||||
|
||||
if (!$targetItem) {
|
||||
user_error('Target item not found', E_USER_ERROR);
|
||||
}
|
||||
|
||||
$currentPage = 1;
|
||||
|
||||
$pageState = $gridField->State->GridFieldPaginator;
|
||||
if ($pageState->currentPage && $pageState->currentPage > 1) {
|
||||
$currentPage = $pageState->currentPage;
|
||||
}
|
||||
|
||||
if ($many_many) {
|
||||
$schema = Injector::inst()->get(DataObjectSchema::class);
|
||||
$componentDetails = $schema->manyManyComponent(get_class($owner), (!empty($this->custom_relation_name) ? $this->custom_relation_name : $gridField->getName()));
|
||||
$parentField = $componentDetails['parentField'];
|
||||
$componentField = $componentDetails['childField'];
|
||||
$table = $componentDetails['join'];
|
||||
|
||||
//For ManyManyThroughLists get the right join table
|
||||
if ($items instanceof ManyManyThroughList && class_exists($table)) {
|
||||
$table = $schema->tableName($table);
|
||||
}
|
||||
}
|
||||
|
||||
if ($data['Target'] == 'previouspage') {
|
||||
$items = $items->limit($paginator->getItemsPerPage() + 1, ($paginator->getItemsPerPage() * ($currentPage - 1)) - 1);
|
||||
} else if ($data['Target'] == 'nextpage') {
|
||||
$items = $items->limit($paginator->getItemsPerPage() + 1, $paginator->getItemsPerPage() * ($currentPage - 1));
|
||||
} else {
|
||||
user_error('Not implemented: ' . $data['Target'], E_USER_ERROR);
|
||||
}
|
||||
|
||||
$sortPositions = $items->column($sortColumn);
|
||||
|
||||
//Event to notify the Controller or owner DataObject before list sort
|
||||
if ($owner && $owner instanceof DataObject && method_exists($owner, 'onBeforeGridFieldPageSort')) {
|
||||
$owner->onBeforeGridFieldPageSort(clone $items);
|
||||
} else if (Controller::has_curr() && Controller::curr() instanceof ModelAdmin && method_exists(Controller::curr(), 'onBeforeGridFieldPageSort')) {
|
||||
Controller::curr()->onBeforeGridFieldPageSort(clone $items);
|
||||
}
|
||||
|
||||
//Find the sort column
|
||||
if ($this->update_versioned_stage && $this->hasVersionedExtension($className)) {
|
||||
$table = false;
|
||||
$classes = ClassInfo::ancestry($className, true);
|
||||
foreach ($classes as $class) {
|
||||
$db = Config::inst()->get($class, "db", CONFIG::UNINHERITED);
|
||||
if (!empty($db) && array_key_exists($sortColumn, $db)) {
|
||||
$table = DataObject::getSchema()->tableName($class);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($table === false) {
|
||||
user_error('Sort column ' . $this->sortColumn . ' could not be found in ' . $gridField->getModelClass() . '\'s ancestry', E_USER_ERROR);
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
//Start transaction if supported
|
||||
if (DB::get_conn()->supportsTransactions()) {
|
||||
DB::get_conn()->transactionStart();
|
||||
}
|
||||
|
||||
if ($data['Target'] == 'previouspage') {
|
||||
if ($many_many) {
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn . '" = ' . $sortPositions[0]
|
||||
. ' WHERE "' . $componentField . '" = ' . $targetItem->ID . ' AND "' . $parentField . '" = ' . $owner->ID);
|
||||
} else {
|
||||
$targetItem->$sortColumn = $sortPositions[0];
|
||||
$targetItem->write();
|
||||
|
||||
if ($this->update_versioned_stage && $this->hasVersionedExtension($className)) {
|
||||
DB::query('UPDATE "' . $table . '_' . $this->update_versioned_stage
|
||||
. '" SET "' . $sortColumn . '" = ' . $sortPositions[0]
|
||||
. ' WHERE "ID" = ' . $targetItem->ID);
|
||||
}
|
||||
}
|
||||
|
||||
$i = 1;
|
||||
foreach ($items as $obj) {
|
||||
if ($obj->ID == $targetItem->ID || $i >= count($sortPositions)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if ($many_many) {
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn . '" = ' . $sortPositions[$i]
|
||||
. ' WHERE "' . $componentField . '" = ' . $obj->ID . ' AND "' . $parentField . '" = ' . $owner->ID);
|
||||
} else {
|
||||
$obj->$sortColumn = $sortPositions[$i];
|
||||
$obj->write();
|
||||
|
||||
if ($this->update_versioned_stage && $this->hasVersionedExtension($className)) {
|
||||
DB::query('UPDATE "' . $table . '_' . $this->update_versioned_stage
|
||||
. '" SET "' . $sortColumn . '" = ' . $sortPositions[$i]
|
||||
. ' WHERE "ID" = ' . $obj->ID);
|
||||
}
|
||||
}
|
||||
|
||||
$i++;
|
||||
}
|
||||
} else {
|
||||
if ($many_many) {
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn . '" = ' . $sortPositions[count($sortPositions) - 1]
|
||||
. ' WHERE "' . $componentField . '" = ' . $targetItem->ID . ' AND "' . $parentField . '" = ' . $owner->ID);
|
||||
} else {
|
||||
$targetItem->$sortColumn = $sortPositions[count($sortPositions) - 1];
|
||||
$targetItem->write();
|
||||
|
||||
if ($this->update_versioned_stage && $this->hasVersionedExtension($className)) {
|
||||
DB::query('UPDATE "' . $table . '_' . $this->update_versioned_stage
|
||||
. '" SET "' . $sortColumn . '" = ' . $sortPositions[count($sortPositions) - 1]
|
||||
. ' WHERE "ID" = ' . $targetItem->ID);
|
||||
}
|
||||
}
|
||||
|
||||
$i = 0;
|
||||
foreach ($items as $obj) {
|
||||
if ($obj->ID == $targetItem->ID) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if ($many_many) {
|
||||
DB::query('UPDATE "' . $table
|
||||
. '" SET "' . $sortColumn . '" = ' . $sortPositions[$i]
|
||||
. ' WHERE "' . $componentField . '" = ' . $obj->ID . ' AND "' . $parentField . '" = ' . $owner->ID);
|
||||
} else {
|
||||
$obj->$sortColumn = $sortPositions[$i];
|
||||
$obj->write();
|
||||
|
||||
if ($this->update_versioned_stage && $this->hasVersionedExtension($className)) {
|
||||
DB::query('UPDATE "' . $table . '_' . $this->update_versioned_stage
|
||||
. '" SET "' . $sortColumn . '" = ' . $sortPositions[$i]
|
||||
. ' WHERE "ID" = ' . $obj->ID);
|
||||
}
|
||||
}
|
||||
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
//End transaction if supported
|
||||
if (DB::get_conn()->supportsTransactions()) {
|
||||
DB::get_conn()->transactionEnd();
|
||||
}
|
||||
|
||||
//Event to notify the Controller or owner DataObject after list sort
|
||||
if ($owner && $owner instanceof DataObject && method_exists($owner, 'onAfterGridFieldPageSort')) {
|
||||
$owner->onAfterGridFieldPageSort(clone $items);
|
||||
} else if (Controller::has_curr() && Controller::curr() instanceof ModelAdmin && method_exists(Controller::curr(), 'onAfterGridFieldPageSort')) {
|
||||
Controller::curr()->onAfterGridFieldPageSort(clone $items);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if the given class name has the Versioned extension
|
||||
* @param \SilverStripe\Core\Extensible|string $className
|
||||
* @return bool
|
||||
*/
|
||||
public function hasVersionedExtension($className)
|
||||
{
|
||||
return $className::has_extension(Versioned::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if $table_name is declared on the DataObject, if not returns string as given
|
||||
* @param $className
|
||||
* @return string
|
||||
* @deprecated Use DataObject::getSchema()->tableName() instead
|
||||
*/
|
||||
public function mapTableNameAndReturn($className)
|
||||
{
|
||||
return DataObject::getSchema()->tableName($className);
|
||||
}
|
||||
}
|
|
@ -1,10 +0,0 @@
|
|||
<tr>
|
||||
<th class="extra sortablerowsheading" colspan="$Colspan">
|
||||
<div class="gridfield-sortablerows">
|
||||
<input type="checkbox" id="{$ID}_AllowDragDropCheck" value="1" class="no-change-track"$Checked/> <label for="{$ID}_AllowDragDropCheck"><%t GridFieldSortableRows.ALLOW_DRAG_DROP "_Allow drag and drop re-ordering" %></label>
|
||||
$SortableToggle
|
||||
$PagenatorToggle
|
||||
$SortToPage
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
|
@ -0,0 +1,11 @@
|
|||
<tr>
|
||||
<td class="sortablerowsheading" colspan="$Colspan">
|
||||
<div class="gridfield-sortablerows">
|
||||
<input type="checkbox" id="{$ID}_AllowDragDropCheck" value="1" autocomplete="off" class="no-change-track<% if $DisableSelection %> gridfield-sortablerows-noselection<% end_if %>"$Checked/>
|
||||
<label for="{$ID}_AllowDragDropCheck"><%t GridFieldSortableRows.ALLOW_DRAG_DROP "Allow drag and drop re-ordering" %></label>
|
||||
$SortableToggle
|
||||
$SortOrderSave
|
||||
$SortToPage
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
|
@ -0,0 +1,7 @@
|
|||
<% if $Checked %>
|
||||
<div class="gridfield-sortablerows-movepage" colspan="$Colspan">
|
||||
<a href="" class="sortablerows-psort-arrow sortablerows-prev-page"><i><%t GridFieldSortableRows.PREVIOUS 'Move to Previous Page' %></i></a>
|
||||
|
||||
<a href="" class="sortablerows-psort-arrow sortablerows-next-page"><i><%t GridFieldSortableRows.NEXT 'Move to Next Page' %></i></a>
|
||||
</div>
|
||||
<% end_if %>
|
|
@ -0,0 +1,112 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests\PHPUnit\Bootstrap;
|
||||
|
||||
use PHPUnit\Framework\TestFailure;
|
||||
use PHPUnit\TextUI\DefaultResultPrinter;
|
||||
|
||||
class GitHubActionsAnnotatorPrinter extends DefaultResultPrinter
|
||||
{
|
||||
protected $currentType = null;
|
||||
|
||||
/**
|
||||
* Handles printing of the defects
|
||||
* @param array $defects Array of Test Failures
|
||||
* @param string $type Type of the failure
|
||||
*/
|
||||
protected function printDefects(array $defects, string $type): void
|
||||
{
|
||||
$this->currentType = $type;
|
||||
|
||||
parent::printDefects($defects, $type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles printing of a single defect
|
||||
* @param TestFailure $defect Test Failure Object
|
||||
* @param int $count Current position
|
||||
*/
|
||||
protected function printDefect(TestFailure $defect, int $count): void
|
||||
{
|
||||
parent::printDefect($defect, $count);
|
||||
|
||||
$this->printGitHubAnnotation($defect);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prints a GitHub Annotation Command
|
||||
* @param TestFailure $defect Defect to print
|
||||
*/
|
||||
protected function printGitHubAnnotation(TestFailure $defect)
|
||||
{
|
||||
$e = $defect->thrownException();
|
||||
|
||||
$errorLines = array_filter(
|
||||
explode("\n", (string) $e),
|
||||
function ($l) {
|
||||
return $l;
|
||||
}
|
||||
);
|
||||
|
||||
$error = end($errorLines);
|
||||
$lineIndex = strrpos($error, ":");
|
||||
$path = substr($error, 0, $lineIndex);
|
||||
$line = substr($error, $lineIndex + 1);
|
||||
|
||||
if (!$path) {
|
||||
list($path, $line) = $this->getReflectionFromTest(
|
||||
$defect->getTestName()
|
||||
);
|
||||
}
|
||||
|
||||
$message = explode("\n", trim($defect->getTestName() . "\n\n" . (string) $e));
|
||||
$message = implode('%0A', $message);
|
||||
|
||||
$type = $this->getCurrentType();
|
||||
$file = "file={$this->relativePath($path)}";
|
||||
$line = "line={$line}";
|
||||
$this->write("::{$type} $file,$line::{$message}\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current type of the defect
|
||||
* @return string
|
||||
*/
|
||||
protected function getCurrentType()
|
||||
{
|
||||
if (in_array($this->currentType, ['error', 'failure'])) {
|
||||
return 'error';
|
||||
}
|
||||
|
||||
return 'warning';
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the relative path to the file
|
||||
* @param string $path Path to make relative
|
||||
* @return string
|
||||
*/
|
||||
protected function relativePath($path)
|
||||
{
|
||||
$relative = str_replace(getcwd() . DIRECTORY_SEPARATOR, '', $path);
|
||||
|
||||
//Normalize
|
||||
$relative = str_replace('\\', '/', $relative);
|
||||
|
||||
return $relative;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the file name and start line for the test
|
||||
* @param string $name Name of the test
|
||||
* @return array
|
||||
*/
|
||||
protected function getReflectionFromTest($name)
|
||||
{
|
||||
list($klass, $method) = explode('::', $name);
|
||||
$c = new \ReflectionClass($klass);
|
||||
$m = $c->getMethod($method);
|
||||
|
||||
return [$m->getFileName(), $m->getStartLine()];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,264 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests\Forms;
|
||||
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
use SilverStripe\Forms\FieldList;
|
||||
use SilverStripe\Forms\Form;
|
||||
use SilverStripe\Forms\GridField\GridField;
|
||||
use SilverStripe\Forms\GridField\GridFieldConfig;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\Security\Security;
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
use UndefinedOffset\SortableGridField\Forms\GridFieldSortableRows;
|
||||
use UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\BaseObject;
|
||||
use UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\ChildObject;
|
||||
use UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\DummyController;
|
||||
use UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\Player;
|
||||
use UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\TestParent;
|
||||
use UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\VPlayer;
|
||||
|
||||
class AutoSortTest extends SapphireTest
|
||||
{
|
||||
/** @var string */
|
||||
public static $fixture_file = 'AutoSortTest.yml';
|
||||
|
||||
/** @var array */
|
||||
protected static $extra_dataobjects = [
|
||||
Player::class,
|
||||
VPlayer::class,
|
||||
TestParent::class,
|
||||
BaseObject::class,
|
||||
ChildObject::class
|
||||
];
|
||||
|
||||
public function testAutoSort()
|
||||
{
|
||||
if (Security::getCurrentUser()) {
|
||||
$this->logOut();
|
||||
}
|
||||
|
||||
$list = Player::get();
|
||||
$config = GridFieldConfig::create()->addComponent(new GridFieldSortableRows('SortOrder'));
|
||||
$gridField = new GridField('testfield', 'testfield', $list, $config);
|
||||
$form = new Form(new DummyController(), 'mockform', new FieldList([$gridField]), new FieldList());
|
||||
|
||||
$stateID = 'testGridStateActionField';
|
||||
$request = new HTTPRequest('POST', 'url', [], ['action_gridFieldAlterAction?StateID=' . $stateID => true, $form->getSecurityToken()->getName() => $form->getSecurityToken()->getValue()]);
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$session->set($form->getSecurityToken()->getName(), $form->getSecurityToken()->getValue());
|
||||
$session->set($stateID, ['grid' => '', 'actionName' => 'sortableRowsToggle', 'args' => ['GridFieldSortableRows' => ['sortableToggle' => true]]]);
|
||||
$request->setSession($session);
|
||||
|
||||
$gridField->gridFieldAlterAction(['StateID' => $stateID], $form, $request);
|
||||
|
||||
//Insure sort ran
|
||||
$this->assertEquals(3, $list->last()->SortOrder, 'Auto sort should have run');
|
||||
|
||||
|
||||
//Check for duplicates (there shouldn't be any)
|
||||
$count = $list->Count();
|
||||
$indexes = count(array_unique($list->column('SortOrder')));
|
||||
$this->assertEquals(0, $count - $indexes, 'Duplicate indexes detected');
|
||||
}
|
||||
|
||||
public function testAppendToTopAutoSort()
|
||||
{
|
||||
if (Security::getCurrentUser()) {
|
||||
$this->logOut();
|
||||
}
|
||||
|
||||
$list = Player::get();
|
||||
$config = GridFieldConfig::create()->addComponent(new GridFieldSortableRows('SortOrder'));
|
||||
$gridField = new GridField('testfield', 'testfield', $list, $config);
|
||||
$form = new Form(new DummyController(), 'mockform', new FieldList([$gridField]), new FieldList());
|
||||
|
||||
/** @var GridFieldSortableRows $sortableRows */
|
||||
$sortableRows = $gridField->getConfig()->getComponentByType(GridFieldSortableRows::class);
|
||||
$sortableRows->setAppendToTop(true);
|
||||
|
||||
$this->assertEquals(0, $list->last()->SortOrder, 'Auto sort should not have run');
|
||||
|
||||
$stateID = 'testGridStateActionField';
|
||||
$request = new HTTPRequest('POST', 'url', [], ['action_gridFieldAlterAction?StateID=' . $stateID => true, $form->getSecurityToken()->getName() => $form->getSecurityToken()->getValue()]);
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$session->set($form->getSecurityToken()->getName(), $form->getSecurityToken()->getValue());
|
||||
$session->set($stateID, ['grid' => '', 'actionName' => 'sortableRowsToggle', 'args' => ['GridFieldSortableRows' => ['sortableToggle' => true]]]);
|
||||
$request->setSession($session);
|
||||
$gridField->gridFieldAlterAction(['StateID' => $stateID], $form, $request);
|
||||
|
||||
//Insure sort ran
|
||||
$this->assertEquals(3, $list->last()->SortOrder, 'Auto sort should have run');
|
||||
|
||||
|
||||
//Check for duplicates (there shouldn't be any)
|
||||
$count = $list->Count();
|
||||
$indexes = count(array_unique($list->column('SortOrder')));
|
||||
$this->assertEquals(0, $count - $indexes, 'Duplicate indexes detected');
|
||||
}
|
||||
|
||||
public function testAutoSortVersioned()
|
||||
{
|
||||
if (Security::getCurrentUser()) {
|
||||
$this->logOut();
|
||||
}
|
||||
|
||||
//Force versioned to reset
|
||||
Versioned::reset();
|
||||
|
||||
$list = VPlayer::get();
|
||||
|
||||
//Publish all records
|
||||
foreach ($list as $item) {
|
||||
$item->publishSingle();
|
||||
}
|
||||
|
||||
|
||||
$config = GridFieldConfig::create()->addComponent(new GridFieldSortableRows('SortOrder', true, 'Live'));
|
||||
$gridField = new GridField('testfield', 'testfield', $list, $config);
|
||||
$form = new Form(new DummyController(), 'mockform', new FieldList([$gridField]), new FieldList());
|
||||
|
||||
$stateID = 'testGridStateActionField';
|
||||
$request = new HTTPRequest('POST', 'url', [], ['action_gridFieldAlterAction?StateID=' . $stateID => true, $form->getSecurityToken()->getName() => $form->getSecurityToken()->getValue()]);
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$session->set($form->getSecurityToken()->getName(), $form->getSecurityToken()->getValue());
|
||||
$session->set($stateID, ['grid' => '', 'actionName' => 'sortableRowsToggle', 'args' => ['GridFieldSortableRows' => ['sortableToggle' => true]]]);
|
||||
$request->setSession($session);
|
||||
$gridField->gridFieldAlterAction(['StateID' => $stateID], $form, $request);
|
||||
|
||||
|
||||
//Insure sort ran
|
||||
$this->assertEquals(3, $list->last()->SortOrder, 'Auto sort should have run on Versioned stage "Stage"');
|
||||
|
||||
|
||||
//Check for duplicates (there shouldn't be any)
|
||||
$count = $list->Count();
|
||||
$indexes = count(array_unique($list->column('SortOrder')));
|
||||
$this->assertEquals(0, $count - $indexes, 'Duplicate indexes detected on Versioned stage "Stage"');
|
||||
|
||||
|
||||
//Force versioned over to Live stage
|
||||
Versioned::set_reading_mode('Live');
|
||||
|
||||
//Get live instance
|
||||
$obj = Versioned::get_one_by_stage(VPlayer::class, 'Live', '"ID"=' . $list->last()->ID);
|
||||
|
||||
//Insure sort ran
|
||||
$this->assertEquals(3, $obj->SortOrder, 'Auto sort should have run on Versioned stage "Live"');
|
||||
|
||||
|
||||
//Check for duplicates (there shouldn't be any)
|
||||
$list = Versioned::get_by_stage(VPlayer::class, 'Live');
|
||||
$count = $list->Count();
|
||||
$indexes = count(array_unique($list->column('SortOrder')));
|
||||
$this->assertEquals(0, $count - $indexes, 'Duplicate indexes detected on Versioned stage "Live"');
|
||||
}
|
||||
|
||||
public function testAppendToTopAutoSortVersioned()
|
||||
{
|
||||
if (Security::getCurrentUser()) {
|
||||
$this->logOut();
|
||||
}
|
||||
|
||||
//Force versioned to reset
|
||||
Versioned::reset();
|
||||
|
||||
$list = VPlayer::get();
|
||||
|
||||
//Publish all records
|
||||
foreach ($list as $item) {
|
||||
$item->publishSingle();
|
||||
}
|
||||
|
||||
|
||||
$config = GridFieldConfig::create()->addComponent(new GridFieldSortableRows('SortOrder', true, 'Live'));
|
||||
$gridField = new GridField('testfield', 'testfield', $list, $config);
|
||||
$form = new Form(new DummyController(), 'mockform', new FieldList([$gridField]), new FieldList());
|
||||
|
||||
/** @var GridFieldSortableRows $sortableRows */
|
||||
$sortableRows = $gridField->getConfig()->getComponentByType(GridFieldSortableRows::class);
|
||||
$sortableRows->setAppendToTop(true);
|
||||
|
||||
$this->assertEquals(0, $list->last()->SortOrder, 'Auto sort should not have run on Versioned stage "Stage"');
|
||||
|
||||
$stateID = 'testGridStateActionField';
|
||||
$request = new HTTPRequest('POST', 'url', [], ['action_gridFieldAlterAction?StateID=' . $stateID => true, $form->getSecurityToken()->getName() => $form->getSecurityToken()->getValue()]);
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$session->set($form->getSecurityToken()->getName(), $form->getSecurityToken()->getValue());
|
||||
$session->set($stateID, ['grid' => '', 'actionName' => 'sortableRowsToggle', 'args' => ['GridFieldSortableRows' => ['sortableToggle' => true]]]);
|
||||
$request->setSession($session);
|
||||
$gridField->gridFieldAlterAction(['StateID' => $stateID], $form, $request);
|
||||
|
||||
|
||||
//Insure sort ran
|
||||
$this->assertEquals(3, $list->last()->SortOrder, 'Auto sort should have run on Versioned stage "Stage"');
|
||||
|
||||
|
||||
//Check for duplicates (there shouldn't be any)
|
||||
$count = $list->Count();
|
||||
$indexes = count(array_unique($list->column('SortOrder')));
|
||||
$this->assertEquals(0, $count - $indexes, 'Duplicate indexes detected on Versioned stage "Stage"');
|
||||
|
||||
|
||||
//Force versioned over to Live stage
|
||||
Versioned::set_reading_mode('Live');
|
||||
|
||||
//Insure sort ran
|
||||
$this->assertEquals(3, $list->last()->SortOrder, 'Auto sort should have run on Versioned stage "Live"');
|
||||
|
||||
|
||||
//Check for duplicates (there shouldn't be any)
|
||||
$count = $list->Count();
|
||||
$indexes = count(array_unique($list->column('SortOrder')));
|
||||
$this->assertEquals(0, $count - $indexes, 'Duplicate indexes detected on Versioned stage "Live"');
|
||||
}
|
||||
|
||||
public function testAppendToTopAutoSortChild()
|
||||
{
|
||||
if (Security::getCurrentUser()) {
|
||||
$this->logOut();
|
||||
}
|
||||
|
||||
//Push the edit date into the past, we're checking this later
|
||||
DB::query('UPDATE "GridFieldAction_SortOrder_BaseObject" SET "LastEdited"=\'' . date('Y-m-d 00:00:00', strtotime('yesterday')) . '\'');
|
||||
|
||||
/** @var TestParent $parent */
|
||||
$parent = TestParent::get()->first();
|
||||
|
||||
/** @var DataList $list */
|
||||
$list = $parent->TestRelation();
|
||||
|
||||
$config = GridFieldConfig::create()->addComponent(new GridFieldSortableRows('SortOrder'));
|
||||
$gridField = new GridField('testfield', 'testfield', $list, $config);
|
||||
$form = new Form(new DummyController(), 'mockform', new FieldList([$gridField]), new FieldList());
|
||||
$form->loadDataFrom($parent);
|
||||
|
||||
/** @var GridFieldSortableRows $sortableRows */
|
||||
$sortableRows = $gridField->getConfig()->getComponentByType(GridFieldSortableRows::class);
|
||||
$sortableRows->setAppendToTop(true);
|
||||
|
||||
$this->assertEquals(0, $list->last()->SortOrder, 'Auto sort should not have run');
|
||||
|
||||
$stateID = 'testGridStateActionField';
|
||||
$request = new HTTPRequest('POST', 'url', [], ['action_gridFieldAlterAction?StateID=' . $stateID => true, $form->getSecurityToken()->getName() => $form->getSecurityToken()->getValue()]);
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$session->set($form->getSecurityToken()->getName(), $form->getSecurityToken()->getValue());
|
||||
$session->set($stateID, ['grid' => '', 'actionName' => 'sortableRowsToggle', 'args' => ['GridFieldSortableRows' => ['sortableToggle' => true]]]);
|
||||
$request->setSession($session);
|
||||
$gridField->gridFieldAlterAction(['StateID' => $stateID], $form, $request);
|
||||
|
||||
//Insure sort ran
|
||||
$this->assertEquals(3, $list->last()->SortOrder, 'Auto sort should have run');
|
||||
|
||||
|
||||
//Check for duplicates (there shouldn't be any)
|
||||
$count = $list->Count();
|
||||
$indexes = count(array_unique($list->column('SortOrder')));
|
||||
$this->assertEquals(0, $count - $indexes, 'Duplicate indexes detected');
|
||||
|
||||
|
||||
//Make sure the last edited is today for all records
|
||||
$this->assertEquals(3, $list->filter('LastEdited:GreaterThan', date('Y-m-d 00:00:00'))->count());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\Player:
|
||||
player1:
|
||||
Name: Player 1
|
||||
SortOrder: 0
|
||||
player2:
|
||||
Name: Player 2
|
||||
SortOrder: 0
|
||||
player3:
|
||||
Name: Player 3
|
||||
SortOrder: 0
|
||||
|
||||
UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\VPlayer:
|
||||
player1:
|
||||
Name: Player 1
|
||||
SortOrder: 0
|
||||
player2:
|
||||
Name: Player 2
|
||||
SortOrder: 0
|
||||
player3:
|
||||
Name: Player 3
|
||||
SortOrder: 0
|
||||
|
||||
UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\TestParent:
|
||||
testparent:
|
||||
Name: Test
|
||||
|
||||
UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\ChildObject:
|
||||
testitem1:
|
||||
Name: Test 1
|
||||
SortOrder: 0
|
||||
Parent: =>UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\TestParent.testparent
|
||||
testitem2:
|
||||
Name: Test 2
|
||||
SortOrder: 0
|
||||
Parent: =>UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\TestParent.testparent
|
||||
testitem3:
|
||||
Name: Test 3
|
||||
SortOrder: 0
|
||||
Parent: =>UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\TestParent.testparent
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
|
||||
/**
|
||||
* Class \UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\BaseObject
|
||||
*
|
||||
* @property string Name
|
||||
*/
|
||||
class BaseObject extends DataObject implements TestOnly
|
||||
{
|
||||
private static $table_name = 'GridFieldAction_SortOrder_BaseObject';
|
||||
|
||||
private static $db = [
|
||||
'Name' => 'Varchar',
|
||||
];
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\FieldType\DBInt;
|
||||
|
||||
/**
|
||||
* Class \UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\ChildObject
|
||||
*
|
||||
* @package SortableGridField\Tests
|
||||
* @property int SortOrder
|
||||
* @method TestParent Parent
|
||||
*/
|
||||
class ChildObject extends BaseObject implements TestOnly
|
||||
{
|
||||
private static $table_name = 'GridFieldAction_SortOrder_ChildObject';
|
||||
|
||||
private static $db = [
|
||||
'SortOrder' => DBInt::class,
|
||||
];
|
||||
|
||||
private static $has_one = [
|
||||
'Parent' => TestParent::class,
|
||||
];
|
||||
|
||||
private static $default_sort = 'SortOrder';
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest;
|
||||
|
||||
use SilverStripe\Control\Controller;
|
||||
|
||||
/**
|
||||
* Class \UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\DummyController
|
||||
*/
|
||||
class DummyController extends Controller
|
||||
{
|
||||
private static $url_segment = 'sortable-grid-field';
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
|
||||
/**
|
||||
* Class \UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\Player
|
||||
*
|
||||
* @property string Name
|
||||
* @property int SortOrder
|
||||
*/
|
||||
class Player extends DataObject implements TestOnly
|
||||
{
|
||||
private static $table_name = 'GridFieldAction_SortOrder_Player';
|
||||
|
||||
private static $db = [
|
||||
'Name' => 'Varchar',
|
||||
'SortOrder' => 'Int',
|
||||
];
|
||||
|
||||
private static $default_sort = 'SortOrder';
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
|
||||
/**
|
||||
* Class \UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\TestParent
|
||||
*
|
||||
* @package SortableGridField\Tests
|
||||
* @property string Name
|
||||
* @method ChildObject TestRelation
|
||||
*/
|
||||
class TestParent extends DataObject implements TestOnly
|
||||
{
|
||||
private static $table_name = 'GridFieldAction_SortOrder_TestParent';
|
||||
|
||||
private static $db = [
|
||||
'Name' => 'Varchar',
|
||||
];
|
||||
|
||||
private static $has_many = [
|
||||
'TestRelation' => ChildObject::class,
|
||||
];
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
|
||||
/**
|
||||
* Class \UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\VPlayer
|
||||
*
|
||||
* @property string Name
|
||||
* @property int SortOrder
|
||||
*/
|
||||
class VPlayer extends DataObject implements TestOnly
|
||||
{
|
||||
private static $table_name = 'GridFieldAction_SortOrder_VPlayer';
|
||||
|
||||
private static $db = [
|
||||
'Name' => 'Varchar',
|
||||
'SortOrder' => 'Int',
|
||||
];
|
||||
|
||||
private static $default_sort = 'SortOrder';
|
||||
|
||||
private static $extensions = [
|
||||
Versioned::class,
|
||||
];
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests;
|
||||
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
use SilverStripe\Forms\FieldList;
|
||||
use SilverStripe\Forms\Form;
|
||||
use SilverStripe\Forms\GridField\GridField;
|
||||
use SilverStripe\Forms\GridField\GridFieldConfig;
|
||||
use SilverStripe\ORM\ValidationException;
|
||||
use SilverStripe\Security\IdentityStore;
|
||||
use SilverStripe\Security\Security;
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
use UndefinedOffset\SortableGridField\Forms\GridFieldSortableRows;
|
||||
use UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\DummyController;
|
||||
use UndefinedOffset\SortableGridField\Tests\Forms\OrderingTest\Team;
|
||||
use UndefinedOffset\SortableGridField\Tests\Forms\OrderingTest\VTeam;
|
||||
|
||||
class OrderingTest extends SapphireTest
|
||||
{
|
||||
/** @var ArrayList */
|
||||
protected $list;
|
||||
|
||||
/** @var GridField */
|
||||
protected $gridField;
|
||||
|
||||
/** @var Form */
|
||||
protected $form;
|
||||
|
||||
/** @var string */
|
||||
public static $fixture_file = 'OrderingTest.yml';
|
||||
|
||||
/** @var array */
|
||||
protected static $extra_dataobjects = [
|
||||
Team::class,
|
||||
VTeam::class
|
||||
];
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->list = Team::get();
|
||||
$config = GridFieldConfig::create()->addComponent(new GridFieldSortableRows('SortOrder'));
|
||||
$this->gridField = new GridField('testfield', 'testfield', $this->list, $config);
|
||||
$this->form = new Form(new DummyController(), 'mockform', new FieldList([$this->gridField]), new FieldList());
|
||||
}
|
||||
|
||||
public function testSortActionWithoutCorrectPermission()
|
||||
{
|
||||
if (Security::getCurrentUser()) {
|
||||
Injector::inst()->get(IdentityStore::class)->logOut(Controller::curr()->getRequest());
|
||||
}
|
||||
|
||||
$this->expectException(ValidationException::class);
|
||||
$team1 = $this->objFromFixture(Team::class, 'team1');
|
||||
$team2 = $this->objFromFixture(Team::class, 'team2');
|
||||
$team3 = $this->objFromFixture(Team::class, 'team3');
|
||||
|
||||
$stateID = 'testGridStateActionField';
|
||||
$request = new HTTPRequest('POST', 'url', ['ItemIDs' => "$team1->ID, $team3->ID, $team2->ID"], ['action_gridFieldAlterAction?StateID=' . $stateID => true, $this->form->getSecurityToken()->getName() => $this->form->getSecurityToken()->getValue()]);
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$session->set($this->form->getSecurityToken()->getName(), $this->form->getSecurityToken()->getValue());
|
||||
$session->set($stateID, ['grid' => '', 'actionName' => 'saveGridRowSort', 'args' => ['GridFieldSortableRows' => ['sortableToggle' => true]]]);
|
||||
$request->setSession($session);
|
||||
$this->gridField->gridFieldAlterAction(['StateID' => $stateID], $this->form, $request);
|
||||
$this->assertEquals($team3->ID, $this->list->last()->ID, 'User should\'t be able to sort records without correct permissions.');
|
||||
}
|
||||
|
||||
public function testSortActionWithAdminPermission()
|
||||
{
|
||||
$team1 = $this->objFromFixture(Team::class, 'team1');
|
||||
$team2 = $this->objFromFixture(Team::class, 'team2');
|
||||
$team3 = $this->objFromFixture(Team::class, 'team3');
|
||||
$this->logInWithPermission('ADMIN');
|
||||
$stateID = 'testGridStateActionField';
|
||||
$request = new HTTPRequest('POST', 'url', ['ItemIDs' => "$team1->ID, $team3->ID, $team2->ID"], ['action_gridFieldAlterAction?StateID=' . $stateID => true, $this->form->getSecurityToken()->getName() => $this->form->getSecurityToken()->getValue()]);
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$session->set($this->form->getSecurityToken()->getName(), $this->form->getSecurityToken()->getValue());
|
||||
$session->set($stateID, ['grid' => '', 'actionName' => 'saveGridRowSort', 'args' => ['GridFieldSortableRows' => ['sortableToggle' => true]]]);
|
||||
$request->setSession($session);
|
||||
$this->gridField->gridFieldAlterAction(['StateID' => $stateID], $this->form, $request);
|
||||
$this->assertEquals($team2->ID, $this->list->last()->ID, 'User should be able to sort records with ADMIN permission.');
|
||||
}
|
||||
|
||||
public function testSortActionVersioned()
|
||||
{
|
||||
//Force versioned to reset
|
||||
Versioned::reset();
|
||||
|
||||
$list = VTeam::get();
|
||||
$this->gridField->setList($list);
|
||||
|
||||
/** @var GridFieldSortableRows $sortableGrid */
|
||||
$sortableGrid = $this->gridField->getConfig()->getComponentByType(GridFieldSortableRows::class);
|
||||
$sortableGrid->setUpdateVersionedStage('Live');
|
||||
|
||||
//Publish all records
|
||||
foreach ($list as $item) {
|
||||
$item->publishSingle();
|
||||
}
|
||||
|
||||
$team1 = $this->objFromFixture(VTeam::class, 'team1');
|
||||
$team2 = $this->objFromFixture(VTeam::class, 'team2');
|
||||
$team3 = $this->objFromFixture(VTeam::class, 'team3');
|
||||
|
||||
$this->logInWithPermission('ADMIN');
|
||||
$stateID = 'testGridStateActionField';
|
||||
$request = new HTTPRequest('POST', 'url', ['ItemIDs' => "$team1->ID, $team3->ID, $team2->ID"], ['action_gridFieldAlterAction?StateID=' . $stateID => true, $this->form->getSecurityToken()->getName() => $this->form->getSecurityToken()->getValue()]);
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$session->set($this->form->getSecurityToken()->getName(), $this->form->getSecurityToken()->getValue());
|
||||
$session->set($stateID, ['grid' => '', 'actionName' => 'saveGridRowSort', 'args' => ['GridFieldSortableRows' => ['sortableToggle' => true]]]);
|
||||
$request->setSession($session);
|
||||
$this->gridField->gridFieldAlterAction(['StateID' => $stateID], $this->form, $request);
|
||||
|
||||
$this->assertEquals($team2->ID, $list->last()->ID, 'Sort should have happened on Versioned stage "Stage"');
|
||||
|
||||
$list = Versioned::get_by_stage(VTeam::class, 'Live');
|
||||
$this->assertEquals($team2->ID, $list->last()->ID, 'Sort should have happened on Versioned stage "Live"');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
UndefinedOffset\SortableGridField\Tests\Forms\OrderingTest\Team:
|
||||
team1:
|
||||
Name: Team 1
|
||||
City: Cologne
|
||||
SortOrder: 1
|
||||
team2:
|
||||
Name: Team 2
|
||||
City: Wellington
|
||||
SortOrder: 2
|
||||
team3:
|
||||
Name: Team 3
|
||||
City: Auckland
|
||||
SortOrder: 3
|
||||
|
||||
UndefinedOffset\SortableGridField\Tests\Forms\OrderingTest\VTeam:
|
||||
team1:
|
||||
Name: Team 1
|
||||
City: Cologne
|
||||
SortOrder: 1
|
||||
team2:
|
||||
Name: Team 2
|
||||
City: Wellington
|
||||
SortOrder: 2
|
||||
team3:
|
||||
Name: Team 3
|
||||
City: Auckland
|
||||
SortOrder: 3
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests\Forms\OrderingTest;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
|
||||
/**
|
||||
* Class \UndefinedOffset\SortableGridField\Tests\Forms\OrderingTest\Team
|
||||
*
|
||||
* @property string Name
|
||||
* @property string City
|
||||
* @property int SortOrder
|
||||
*/
|
||||
class Team extends DataObject implements TestOnly
|
||||
{
|
||||
private static $table_name = 'GridFieldAction_SortOrder_Team';
|
||||
|
||||
private static $db = [
|
||||
'Name' => 'Varchar',
|
||||
'City' => 'Varchar',
|
||||
'SortOrder' => 'Int',
|
||||
];
|
||||
|
||||
private static $default_sort = 'SortOrder';
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests\Forms\OrderingTest;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
|
||||
/**
|
||||
* Class \UndefinedOffset\SortableGridField\Tests\Forms\OrderingTest\VTeam
|
||||
*
|
||||
* @property string Name
|
||||
* @property string City
|
||||
* @property int SortOrder
|
||||
*/
|
||||
class VTeam extends DataObject implements TestOnly
|
||||
{
|
||||
private static $table_name = 'GridFieldAction_SortOrder_VTeam';
|
||||
|
||||
private static $db = [
|
||||
'Name' => 'Varchar',
|
||||
'City' => 'Varchar',
|
||||
'SortOrder' => 'Int',
|
||||
];
|
||||
private static $default_sort = 'SortOrder';
|
||||
|
||||
private static $extensions = [
|
||||
Versioned::class,
|
||||
];
|
||||
}
|
|
@ -0,0 +1,188 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests;
|
||||
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
use SilverStripe\Forms\FieldList;
|
||||
use SilverStripe\Forms\Form;
|
||||
use SilverStripe\Forms\GridField\GridField;
|
||||
use SilverStripe\Forms\GridField\GridFieldConfig_Base;
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
use UndefinedOffset\SortableGridField\Forms\GridFieldSortableRows;
|
||||
use UndefinedOffset\SortableGridField\Tests\Forms\AutoSortTest\DummyController;
|
||||
use UndefinedOffset\SortableGridField\Tests\Forms\PageSortingTest\Team;
|
||||
use UndefinedOffset\SortableGridField\Tests\Forms\PageSortingTest\VTeam;
|
||||
|
||||
/**
|
||||
* Class \UndefinedOffset\SortableGridField\Tests\PageSortingTest
|
||||
*/
|
||||
class PageSortingTest extends SapphireTest
|
||||
{
|
||||
/** @var ArrayList */
|
||||
protected $list;
|
||||
|
||||
/** @var GridField */
|
||||
protected $gridField;
|
||||
|
||||
/** @var Form */
|
||||
protected $form;
|
||||
|
||||
/** @var string */
|
||||
public static $fixture_file = 'PageSortingTest.yml';
|
||||
|
||||
/** @var array */
|
||||
protected static $extra_dataobjects = [
|
||||
Team::class,
|
||||
VTeam::class
|
||||
];
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$this->list = Team::get();
|
||||
$config = GridFieldConfig_Base::create(5)->addComponent(new GridFieldSortableRows('SortOrder'));
|
||||
$this->gridField = new GridField('testfield', 'testfield', $this->list, $config);
|
||||
$this->form = new Form(new DummyController(), 'mockform', FieldList::create([$this->gridField]), FieldList::create());
|
||||
}
|
||||
|
||||
public function testSortToNextPage()
|
||||
{
|
||||
$this->gridField->State->GridFieldPaginator->currentPage = 1;
|
||||
|
||||
$team3 = $this->objFromFixture(Team::class, 'team3');
|
||||
|
||||
$this->logInWithPermission('ADMIN');
|
||||
$stateID = 'testGridStateActionField';
|
||||
$request = new HTTPRequest('POST', 'url', ['ItemID' => $team3->ID, 'Target' => 'nextpage'], ['action_gridFieldAlterAction?StateID=' . $stateID => true, $this->form->getSecurityToken()->getName() => $this->form->getSecurityToken()->getValue()]);
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$session->set($this->form->getSecurityToken()->getName(), $this->form->getSecurityToken()->getValue());
|
||||
$session->set($stateID, ['grid' => '', 'actionName' => 'sortToPage', 'args' => ['GridFieldSortableRows' => ['sortableToggle' => true], 'GridFieldPaginator' => ['currentPage' => 1]]]);
|
||||
$request->setSession($session);
|
||||
$this->gridField->gridFieldAlterAction(['StateID' => $stateID], $this->form, $request);
|
||||
|
||||
$team6 = $this->objFromFixture(Team::class, 'team6');
|
||||
$this->assertEquals(5, $team6->SortOrder, 'Team 6 Should have moved to the bottom of the first page');
|
||||
|
||||
$team3 = $this->objFromFixture(Team::class, 'team3');
|
||||
$this->assertEquals(6, $team3->SortOrder, 'Team 3 Should have moved to the top of the second page');
|
||||
}
|
||||
|
||||
public function testSortToPrevPage()
|
||||
{
|
||||
$this->gridField->State->GridFieldPaginator->currentPage = 2;
|
||||
|
||||
$team7 = $this->objFromFixture(Team::class, 'team7');
|
||||
|
||||
$this->logInWithPermission('ADMIN');
|
||||
$stateID = 'testGridStateActionField';
|
||||
$request = new HTTPRequest('POST', 'url', ['ItemID' => $team7->ID, 'Target' => 'previouspage'], ['action_gridFieldAlterAction?StateID=' . $stateID => true, $this->form->getSecurityToken()->getName() => $this->form->getSecurityToken()->getValue()]);
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$session->set($this->form->getSecurityToken()->getName(), $this->form->getSecurityToken()->getValue());
|
||||
$session->set($stateID, ['grid' => '', 'actionName' => 'sortToPage', 'args' => ['GridFieldSortableRows' => ['sortableToggle' => true], 'GridFieldPaginator' => ['currentPage' => 1]]]);
|
||||
$request->setSession($session);
|
||||
$this->gridField->gridFieldAlterAction(['StateID' => $stateID], $this->form, $request);
|
||||
|
||||
|
||||
$team7 = $this->objFromFixture(Team::class, 'team7');
|
||||
$this->assertEquals(5, $team7->SortOrder, 'Team 7 Should have moved to the bottom of the first page');
|
||||
|
||||
$team5 = $this->objFromFixture(Team::class, 'team5');
|
||||
$this->assertEquals(6, $team5->SortOrder, 'Team 5 Should have moved to the top of the second page');
|
||||
}
|
||||
|
||||
public function testSortToNextPageVersioned()
|
||||
{
|
||||
//Force versioned to reset
|
||||
Versioned::reset();
|
||||
|
||||
$list = VTeam::get();
|
||||
$this->gridField->setList($list);
|
||||
|
||||
/** @var GridFieldSortableRows $sortableGrid */
|
||||
$sortableGrid = $this->gridField->getConfig()->getComponentByType(GridFieldSortableRows::class);
|
||||
$sortableGrid->setUpdateVersionedStage('Live');
|
||||
$this->gridField->State->GridFieldPaginator->currentPage = 1;
|
||||
|
||||
//Publish all records
|
||||
foreach ($list as $item) {
|
||||
$item->publishSingle();
|
||||
}
|
||||
|
||||
|
||||
$team3 = $this->objFromFixture(VTeam::class, 'team3');
|
||||
|
||||
$this->logInWithPermission('ADMIN');
|
||||
$stateID = 'testGridStateActionField';
|
||||
$request = new HTTPRequest('POST', 'url', ['ItemID' => $team3->ID, 'Target' => 'nextpage'], ['action_gridFieldAlterAction?StateID=' . $stateID => true, $this->form->getSecurityToken()->getName() => $this->form->getSecurityToken()->getValue()]);
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$session->set($this->form->getSecurityToken()->getName(), $this->form->getSecurityToken()->getValue());
|
||||
$session->set($stateID, ['grid' => '', 'actionName' => 'sortToPage', 'args' => ['GridFieldSortableRows' => ['sortableToggle' => true], 'GridFieldPaginator' => ['currentPage' => 1]]]);
|
||||
$request->setSession($session);
|
||||
$this->gridField->gridFieldAlterAction(['StateID' => $stateID], $this->form, $request);
|
||||
|
||||
|
||||
$team6 = $this->objFromFixture(VTeam::class, 'team6');
|
||||
$this->assertEquals(5, $team6->SortOrder, 'Team 6 Should have moved to the bottom of the first page on Versioned stage "Stage"');
|
||||
|
||||
$team3 = $this->objFromFixture(VTeam::class, 'team3');
|
||||
$this->assertEquals(6, $team3->SortOrder, 'Team 3 Should have moved to the top of the second page on Versioned stage "Stage"');
|
||||
|
||||
|
||||
$list = Versioned::get_by_stage(VTeam::class, 'Live');
|
||||
|
||||
$team6 = $list->byID($team6->ID);
|
||||
$this->assertEquals(5, $team6->SortOrder, 'Team 6 Should have moved to the bottom of the first page on Versioned stage "Live"');
|
||||
|
||||
$team3 = $list->byID($team3->ID);
|
||||
$this->assertEquals(6, $team3->SortOrder, 'Team 3 Should have moved to the top of the second page on Versioned stage "Live"');
|
||||
}
|
||||
|
||||
public function testSortToPrevPageVersioned()
|
||||
{
|
||||
//Force versioned to reset
|
||||
Versioned::reset();
|
||||
|
||||
$list = VTeam::get();
|
||||
$this->gridField->setList($list);
|
||||
|
||||
/** @var GridFieldSortableRows $sortableGrid */
|
||||
$sortableGrid = $this->gridField->getConfig()->getComponentByType(GridFieldSortableRows::class);
|
||||
$sortableGrid->setUpdateVersionedStage('Live');
|
||||
$this->gridField->State->GridFieldPaginator->currentPage = 2;
|
||||
|
||||
//Publish all records
|
||||
foreach ($list as $item) {
|
||||
$item->publishSingle();
|
||||
}
|
||||
|
||||
|
||||
$team7 = $this->objFromFixture(VTeam::class, 'team7');
|
||||
|
||||
$this->logInWithPermission('ADMIN');
|
||||
$stateID = 'testGridStateActionField';
|
||||
$request = new HTTPRequest('POST', 'url', ['ItemID' => $team7->ID, 'Target' => 'previouspage'], ['action_gridFieldAlterAction?StateID=' . $stateID => true, $this->form->getSecurityToken()->getName() => $this->form->getSecurityToken()->getValue()]);
|
||||
$session = Controller::curr()->getRequest()->getSession();
|
||||
$session->set($this->form->getSecurityToken()->getName(), $this->form->getSecurityToken()->getValue());
|
||||
$session->set($stateID, ['grid' => '', 'actionName' => 'sortToPage', 'args' => ['GridFieldSortableRows' => ['sortableToggle' => true], 'GridFieldPaginator' => ['currentPage' => 1]]]);
|
||||
$request->setSession($session);
|
||||
$this->gridField->gridFieldAlterAction(['StateID' => $stateID], $this->form, $request);
|
||||
|
||||
|
||||
$team7 = $this->objFromFixture(VTeam::class, 'team7');
|
||||
$this->assertEquals(5, $team7->SortOrder, 'Team 7 Should have moved to the bottom of the first page on Versioned stage "Stage"');
|
||||
|
||||
$team5 = $this->objFromFixture(VTeam::class, 'team5');
|
||||
$this->assertEquals(6, $team5->SortOrder, 'Team 5 Should have moved to the top of the second page on Versioned stage "Stage"');
|
||||
|
||||
|
||||
$list = Versioned::get_by_stage(VTeam::class, 'Live');
|
||||
|
||||
$team7 = $list->byID($team7->ID);
|
||||
$this->assertEquals(5, $team7->SortOrder, 'Team 7 Should have moved to the bottom of the first page on Versioned stage "Live"');
|
||||
|
||||
$team5 = $list->byID($team5->ID);
|
||||
$this->assertEquals(6, $team5->SortOrder, 'Team 5 Should have moved to the top of the second page on Versioned stage "Live"');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
UndefinedOffset\SortableGridField\Tests\Forms\PageSortingTest\Team:
|
||||
team1:
|
||||
Name: Team 1
|
||||
City: Cologne
|
||||
SortOrder: 1
|
||||
team2:
|
||||
Name: Team 2
|
||||
City: Wellington
|
||||
SortOrder: 2
|
||||
team3:
|
||||
Name: Team 3
|
||||
City: Auckland
|
||||
SortOrder: 3
|
||||
team4:
|
||||
Name: Team 4
|
||||
City: Cologne
|
||||
SortOrder: 4
|
||||
team5:
|
||||
Name: Team 5
|
||||
City: Wellington
|
||||
SortOrder: 5
|
||||
team6:
|
||||
Name: Team 6
|
||||
City: Auckland
|
||||
SortOrder: 6
|
||||
team7:
|
||||
Name: Team 7
|
||||
City: Cologne
|
||||
SortOrder: 7
|
||||
team8:
|
||||
Name: Team 8
|
||||
City: Wellington
|
||||
SortOrder: 8
|
||||
team9:
|
||||
Name: Team 9
|
||||
City: Auckland
|
||||
SortOrder: 9
|
||||
|
||||
UndefinedOffset\SortableGridField\Tests\Forms\PageSortingTest\VTeam:
|
||||
team1:
|
||||
Name: Team 1
|
||||
City: Cologne
|
||||
SortOrder: 1
|
||||
team2:
|
||||
Name: Team 2
|
||||
City: Wellington
|
||||
SortOrder: 2
|
||||
team3:
|
||||
Name: Team 3
|
||||
City: Auckland
|
||||
SortOrder: 3
|
||||
team4:
|
||||
Name: Team 4
|
||||
City: Cologne
|
||||
SortOrder: 4
|
||||
team5:
|
||||
Name: Team 5
|
||||
City: Wellington
|
||||
SortOrder: 5
|
||||
team6:
|
||||
Name: Team 6
|
||||
City: Auckland
|
||||
SortOrder: 6
|
||||
team7:
|
||||
Name: Team 7
|
||||
City: Cologne
|
||||
SortOrder: 7
|
||||
team8:
|
||||
Name: Team 8
|
||||
City: Wellington
|
||||
SortOrder: 8
|
||||
team9:
|
||||
Name: Team 9
|
||||
City: Auckland
|
||||
SortOrder: 9
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests\Forms\PageSortingTest;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
|
||||
/**
|
||||
* Class \UndefinedOffset\SortableGridField\Tests\Forms\PageSortingTest\Team
|
||||
*
|
||||
* @property string Name
|
||||
* @property string City
|
||||
* @property int SortOrder
|
||||
*/
|
||||
class Team extends DataObject implements TestOnly
|
||||
{
|
||||
private static $table_name = 'GridFieldAction_PageSortOrder_Team';
|
||||
|
||||
private static $db = [
|
||||
'Name' => 'Varchar',
|
||||
'City' => 'Varchar',
|
||||
'SortOrder' => 'Int',
|
||||
];
|
||||
|
||||
private static $default_sort = 'SortOrder';
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<?php
|
||||
namespace UndefinedOffset\SortableGridField\Tests\Forms\PageSortingTest;
|
||||
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\Versioned\Versioned;
|
||||
|
||||
/**
|
||||
* Class \UndefinedOffset\SortableGridField\Tests\Forms\PageSortingTest\VTeam
|
||||
*
|
||||
* @property string Name
|
||||
* @property string City
|
||||
* @property int SortOrder
|
||||
*/
|
||||
class VTeam extends DataObject implements TestOnly
|
||||
{
|
||||
private static $table_name = 'GridFieldAction_PageSortOrder_VTeam';
|
||||
|
||||
private static $db = [
|
||||
'Name' => 'Varchar',
|
||||
'City' => 'Varchar',
|
||||
'SortOrder' => 'Int',
|
||||
];
|
||||
|
||||
private static $default_sort = 'SortOrder';
|
||||
|
||||
private static $extensions = [
|
||||
Versioned::class,
|
||||
];
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
<?php
|
||||
class GridFieldSortableRowsAutoSortTest extends SapphireTest {
|
||||
|
||||
/** @var ArrayList */
|
||||
protected $list;
|
||||
|
||||
/** @var GridField */
|
||||
protected $gridField;
|
||||
|
||||
/** @var Form */
|
||||
protected $form;
|
||||
|
||||
/** @var string */
|
||||
public static $fixture_file = 'GridFieldSortableRowsAutoSortTest.yml';
|
||||
|
||||
/** @var array */
|
||||
protected $extraDataObjects = array('GridFieldAction_SortOrder_Player');
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
$this->list = GridFieldAction_SortOrder_Player::get();
|
||||
$config = GridFieldConfig::create()->addComponent(new GridFieldSortableRows('SortOrder'));
|
||||
$this->gridField = new GridField('testfield', 'testfield', $this->list, $config);
|
||||
$this->form = new Form(new Controller(), 'mockform', new FieldList(array($this->gridField)), new FieldList());
|
||||
}
|
||||
|
||||
public function testAutoSort() {
|
||||
if(Member::currentUser()) { Member::currentUser()->logOut(); }
|
||||
|
||||
$stateID = 'testGridStateActionField';
|
||||
Session::set($stateID, array('grid'=>'', 'actionName'=>'sortableRowsDisablePaginator', 'args'=>array('GridFieldSortableRows'=>array('sortableToggle'=>true))));
|
||||
$request = new SS_HTTPRequest('POST', 'url', array(), array('action_gridFieldAlterAction?StateID='.$stateID=>true));
|
||||
$this->gridField->gridFieldAlterAction(array('StateID'=>$stateID), $this->form, $request);
|
||||
$this->assertEquals(3, $this->list->last()->SortOrder, 'Auto sort should have run');
|
||||
}
|
||||
}
|
||||
|
||||
class GridFieldAction_SortOrder_Player extends DataObject implements TestOnly {
|
||||
static $db = array(
|
||||
'Name' => 'Varchar',
|
||||
'SortOrder' => 'Int'
|
||||
);
|
||||
|
||||
static $default_sort='SortOrder';
|
||||
}
|
||||
?>
|
|
@ -1,10 +0,0 @@
|
|||
GridFieldAction_SortOrder_Player:
|
||||
player1:
|
||||
Name: Player 1
|
||||
SortOrder: 0
|
||||
player2:
|
||||
Name: Player 2
|
||||
SortOrder: 0
|
||||
player3:
|
||||
Name: Player 3
|
||||
SortOrder: 0
|
|
@ -1,63 +0,0 @@
|
|||
<?php
|
||||
class GridFieldSortableRowsTest extends SapphireTest {
|
||||
|
||||
/** @var ArrayList */
|
||||
protected $list;
|
||||
|
||||
/** @var GridField */
|
||||
protected $gridField;
|
||||
|
||||
/** @var Form */
|
||||
protected $form;
|
||||
|
||||
/** @var string */
|
||||
public static $fixture_file = 'GridFieldSortableRowsTest.yml';
|
||||
|
||||
/** @var array */
|
||||
protected $extraDataObjects = array('GridFieldAction_SortOrder_Team');
|
||||
|
||||
public function setUp() {
|
||||
parent::setUp();
|
||||
$this->list = GridFieldAction_SortOrder_Team::get();
|
||||
$config = GridFieldConfig::create()->addComponent(new GridFieldSortableRows('SortOrder'));
|
||||
$this->gridField = new GridField('testfield', 'testfield', $this->list, $config);
|
||||
$this->form = new Form(new Controller(), 'mockform', new FieldList(array($this->gridField)), new FieldList());
|
||||
}
|
||||
|
||||
public function testSortActionWithoutCorrectPermission() {
|
||||
if(Member::currentUser()) { Member::currentUser()->logOut(); }
|
||||
$this->setExpectedException('ValidationException');
|
||||
$team1 = $this->objFromFixture('GridFieldAction_SortOrder_Team', 'team1');
|
||||
$team2 = $this->objFromFixture('GridFieldAction_SortOrder_Team', 'team2');
|
||||
$team3 = $this->objFromFixture('GridFieldAction_SortOrder_Team', 'team3');
|
||||
|
||||
$stateID = 'testGridStateActionField';
|
||||
Session::set($stateID, array('grid'=>'', 'actionName'=>'saveGridRowSort', 'args'=>array('GridFieldSortableRows'=>array('sortableToggle'=>true))));
|
||||
$request = new SS_HTTPRequest('POST', 'url', array('ItemIDs'=>"$team1->ID, $team3->ID, $team2->ID"), array('action_gridFieldAlterAction?StateID='.$stateID=>true));
|
||||
$this->gridField->gridFieldAlterAction(array('StateID'=>$stateID), $this->form, $request);
|
||||
$this->assertEquals($team3->ID, $this->list->last()->ID, 'User should\'t be able to sort records without correct permissions.');
|
||||
}
|
||||
|
||||
public function testSortActionWithAdminPermission() {
|
||||
$team1 = $this->objFromFixture('GridFieldAction_SortOrder_Team', 'team1');
|
||||
$team2 = $this->objFromFixture('GridFieldAction_SortOrder_Team', 'team2');
|
||||
$team3 = $this->objFromFixture('GridFieldAction_SortOrder_Team', 'team3');
|
||||
$this->logInWithPermission('ADMIN');
|
||||
$stateID = 'testGridStateActionField';
|
||||
Session::set($stateID, array('grid'=>'', 'actionName'=>'saveGridRowSort', 'args'=>array('GridFieldSortableRows'=>array('sortableToggle'=>true))));
|
||||
$request = new SS_HTTPRequest('POST', 'url', array('ItemIDs'=>"$team1->ID, $team3->ID, $team2->ID"), array('action_gridFieldAlterAction?StateID='.$stateID=>true));
|
||||
$this->gridField->gridFieldAlterAction(array('StateID'=>$stateID), $this->form, $request);
|
||||
$this->assertEquals($team2->ID, $this->list->last()->ID, 'User should be able to sort records with ADMIN permission.');
|
||||
}
|
||||
}
|
||||
|
||||
class GridFieldAction_SortOrder_Team extends DataObject implements TestOnly {
|
||||
static $db = array(
|
||||
'Name' => 'Varchar',
|
||||
'City' => 'Varchar',
|
||||
'SortOrder' => 'Int'
|
||||
);
|
||||
|
||||
static $default_sort='SortOrder';
|
||||
}
|
||||
?>
|
|
@ -1,13 +0,0 @@
|
|||
GridFieldAction_SortOrder_Team:
|
||||
team1:
|
||||
Name: Team 1
|
||||
City: Cologne
|
||||
SortOrder: 1
|
||||
team2:
|
||||
Name: Team 2
|
||||
City: Wellington
|
||||
SortOrder: 2
|
||||
team3:
|
||||
Name: Team 3
|
||||
City: Auckland
|
||||
SortOrder: 3
|
|
@ -0,0 +1,15 @@
|
|||
SS_ENVIRONMENT_TYPE="dev"
|
||||
SS_TRUSTED_PROXY_IPS="*"
|
||||
|
||||
SS_DATABASE_CLASS="MySQLDatabase"
|
||||
SS_DATABASE_SERVER="127.0.0.1"
|
||||
SS_DATABASE_USERNAME="root"
|
||||
SS_DATABASE_PASSWORD="testpassword"
|
||||
SS_DATABASE_NAME="test_db"
|
||||
|
||||
SS_DEFAULT_ADMIN_USERNAME="username"
|
||||
SS_DEFAULT_ADMIN_PASSWORD="password"
|
||||
|
||||
SS_ERROR_LOG="artifacts/silverstripe-errors.log"
|
||||
|
||||
TRAVIS_TEST_SESSION="1"
|
Loading…
Reference in New Issue